10. Quality Requirements
Priorities are in Section 1.2. Each scenario names the checks that verify it today; unverified parts are listed in Section 11.
| Goal | Scenario | Expected response | Verified by |
|---|---|---|---|
| Usability | A household member connects a phone to the sync backend of their deployment while standing in a kitchen or store | The Sync page shows exactly one flow. Self-hosted: user name and password, a note that the password is stored on the device, a login check before anything is saved. Cloud: Create account, Join with QR or code, then invite QR, account link and Disconnect. | Component tests of the sync settings (src/features/settings/); sync journeys with stubbed servers (tests/) |
| Usability | A user creates a cloud account on a new device and the request is approved, declined, abandoned or cancelled | A short code is shown and the approval page opens; approval connects the device and starts sync. Denied and expired offer “Try again”; Cancel enrolls nothing; transient poll failures retry until expiry; approval without a valid session enrolls nothing. | Approval service tests (src/infrastructure/sync/); cloud sync component tests; cloud sync journey |
| Learnability | A contributor or agent changes sync behavior or deployment setup | The docs state both sync modes, the announcement and the operator boundary within a short read. | bun run check:arc42 (docs name existing paths and gateway routes) |
| Offline-First | A user loses connectivity while creating recipes, checking shopping items or changing settings | Reads and writes continue locally, no blocking network error appears, and replication resumes when connectivity returns, also when the app started offline. | Sync unit tests (src/infrastructure/storage/); auto-retry hook test; offline journey in tests/ |
| Privacy | A user runs forked without sync or AI import | No request leaves the app origin, data stays on the device, export works without a hosted service. Without an announced gateway no operator is contacted. | Runtime-config unit tests (src/infrastructure/storage/); no-third-party-requests journey in tests/ |
| Privacy | The stored sync password must not leak through the PWA | It exists only as SelfHostedLogin, goes only as Basic auth to the announced CouchDB without browser credentials, is never logged or synced, and the CSP limits exfiltration targets. Cloud mode stores no password and keeps the token in memory. | Local-record and sync unit tests (src/infrastructure/storage/) |
| Privacy | A cloud device is removed on the website, its session expires, or its household mismatches | The device gets no new token (401) and stops with the revoked notice; a token for a foreign database stops sync before data is replicated; the 15-minute token bounds exposure. | Sync unit tests (revoked session, household pinning), gateway client and invite tests (src/infrastructure/); cloud sync component tests |
| Reliability | Two devices edit overlapping data and reconnect later | Both replicas converge on the same winning revision; losing revisions remain as conflict leaves (ADR-025). | Two-replica convergence test (src/infrastructure/database/) |
| Reliability | The sync password is wrong or was changed on the server (self-hosted) | CouchDB answers 401/403; sync stops without a retry loop, the header shows “Sign-in needed”, the Sync page offers to update the login, and local data stays usable. Connecting with the corrected login restarts sync. | Sync unit tests (src/infrastructure/storage/); self-hosted sync component tests |
| Operability | A self-hoster deploys sync for one household on a small Docker host | Two required secrets (COUCHDB_PASSWORD, FORKED_SYNC_PASSWORD); docker compose up -d creates database, user and membership without manual CouchDB calls; HTTPS is one profile (tls) away. | Manual run of the Compose stack; the init job is idempotent by construction |
| Operability | A self-hoster enters a wrong or unreachable address or database | The connect check distinguishes ok, unauthorized, not-found, unreachable and error, stores nothing unless ok, and shows a matching message. Without /forked-config.json the dev default <origin>/couchdb applies. | Connect-check and runtime-config unit tests (src/infrastructure/storage/) |
| Operability | An attacker without credentials probes the self-hosted endpoint | CouchDB requires a valid user (only /_up is open); the proxy answers 404 for everything but /couchdb/forked, strips cookies and rate-limits per client address; CouchDB locks a user out after 5 wrong passwords. | Manual curl of _all_dbs and _utils against the running stack |
| Evolvability | An operator switches a deployment between modes or serves CouchDB from another address | Setting FORKED_GATEWAY_URL and FORKED_COUCHDB_URL is the only change, no rebuild. The announcement decides the mode for every device of that origin; an offline start uses the cached one. | Runtime-config, local-record and sync-page tests; architecture test (src/test/) |
| Internationalization | A user switches between German and English, or a contributor adds a locale | UI text comes from external resources, the preference persists locally, and new strings fit the key structure without code changes. | Localization journey in tests/; locale key parity check in the harness |
| Performance | A user searches or scrolls roughly 1000 recipes on a mid-range phone | Search and list interactions stay responsive; first interaction does not depend on a network round trip. | Not measured (Section 11) |