critical priority high complexity backend pending backend specialist Tier 0

Acceptance Criteria

A deriveOrgKey(orgId, masterSecret, keyVersion) function exists and produces a deterministic 256-bit key using HKDF-SHA256 with orgId as the info parameter and a static application salt
Different orgIds produce cryptographically distinct derived keys — verified by test asserting no two org keys are equal across a sample of 10 org IDs
The master secret is never stored in the mobile app binary or Dart source code — it is loaded exclusively from Supabase Edge Function environment variables
Key versioning: each derived key is tagged with an integer version; the current active version is stored in a secure server-side configuration store (Supabase secrets or equivalent)
Key rotation: incrementing the key version produces a new derived key; old versions remain derivable from the same master secret for decryption of existing blobs
AES-256-GCM encryption function accepts plaintext bytes, org key bytes, and returns ciphertext + 12-byte nonce + key version integer as a structured EncryptedBlob object
AES-256-GCM decryption function accepts an EncryptedBlob, looks up the correct org key by version, and returns plaintext bytes; returns a typed DecryptionError if the key version is unknown
All key derivation and encryption logic runs server-side inside a Supabase Edge Function (Deno) — no cryptographic key material is ever sent to or processed on the mobile client
Unit tests cover: correct key derivation for known inputs, encryption round-trip (encrypt then decrypt returns original plaintext), decryption with wrong key version returns error, decryption with tampered ciphertext returns error
The EncryptedBlob structure includes: ciphertext (Uint8List), nonce (12 bytes), keyVersion (int), orgId (String), encryptedAt (ISO-8601 timestamp)

Technical Requirements

frameworks
Supabase Edge Functions (Deno)
Dart (client-side service interface only)
apis
Supabase Edge Functions REST API
Supabase Secrets (for master secret storage)
data models
confidentiality_declaration
performance requirements
Key derivation (HKDF) must complete in under 5ms server-side
AES-256-GCM encryption of a 10KB payload must complete in under 20ms server-side
security requirements
Master secret minimum 256 bits of entropy, stored only in Supabase Edge Function environment secrets — never in database or source code
HKDF-SHA256 used for key derivation with application-specific salt and orgId as context (info parameter) to ensure domain separation
Each encryption operation generates a fresh random 12-byte nonce via crypto.getRandomValues() — nonces must never be reused
Key material never logged, never included in error messages, never transmitted over any channel other than the secure server environment
Key version stored in blob metadata (not secret) to allow version lookup during decryption without exposing key material
Access to the key derivation Edge Function restricted to service role JWT — never callable from mobile client directly

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implement entirely as a Supabase Edge Function (Deno/TypeScript). Use the Web Crypto API (SubtleCrypto) available natively in Deno for HKDF and AES-GCM — do not add third-party crypto libraries. Master secret loaded via Deno.env.get('DECLARATION_MASTER_SECRET'). Key version stored in Deno.env.get('DECLARATION_KEY_VERSION') as an integer, defaulting to 1.

For key rotation, bump DECLARATION_KEY_VERSION — old versions are re-derived on-demand using the same master secret and HKDF, so there is no need to store old keys. The Dart service class on mobile should expose only two methods: encryptDeclaration(Uint8List plaintext, String orgId) → Future and decryptDeclaration(EncryptedBlob blob) → Future; both invoke the Edge Function via authenticated HTTP POST. Keep the EncryptedBlob Dart model as a plain serializable value object with no crypto logic.

Testing Requirements

Server-side unit tests (Deno test) covering: deriveOrgKey produces consistent output for same inputs (idempotency), deriveOrgKey produces distinct output for different orgIds, encrypt+decrypt round-trip with version 1 key, decrypt with version 2 key on version-1 blob returns DecryptionError, decrypt with bit-flipped ciphertext returns error. Integration test: deploy Edge Function to a Supabase staging environment and invoke via REST, asserting correct encrypted blob structure in response. No cryptographic tests on the Flutter/Dart side — the mobile layer should only see opaque base64 blobs.

Component
Declaration Encryption Service
service high
Epic Risks (4)
high impact medium prob security

Org-scoped encryption key management is complex. If keys are not correctly isolated per organization, a breach in one org's key could expose another org's declarations. Additionally, key rotation is not specified but may be needed for compliance, and the current implementation may not support it.

Mitigation & Contingency

Mitigation: Use Supabase Vault or a dedicated secrets management approach for org-scoped key storage. Define the key derivation strategy (per-org master key) in a security design document reviewed before implementation begins. Include key isolation tests in the test suite.

Contingency: If a full per-org key management system cannot be safely implemented within the sprint, fall back to a single platform-level encryption key with strict RLS isolation as a temporary measure, flagging the key rotation gap as a security debt item with a defined resolution milestone.

medium impact medium prob integration

Push notification delivery to drivers depends on FCM token availability and device connectivity. If a driver has not granted notification permissions or has an expired FCM token, the declaration delivery notification will silently fail, leaving the coordinator unaware and the declaration unacknowledged.

Mitigation & Contingency

Mitigation: Implement delivery status tracking in declaration-notification-service. Fall back to in-app notification and SMS (if configured) when push delivery fails. Expose delivery failure status in the declaration status badge so coordinators can identify and manually follow up.

Contingency: If push delivery proves unreliable, implement a polling-based in-app notification fallback where drivers see pending declarations on next app open, ensuring the workflow can complete even without push notifications.

medium impact medium prob technical

The acknowledgement service is meant to validate that the driver has fully scrolled through the declaration before confirming. Implementing reliable scroll completion detection in Flutter across different screen sizes and font sizes is technically non-trivial and could be bypassed.

Mitigation & Contingency

Mitigation: Implement scroll position tracking using ScrollController with a threshold (e.g., 95% of content height reached) and record the validated state server-side before allowing acknowledgement submission. Document the approach in the legal sign-off checkpoint noted in the feature documentation.

Contingency: If reliable scroll detection cannot be implemented within the sprint, add a mandatory reading delay timer (e.g., estimated reading time based on word count) as an alternative validation mechanism, pending legal review of the approach.

medium impact low prob dependency

The driver assignment service must coordinate with the threshold-based expense approval workflow for fees above configured thresholds. If the expense approval workflow interface changes or is not yet stable, the integration point could break or produce incorrect routing behavior.

Mitigation & Contingency

Mitigation: Define a clear interface contract between driver-assignment-service and the expense approval workflow before implementation. Use dependency injection so the expense workflow client can be mocked in tests. Monitor the expense approval feature for interface changes.

Contingency: If the expense approval workflow interface is not stable, implement a direct database insert to the expense records table as a temporary bypass, with a flag indicating manual review is needed, until the stable interface is available.