forked / Architecture

4. Solution Strategy

4.1 Approach

forked is a local-first, offline-first PWA. Every device holds the full data set in PouchDB and works without a network. Optional sync replicates that store directly with a CouchDB. The sync mode is a property of the deployment, not a user choice.

4.2 Technology Decisions

The one list of technologies; other sections link here.

ConcernChoiceWhyQuality goal
ArchitectureLocal-firstData on the device, sync optionalOffline-First, Privacy
DeliveryPWA only (ADR-039)One installable web UI for phones, tablets and desktops, updates via service workerUsability
FrontendReact 19, TypeScript (strict), Tailwind 4, react-router 7Component model, large ecosystem, mobile-first utilitiesUsability, Learnability
Build, packagesVite with vite-plugin-pwa, BunFast builds, TypeScript without a toolchainEvolvability
Client databasePouchDB over IndexedDBBrowser-native persistence with CouchDB-compatible replicationOffline-First
SyncDirect PouchDB-to-CouchDB replication (ADR-028)One sync path, no server code of ours in the data pathPrivacy, Operability
Sync modeSelf-hosted or forked cloud, chosen by /forked-config.json (ADR-038)One image serves both; users never chooseLearnability, Evolvability
ConflictsCouchDB deterministic revision winner (ADR-025)Convergence without custom codeReliability
i18nreact-i18next with JSON filesStandard, easy to extend (Section 8.5)Internationalization
AI importOpt-in, user’s own provider and key (ADR-024)Only off-device path besides sync, gated by consentPrivacy, Usability
Tests, CIVitest, Playwright, GitHub ActionsSection 8.8Reliability

4.3 Achieving the Quality Goals

GoalApproach
UsabilityMobile-first adaptive shell, bottom navigation on phones, optimistic local updates, 44×44 px touch targets (Section 8.2).
LearnabilityFamiliar mobile patterns, minimal configuration, one sync flow per deployment. Self-hosting asks only for a user name and password; address and database are implicit.
Offline-FirstRead and write the local store first; live replication runs in the background; conflicts converge automatically (Section 6.2, Section 6.3).
PrivacyData leaves the device only through household sync and consented AI import; no analytics; a restrictive CSP; no built-in backend; export for portability (Section 8.3). Security measures are part of this goal.
InternationalizationAll UI text from locale files, German and English, key parity enforced (Section 8.5).

4.4 Sync Modes

The PWA replicates directly with CouchDB in both modes. The Sync page shows exactly one flow.

AspectSelf-hosted mode (no gateway announced)Forked cloud mode (gateway announced)
IdentityOne CouchDB user shared by all devices; no accounts, invites or device recordsAccount on the operator’s website; each device enrolled by device approval or invite
CredentialUser name and password, stored as SelfHostedLogin; Basic authSession cookie at the gateway, 15-minute CouchDB JWT in memory; stored only as GatewayEnrollment
DatabaseFixed name forked, address from the announcementNamed by the sync token and pinned per device
Server sidePlain CouchDB and proxy (Section 7.1)Operator gateway and website, outside this repository (Section 7.3)
FlowSection 6.1Section 6.4

One deployment equals one household and one database. Multi-tenancy belongs in the operator’s gateway, not in the self-hosted default. Self-hosting is the baseline because it fits the main use case, one household with as little operator complexity as possible and data on infrastructure the household controls.

4.5 Patterns

  • Local store as single source for the UI: components read and write through ForkedDatabase only (Section 5.1); they never talk to the network for core data.
  • Background replication: PouchDB live sync with retry: true replicates the local database. There is no application operation queue. Start-up retries and failure rules are in Section 6.2.
  • Strategy per mode: both modes share syncWithRemote and the status store and differ only in how the remote is authenticated (Section 5.2).
  • Layered dependencies: enforced by an architecture test (ADR-031).

View source on GitHub