Appearance
Architecture
Doc status: Latest (rolling). See Versions.
Design principle
NWatch scopes membership to invited groups. Managers control membership and the API enforces it. Members can belong to multiple groups and choose their outgoing alert destinations; managers can operate multiple groups in the portal. See Security and Encryption and group access for the trust model.
High level
- Mobile App — current source (Expo SDK 58 / React Native 0.88 with React Native Firebase 26 modular native APIs)
- Admin Web — current source (Next.js 16 API surface / React 19, built with Vite 8 and vinext for Cloudflare Workers)
- Manager Portal — current source (React 19 / Vite 8, Firebase 13 modular browser SDK)
- API (Cloudflare Workers — Hono)
- Data (Firestore)
- Push (FCM → APNs/Android)
- Payments (Stripe — REST API, no SDK)
- PQC Crypto (iOS native CryptoKit via
@neighbourhoodwatch/pqc-native+ JS fallbackmlkem/@noble/ciphers)
The September 2026 toolchain uplift is source-only. It does not change the already-built 1.2.30 artifacts or establish a production deployment, native build, store submission or physical-device acceptance for the new dependencies. Release availability and device verification remain separate gates.
mermaid
flowchart LR
Mobile[Mobile App] -->|Firebase ID Token| API[Cloudflare Worker API]
Admin[Admin Web] -->|CF Access JWT| API
EntraID[Microsoft Entra ID] -->|OIDC SSO| CFA[Cloudflare Zero Trust Access]
CFA -->|JWT cookie| Admin
API -->|Firestore REST| DB[(Firestore)]
API -->|FCM HTTP v1| FCM[FCM]
API -->|REST| Stripe[Stripe]
Stripe -->|Webhooks| API
FCM --> APNs[APNs / iOS]
FCM --> Droid[Android]Request / auth flow
Mobile (Firebase Auth — native SDK)
- User signs in via
@react-native-firebase/auth(native SDK) using Google, a passwordless email link, or Microsoft when configured; Sign in with Apple is also available on iOS. Current source uses modular functions such asgetAuth()andsignInWithCredential(auth, credential), not the removed namespacedauth().…API. - The native SDK initializes automatically via
google-services.json(Android) andGoogleService-Info.plist(iOS) — no JS-levelinitializeAuthcall. - App calls the Worker API with
Authorization: Bearer <FirebaseIdToken>. - Worker verifies the Firebase ID token server-side.
- Worker enforces authorization (role + membership + status) server-side.
Super-admin console (Cloudflare Zero Trust + Microsoft Entra ID)
- Admin visits the dashboard — Cloudflare Access intercepts and redirects to Microsoft Entra ID SSO.
- After SSO, CF Access sets a signed
CF_AuthorizationJWT cookie. - Admin app reads the cookie and forwards it as
cf-access-jwt-assertionheader to the Worker API. - Worker verifies the CF Access JWT against the team's JWKS endpoint.
- Worker maps the Entra email to a Firestore user (auto-provisions a stub if new).
- Worker enforces authorization (role + membership + status) server-side.
Common
- Worker reads/writes Firestore via REST using a service account.
- Worker triggers push fan-out using FCM HTTP v1.
Authorization model
Standard users (mobile only) can:
- register device
- join group via invite
- trigger incident (only for groups they are an active member of, with active license)
- view their own profile and notifications
Managers can (scoped to their groups):
- create groups and invite codes
- pause/remove members and manage member roles
- review member device readiness
- reveal one incident's encrypted details through an audited workflow and resolve incidents
- view group members, invites and licence status
- manage seats, billing and Stripe checkout for group licences
Super admins (platform-wide) can:
- view all users, groups, licenses, payments
- set user roles (standard/manager/super_admin)
- grant and revoke licenses
- perform platform administration across groups; plaintext incident reveal remains separately gated by direct active group membership
Server-side checks are mandatory for all privileged actions.
Data model (logical)
This is the conceptual structure (implemented in Firestore collections/subcollections):
users/{uid}- profile:
email,displayName,role,status devices/{deviceId}:platform,token,createdAt,lastSeenAt
- profile:
groups/{groupId}- metadata:
name,zoneId,createdByUid,createdAt members/{uid}:role(member/manager),status(active/paused/banned)incidents/{incidentId}: incident records
- metadata:
invites/{inviteCode}groupId,expiresAt,maxUses,uses,revoked
licenses/{licenseId}groupId,status(active/expired/revoked/trial),type(paid/granted)stripeSubscriptionId,stripeCustomerId,grantedByUidstartsAt,expiresAt
payments/{paymentId}licenseId,groupId,adminUidstripePaymentIntentId,amount,currency,status
notifications_log/{notifId}type,targetUid,groupId,message,read
system/cryptokemPublicKey,kid,updatedAt— the server-managed system KEM identity
Security model
- All privileged actions are checked server-side:
- Mobile auth: Firebase ID token verification
- Manager portal auth: Firebase ID token verification
- Super-admin auth: Cloudflare Access JWT verification (JWKS), backed by Microsoft Entra ID SSO
- Authorization: group manager role checks in Firestore
- The super-admin console is gated by Cloudflare Zero Trust — only authorised Entra ID users can reach it.
- Do not persist saved addresses as plaintext profile fields; use coarse zones for group organisation and encrypted incident envelopes for sent address/GPS snapshots.
Platform ownership
The current contracting entity and operator details are maintained in the public Terms and Privacy Policy.
Alert encryption and key management
The phone snapshots the selected groups, their saved alert text and optional current GPS when the member sends. It encrypts the snapshot before upload, independently for each recipient using ML-KEM-768 and AES-256-GCM. Every envelope has its own KEM ciphertext, encrypted message, nonce, authentication tag and group/incident/recipient/key context.
The API authorises group membership, stores encrypted envelopes and sends generic push notifications. Active members fetch their own envelopes and decrypt locally. Separate groups receive separate incidents; a member's outgoing selection does not grant access to another group's content.
Member private keys stay in OS-protected phone storage. The production service-recovery private key is an encrypted Cloudflare Worker secret: hidden from dashboard/Wrangler readback but available to the authorised Worker at runtime. A separate recovery envelope supports audit-logged manager reveal and incident-key recovery. Neither operation reads unsent phone settings or live GPS, and neither is account recovery.
The manager portal fetches metadata first. Reveal alert details makes a separate, group-authorised request for that incident's plaintext, returned over HTTPS. The service does not save the decrypted result back to the incident database.
See Encryption and group access for the algorithms, AAD wire contract, local key storage, membership changes, multiple groups and portal instructions.
Emergency alert capabilities
- Android: Channel
alertsis created natively withAudioAttributes.USAGE_ALARM, high importance, public lock-screen visibility, and custom sirenalarm.wav. Full-screen and DND behavior depends on Android policy, user settings and special access. The app neither changes global DND mode nor raises system alarm volume, and it no longer requests overlay permission. - iOS: Incident pushes use APNs alert payload (
aps.alert) withapns-priority: 10and Critical Alert sound object (sound.critical: 1,name: alarm.wav,volume: 1.0) plusinterruption-level: critical. - Permission hardening: Mobile startup runs a readiness check for ordinary notifications, iOS critical-alert authorisation, Android full-screen intent access and channel settings. The home screen preserves a visible readiness warning until required device settings are reviewed.
See also: Security.
Static “waterfall” delivery plan
The requirements are intentionally clear and narrow; this supports a straightforward waterfall delivery sequence:
- Requirements sign-off (roles, invite join, alerting, admin controls, data minimisation)
- System design sign-off (API contracts + data model + security invariants)
- Implementation
- Worker API + Firestore schema
- Mobile minimal UX
- Admin minimal UX
- Verification
- Contract tests (local/staging)
- Staging E2E tests
- Deployment
- Worker deploy
- Mobile release pipeline
- Admin deploy
- Operational hardening
- Monitoring + alerting
- Incident review process
Content & diagrams
- Put images in
docs/public/images/and reference as/images/.... - Use Mermaid blocks (like above) for flow diagrams.