Appearance
Data Flow Diagrams
Security controls are annotated on each trust boundary.
1. Evidence ingestion (on-device)
mermaid
flowchart TD
A[User selects receipt PDF/PNG] --> B[PDF text layer / OCR]
B --> C[Tier-1 Regex extraction]
C --> D{Indicators complete?}
D -->|Yes| E[PII strip NRIC/phone/email]
D -->|No| F[Tier-2 NER optional]
F --> E
E --> G{User saves evidence?}
G -->|Yes| H[IndexedDB AES-GCM envelope<br/>PIN → PBKDF2]
G -->|No| I[Discard raw text]
E --> J[Build telemetry + RS256 JWT]
classDef ctrl fill:#e8f5e9,stroke:#2e7d32
E:::ctrl
H:::ctrl
J:::ctrlControls: on-device processing · PII strip · optional local encryption · JWT payload binding.
2. Telemetry egress
mermaid
flowchart LR
A[SDK submitTelemetry] -->|HTTPS + JWT| B[Gateway pre-auth IP throttle]
B --> C[RS256 verify + jti replay check]
C --> D[Payload hash binding]
D --> E[Advisory policy<br/>disposition=advisory]
E --> F[202 ACCEPTED + event_id<br/>schema_version: 2]
E --> G[Event bus / in-process pipeline]
G --> H[Encrypted alert row + outbox]
G --> I[SSE fan-out]
classDef ctrl fill:#e8f5e9,stroke:#2e7d32
B:::ctrl
C:::ctrl
D:::ctrl
E:::ctrlControls: TLS · partner key registry · jti TTL · advisory contract · rate limits.
3. FMS alert delivery
mermaid
flowchart TD
A[Ingest accepted] --> B[Format FmsRiskAlert]
B --> C[Gateway sign alert]
C --> D{FMS_WEBHOOK_URL set?}
D -->|No| E[Local only + SSE]
D -->|Yes| F[HTTPS POST webhook]
F --> G{Success?}
G -->|Yes| H[Log delivered]
G -->|No| I[Retry / fail<br/>B4 outbox TBD]
C --> J[SSE fan-out<br/>B3 Redis pub/sub TBD]
classDef ctrl fill:#e8f5e9,stroke:#2e7d32
C:::ctrl
F:::ctrl
classDef gap fill:#fff3e0,stroke:#ef6c00
I:::gap
J:::gapControls today: HTTPS-only FMS in production · delivery required flag · durable outbox when DATABASE_URL set · Redis SSE pub/sub when Redis configured.
4. Key management
mermaid
flowchart TD
subgraph Client
P[User PIN] --> K[PBKDF2]
K --> DEK1[Evidence DEK]
DEK1 --> ENC[AES-256-GCM evidence]
end
subgraph Gateway
PK[PARTNER_KEYS_JSON<br/>partner public keys] --> V[JWT verify]
GP[GATEWAY_*_PEM] --> S[Alert / demo sign]
KEK[ALERT_DATA_KEK] --> WRAP[Wrap per-row DEK]
WRAP --> ROW[alerts.*_ciphertext + AAD]
end
classDef ctrl fill:#e8f5e9,stroke:#2e7d32
K:::ctrl
ENC:::ctrl
V:::ctrl
WRAP:::ctrl
ROW:::ctrlControls: envelope encryption · AAD tenant_id:alert_id:field · KEK registry by kek_key_id · never log plaintext/DEK.