DIREKT Functional Web/PWA Parity Implementation Plan¶
Status: Authoritative implementation workstream
Authorized: 2026-07-19 by repository owner
Baseline: synchronized main checkpoint after PR #152 (885eb72dcda12be8c23c4068dec138562af5888a)
Implementation lane: build/android-v1
Related trackers: Issue #133 (customer/provider PWA), Issue #112 (real Phase 11 pilot evidence/exit)
1. Objective¶
Deliver a real customer/provider browser application that is functionally equivalent to the DIREKT Android product while preserving Android as the primary native Version 1 client and Play release target.
The web/PWA is not a separate product and must not invent a second business logic stack. Android and web must converge on the same:
- NestJS REST/OpenAPI contracts;
- PostgreSQL/PostGIS system of record;
- private object-storage boundary;
- DIREKT identity/session and server-side authorization rules;
- provider scope resolution;
- verification/trust semantics;
- discovery/publication rules;
- enquiry, contact-consent, interaction, review and complaint lifecycles;
- commercial/subscription state;
- privacy and audit rules.
Desktop is a layout adaptation only. Mobile web retains bottom navigation aligned to Android. Desktop uses persistent side navigation with the same destinations and capabilities.
2. Non-negotiable architecture¶
DIREKT PRODUCT
│
┌──────────────┴──────────────┐
│ │
Android Client Web/PWA Client
Jetpack Compose Next.js / React
│ │
bottom navigation mobile: bottom nav
desktop: side nav
│ │
└──────────────┬──────────────┘
│
Canonical OpenAPI
│
DIREKT NestJS API
│
┌───────────────┼────────────────┐
│ │ │
PostgreSQL PostGIS Private Storage
│ │ │
└───────────────┴────────────────┘
│
Identity / Trust / Enquiries / Reviews
/ Commercial / Audit
Browser deployment boundary¶
Browser
│ HTTPS
▼
DIREKT Web/PWA — Next.js
│
│ reviewed BFF/session boundary
▼
IAM-private DIREKT NestJS API
│
├── PostgreSQL/PostGIS
└── private Storage grants
The IAM-private API must not be made unauthenticated merely to support the browser client.
The browser must never receive privileged Supabase/database credentials, service-role keys or unrestricted private Storage authority.
3. Technology decision¶
Create the real client under:
web/direkt-app/
Use:
- Next.js;
- React;
- TypeScript;
- installable PWA manifest and bounded service worker;
- typed canonical REST/OpenAPI client boundary;
- server-side BFF/session routes where authenticated browser access requires protected Cloud Run invocation;
- the existing DIREKT visual language and trust vocabulary.
Do not:
- convert Android to Kotlin Multiplatform;
- move Compose UI into shared cross-platform binaries;
- introduce Flutter Web, Vue, Angular or another UI framework for this workstream;
- make the existing private API public;
- connect browser code directly to privileged Supabase/database/Storage surfaces;
- count static fixtures as functional parity when an authoritative backend capability exists.
The current Android project is a single :app Compose module. Preserving that stable structure is lower risk than a cross-platform refactor.
4. Existing synthetic PWA treatment¶
web/direkt-pwa/ is the current synthetic review surface. It remains preserved while the functional app is built.
It must not be silently converted into a live client because current integration-security checks intentionally require that preview surface to remain disconnected from privileged/live APIs.
The controlled cutover occurs only after the real application passes the parity, security and regression gates. Historical preview content is then retained under a clearly labelled archival/preview route.
5. Functional parity definition¶
Parity means:
same product capability
+ same authoritative backend contract
+ same authorization and provider scope
+ same state transitions
+ same trust/privacy semantics
+ same observable business outcome
+ equivalent Android-aligned UX
Parity does not mean copying Android preview fixtures into JavaScript.
A change made through Android must become observable through web, and a change made through web must become observable through Android, whenever both clients support that capability, because both operate on the same backend state.
6. Navigation and responsive contract¶
Customer destinations¶
- Discover
- Saved
- Enquiries
- Account
Provider destinations¶
The browser may present provider-friendly labels while preserving the same product capability mapping:
- Overview / workspace
- Evidence / verification readiness
- Enquiries
- Account / profile / commercial
Viewports¶
- Mobile: Android-aligned bottom navigation.
- Tablet: navigation rail or compact side navigation according to available width.
- Desktop: persistent side navigation; no bottom navigation.
The content hierarchy, actions, trust semantics and state are shared across viewports. Desktop must not become a separate admin-style product.
7. Browser authentication/session contract¶
Firebase may prove phone possession for the controlled pilot direction, but Firebase claims never become DIREKT authorization.
Target flow:
Firebase Web phone authentication
↓
Firebase ID token
↓
DIREKT Web BFF
↓
POST /api/v1/auth/firebase/exchange
↓
DIREKT rotating session
↓
HttpOnly + Secure + SameSite browser session boundary
DIREKT roles, permissions, provider scope, admission, consent and trust state remain backend-authoritative.
Do not store refresh tokens or long-lived sensitive session material in localStorage, sessionStorage, IndexedDB or JavaScript-readable cookies.
Authenticated browser activation is separately gated until BFF/session, CSRF, origin, IAM invocation, timeout/retry, logout/revocation and canary evidence pass.
8. Implementation sequence¶
W0 — Baseline freeze and parity map¶
Deliver:
- exact source baseline recorded;
- Android protected-path contract;
- current Android screen/navigation inventory;
- canonical OpenAPI capability inventory;
- feature classification: API-backed, implemented-gated, preview-only, external-gated;
- functional parity matrix;
- project-wide architecture, testing and no-regression documentation;
- workstream lock claimed.
Exit:
- no ambiguity about what parity means;
- Android baseline remains unchanged;
- every planned browser capability maps to an authoritative product/API boundary or is explicitly gated.
W1 — Functional web foundation¶
Create web/direkt-app/ with:
- Next.js/React/TypeScript foundation;
- DIREKT design tokens;
- responsive shell;
- mobile bottom navigation;
- tablet adaptive navigation;
- desktop side navigation;
- PWA manifest;
- bounded service worker/offline shell;
- loading, empty, error and offline states;
- BFF boundary scaffolding;
- typed API foundation;
- strict environment validation;
- CSP/security-header baseline;
- unit/static/accessibility-oriented component checks;
- CI that also proves protected Android paths did not regress.
Exit:
- clean web build/test/typecheck;
- no privileged material in browser bundle;
- Android gates remain green;
- no real participant or production activation.
W2 — Real public discovery vertical slice¶
Connect through canonical API contracts:
- public categories;
- provider search;
- results;
- provider profile;
- scoped trust claims;
- availability;
- public reviews/share projection where applicable.
Use backend-managed synthetic/test state, not hard-coded UI fixtures, to prove end-to-end connectivity.
Exit:
- backend state changes are observable in the web client;
- public projections expose no private evidence/contact/exact-coordinate data;
- manual/list fallback remains first-class.
W3 — Authentication and account¶
Implement:
- Firebase Web phone-possession flow when approved configuration is present;
- BFF Firebase-to-DIREKT exchange;
- secure browser session handling;
- rotation/logout/revocation/expiry;
- notice/consent admission boundary;
- account/profile/session views;
- backend-derived role/provider mode.
Exit:
- no client-selected provider scope;
- CSRF/origin/session replay and expiry tests pass;
- fail-closed behavior when configuration/gates are absent.
W4 — Customer journey parity¶
Implement:
- discover/search/filter/area;
- save/unsave where canonical contract supports it;
- provider profile and trust details;
- enquiry creation/history/detail/cancel;
- consent-aware contact handoff/revoke;
- interaction history;
- review eligibility and review submission;
- report/appeal/complaint paths supported by the canonical contract;
- account/security/session UX.
Exit:
- every successful mutation produces durable backend acknowledgement;
- Android/web observe the same authoritative lifecycle state.
W5 — Provider journey parity¶
Implement:
- workspace overview/readiness;
- profile/services/operating model/service areas;
- verification/evidence requirements;
- recoverable private evidence upload flow;
- enquiry inbox/detail/transitions;
- contact-handoff state;
- interactions;
- reviews/provider response/appeal;
- account/profile/security;
- commercial/subscription state.
Exit:
- provider scope is actor-resolved server-side;
- private evidence never becomes public/browser-cached;
- retries remain idempotent/recoverable.
W6 — Commercial parity within authorized boundaries¶
Implement only currently authorized domain capabilities:
- product catalogue;
- entitlements/subscription status;
- subscription lifecycle actions;
- invoices/payment-intent state where contract-supported;
- cancellation/status/receipts where contract-supported.
Real MTN MoMo/Airtel Money movement remains disabled until separately approved and runtime-proven.
W7 — Cross-client parity and regression closure¶
Run:
- Android unit/lint/debug/release-policy checks;
- backend/database/OpenAPI checks;
- web unit/type/build/e2e checks;
- customer/provider cross-client parity matrix;
- authorization and provider-scope negatives;
- responsive viewport suite;
- keyboard/focus/screen-reader/contrast/reduced-motion checks;
- slow network/offline/interrupted upload/retry/expired-session scenarios;
- private-data/cache/security scans;
- browser session/CSRF/origin tests.
Exit:
- all applicable parity rows PASS;
- no Android regression;
- no critical/high unresolved review finding;
- no gated provider is falsely promoted.
W8 — Controlled cutover¶
Only after W7:
- preserve current synthetic preview under an explicit historical/preview route;
- promote the functional browser application to the approved canonical app route/domain;
- verify DNS/TLS/runtime health/service-worker/manifest;
- keep production/real-participant gates separate from browser deployment readiness;
- update Issue #133 only when its acceptance evidence is genuinely complete.
9. No-regression contract¶
android/direkt-app/**is protected during W0/W1 unless a separately reviewed compatibility change is unavoidable.- No Android dependency, Gradle wrapper, Compose, Firebase or release/signing upgrade is bundled with PWA work.
- Shared backend/OpenAPI changes are backward compatible by default: additive endpoint/field/versioned behavior rather than destructive rename/removal.
- Every shared contract/backend PR runs Android regression gates.
- Android baseline-before versus result-after must be equivalent for unchanged capabilities.
- No KMP/shared-UI refactor is permitted by this workstream.
- Exact-head CI and review findings are resolved before merge.
- Existing Phase 11/12 legal, participant, payment, signing and production gates remain unchanged.
10. Security/privacy invariants¶
- no direct browser database access;
- no privileged Supabase/service-role credential in client/server bundle source;
- no private evidence URL persisted beyond bounded authorized use;
- no exact private provider coordinate exposed to public discovery;
- no trust claim created by payment, UI flags or client assertions;
- no browser mode toggle grants authorization/provider scope;
- no arbitrary authenticated API response caching in service worker;
- no fake success for offline mutations;
- timeout/retry/idempotency behavior is explicit;
- logs and telemetry minimize personal/contact/location data;
- real participant activation remains gated.
11. Definition of done for functional browser parity¶
The workstream is complete only when all applicable rows in docs/web/FUNCTIONAL_PARITY_MATRIX.md pass and:
- customer and provider workflows are backend-functional rather than fixture-only;
- desktop has side navigation and no bottom navigation;
- mobile retains bottom navigation;
- Android and web operate against the same authoritative state/contracts;
- installability/offline shell/accessibility/responsiveness pass;
- authenticated web access preserves the private API/IAM boundary;
- Android regression evidence is green;
- current synthetic preview is preserved until controlled cutover;
- no formal Phase 11/12 gate is overclaimed.
12. Reversal conditions¶
Revert or narrow the workstream if implementation requires:
- making the canonical API public without an approved gateway/BFF decision;
- weakening Android release/security gates;
- direct privileged Supabase access from browser code;
- a cross-platform Android rewrite;
- material trust/privacy/authorization changes not separately approved;
- production/provider activation without required evidence.