Architecture improvements

This commit is contained in:
franzap
2026-01-19 22:59:08 -03:00
parent 1f4e28e433
commit 125eda76e8
2 changed files with 73 additions and 19 deletions
-9
View File
@@ -53,18 +53,9 @@ If a guideline seems wrong or incomplete, report it as a Spec Issue.
| `test/**` | Shared | Yes |
| `CONTEXT.md` | Human | No |
## Key Dependencies
- **models** / **purplebase**: Nostr SDK (local-first storage, relay sync, domain models).
See package README in pub cache. Basic usage patterns in `spec/guidelines/ARCHITECTURE.md`.
- **amber_signer**: NIP-55 Android signer integration.
- **background_downloader**: Download management with pause/resume.
## Working Rules
- Prefer small, localized changes. Avoid unrelated refactors.
- After dependency changes, run: `fvm flutter pub get`
- Fix any analyze/lint errors introduced by your changes.
- Do not use polling or artificial `Future.delayed`; await Futures/Streams correctly.
- Keep `lib/widgets/common` generic and reusable.
- Assume Android as default target unless instructed otherwise.
+73 -10
View File
@@ -1,35 +1,98 @@
# Zapstore — Architecture
## Core Principle
Architecture exists to prevent accidental coupling and hidden ownership.
Each package has clear responsibilities and must not exceed them.
Each layer has clear responsibilities and must not exceed them.
## Package Responsibilities
## Layers
### zapstore (this Flutter app)
- Flutter UI and application orchestration
- Navigation, presentation, and user interaction
- Coordinates use cases across dependencies
- Must not contain domain rules or persistence logic
### Dart dependencies
#### models
### models
- Domain models for Nostr events, kinds, zaps, releases, and NWC
- Parsing, validation, signing, encryption, and verification
- Pure domain logic only
- Must not depend on storage, networking, isolates, or UI
### purplebase
#### purplebase
- Local-first storage and indexing (SQLite)
- Relay synchronization and subscription lifecycle management
- Background work and isolate execution
- Must not depend on UI or presentation logic
### zapstore
- Flutter UI and application orchestration
- Navigation, presentation, and user interaction
- Coordinates use cases across packages
- Must not contain domain rules or persistence logic
## Dependency Rules
- zapstore → purplebase → models
- Reverse dependencies are forbidden
- UI widgets must not manage relay connections, storage, or background jobs
## Ownership & Orchestration
- Relay pools and subscriptions are owned by purplebase
- Background work lifecycle is explicit and cancellable
- zapstore orchestrates flows but does not own low-level resources
## Common Patterns
### Widget watching data
```dart
// Watch a query provider — reactive, auto-disposes
final state = ref.watch(
query<Profile>(
authors: {pubkey},
source: const LocalAndRemoteSource(relays: {'social'}),
),
);
return switch (state) {
StorageLoading() => CircularProgressIndicator(),
StorageError(:final exception) => Text('Error: $exception'),
StorageData(:final models) => ProfileWidget(models.first),
};
// Nested queries with `and` — loads relationships
final appState = ref.watch(
query<App>(
tags: {'#d': {identifier}},
and: (app) => {
app.latestRelease.query(
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
and: (release) => {release.latestMetadata.query()},
),
},
source: const LocalAndRemoteSource(relays: 'AppCatalog'),
subscriptionPrefix: 'app-detail',
),
);
```
### Imperative queries (notifiers/services)
```dart
// One-shot query via storage extension
final apps = await ref.storage.query(
RequestFilter<App>(authors: {pubkey}, limit: 20).toRequest(),
);
```
### Saving and publishing (from callbacks)
```dart
onPressed: () async {
await ref.storage.save({signedModel});
await ref.storage.publish({signedModel});
}
```
For detailed API, see models/purplebase READMEs in pub cache.