Architecture Validation Report
Architecture Docs Validation Report
Date: 2026-02-21
Scope: All 41 architecture docs in docs/architecture/
Method: 3 critic agents (code, consistency, completeness) + 1 validator agent
Source of truth: Actual source code in src/drop-api/, src/drop-app/, src/drop-mobile/
Summary
| Metric | Count |
|---|---|
| Total findings submitted | 104 |
| Confirmed (real issues) | 70 |
| Rejected (false positives) | 34 |
| Docs affected | 34 of 41 |
Severity Breakdown
| Severity | Count | Description |
|---|---|---|
| HIGH | 21 | Factual errors, security gaps, regulatory compliance issues |
| MEDIUM | 37 | Incorrect details, cross-doc inconsistencies, missing coverage |
| LOW | 12 | Minor naming issues, broken cross-refs, cosmetic |
Root Cause Clusters
| # | Root Cause | Findings | Fix |
|---|---|---|---|
| 1 | Next.js version: 16 to 15 | CODE-001 thru CODE-004, CODE-030, CODE-042 (6) | Global find-replace "Next.js 16" to "Next.js 15" |
| 2 | JWT lifetime: 24h/7d to 7d uniform | CODE-011, CODE-012, CODE-013, CONS-001, CONS-002, CONS-003 (6) | Replace all "24h (web) / 7d (mobile)" with "7d (all clients)" |
| 3 | SameSite: strict to Lax | CODE-009, CODE-010, CODE-028, CONS-004 (4) | Replace "sameSite=strict" to "sameSite=Lax" |
| 4 | middleware.ts to middleware/*.ts | CODE-015, CODE-025, CODE-026 (3) | Fix all "middleware.ts" references to actual file paths |
| 5 | Deprecated 410 endpoints still documented | CODE-045, COMP-002, CODE-031, CONS-014 (4) | Remove/update email+password flows, document 410s |
| 6 | Amount units: NOK to ore in DB | CODE-008, CONS-019, COMP-020 (3+) | Clarify DB stores ore, API converts to/from NOK |
| 7 | Deployment: aspirational vs actual | CODE-005, CODE-024, CONS-007, CONS-008 (4) | Mark AWS/blue-green as planned; document Docker Compose as current |
| 8 | Demo mode undocumented | CODE-019, CODE-020, CODE-034, CODE-047, COMP-001 (5) | Document demo-login flow and SEED_DEMO override |
| 9 | Mobile storage: SecureStore to AsyncStorage | CODE-014, CONS-005 (2) | Fix to AsyncStorage (expo-secure-store is devDep) |
| 10 | Data classification scheme mismatch | CONS-006 (1) | Unify to one taxonomy across security + data architecture |
HIGH Severity Findings (21)
H1. Next.js Version Wrong (6 docs)
IDs: CODE-001, CODE-002, CODE-003, CODE-004, CODE-030, CODE-042
Docs: component-overview, system-context, container-diagram, deployment-architecture, ADR-011
Claim: "Next.js 16"
Reality: next: ^15.5.12 (src/drop-app/package.json:24)
Fix: Replace all "Next.js 16" with "Next.js 15"
H2. Deployment Architecture Aspirational (2 docs)
IDs: CODE-005, CODE-024 Doc: deployment-architecture.md Claim: AWS App Runner, ECR, RDS, Secrets Manager, Fly.io staging Reality: Only docker-compose.yml and docker-compose.production.yml exist. No fly.toml, no apprunner.yaml, no CI/CD. Fix: Mark deployment targets as planned. Document current Docker Compose setup.
H3. Dockerfile 4 Stages, Not 3
ID: CODE-006 Doc: deployment-architecture.md Claim: 3-stage build (deps, builder, runner) Reality: 4 stages: deps, test, builder, runner. Test stage is mandatory quality gate. Evidence: src/drop-app/Dockerfile:15 (test), :48 (builder), :81 (runner) Fix: Document 4-stage pipeline. Highlight mandatory test gate.
H4. Build Tools in Production Image
ID: CODE-007 Doc: deployment-architecture.md Claim: "No build tools in final image" Reality: Runner stage installs python3, make, g++ (Dockerfile:82) Fix: Update doc AND flag as security concern.
H5. Amount Units: NOK vs ore
ID: CODE-008
Doc: flow-qr-payment.md
Claim: Amount in response is NOK (e.g., amount: 129)
Reality: DB stores ore. nokToOre() at transactions.ts:13. Seed data: 4500000 ore = 45000 NOK.
Fix: Document dual representation: API accepts/returns NOK, DB stores ore.
H6. JWT Lifetime Wrong (5 docs)
IDs: CODE-011, CODE-012, CODE-013, CONS-001, CONS-002, CONS-003
Docs: flow-login-authentication, data-architecture, ADR-004, ADR-007
Claim: "24h (web), 7d (mobile)"
Reality: signToken(payload, expiresIn='7d') -- uniform 7d. No platform branching. (auth.ts:42)
Fix: Replace all "24h web / 7d mobile" with "7d (all clients)"
H7. Data Classification Scheme Mismatch
ID: CONS-006 Docs: data-architecture.md vs security-architecture.md Claim: data-arch uses CRITICAL/HIGH/MEDIUM/LOW; security uses CRITICAL/RESTRICTED/CONFIDENTIAL/INTERNAL/PUBLIC Fix: Adopt one taxonomy across both docs.
H8. Registration Flow is BankID-Only
ID: CONS-014 Docs: component-overview.md, flow-registration-onboarding.md Claim: "4 steps (info, OTP, PIN, success)" Reality: /register returns 410. Users auto-created on first BankID login (bankid.ts:findOrCreateUser). Fix: Update to BankID auto-registration.
H9. Demo Mode Architecture Undocumented
ID: COMP-001 Evidence: auth.ts:131-158 (demo-login), mode.ts (isDemoMode), payments.ts (demo branching) Fix: Create flow-demo-mode.md or add section to existing auth docs.
H10. Token Refresh + 410 Endpoints Undocumented
ID: COMP-002 Evidence: auth.ts:201-210 (POST /refresh), auth.ts:109-128 (three 410 endpoints) Fix: Add refresh flow and deprecated endpoints table.
H11. GDPR Endpoints Undocumented
ID: COMP-003 Evidence: user.ts:132-360 -- POST /objection, /rectification, /restriction Claim in docs: "Manual process" (data-lifecycle.md) Reality: Fully implemented API endpoints with audit logging. Fix: Update data-lifecycle.md. Create GDPR rights matrix.
H12. Withdrawal/Angrerett Flow Undocumented
IDs: COMP-004, COMP-005 Evidence: withdrawal.ts creates withdrawal_requests table at runtime. Fix: Create flow-withdrawal.md. Add table to schema docs.
H13. Error Handling Chain Undocumented
ID: COMP-007 Evidence: error-handler.ts, Sentry (captureError), alerts. app.ts:50 mounts globalErrorHandler. Fix: Add observability section to docs.
H14. Merchant = Admin (Security Gap)
ID: COMP-013
Evidence: admin.ts:14-16 -- isAdmin(role) { return role === 'merchant' }
Impact: Any merchant can access audit logs, screening, and file STRs.
Fix: Document RBAC model. Flag for security review.
H15. Transaction Reconciliation Missing
ID: COMP-024 Evidence: QR payments INSERT as 'completed' immediately (transactions.ts:459). Remittances as 'processing' with no webhook/polling. Fix: Document the gap. Note production needs async reconciliation.
MEDIUM Severity Findings (37)
| ID | File | Issue | Fix |
|---|---|---|---|
| CODE-009 | security-architecture.md | SameSite=strict, actual Lax | Change to Lax |
| CODE-010 | flow-login-authentication.md | Cookie: 24h strict, actual 7d Lax | Fix both values |
| CODE-014 | security-architecture.md | SecureStore, actual AsyncStorage | Fix storage name |
| CODE-015 | security-architecture.md | middleware.ts, actual middleware/auth.ts + rate-limit.ts | Fix file paths |
| CODE-016 | container-diagram.md | merchantMiddleware "extends auth", actually independent | Fix description |
| CODE-018 | deployment-architecture.md | JWT_SECRET "cwd hash", actual static string | Fix fallback desc |
| CODE-019 | flow-login-authentication.md | Demo email: amir@example.com, actual demo@example.test | Fix email |
| CODE-020 | flow-login-authentication.md | Demo calls POST /login, actual POST /demo-login (no creds) | Rewrite demo section |
| CODE-021 | container-diagram.md | Rate limit missing per-user limit (3 req) | Add dual limits |
| CODE-023 | ADR-012 vs deployment-arch | Blue/green contradiction | Make consistent |
| CODE-025 | database-design.md | middleware.ts:11, actual middleware/rate-limit.ts:11 | Fix path |
| CODE-026 | data-architecture.md | Rate limit cleanup "every check", actual every 100 checks | Fix frequency + path |
| CODE-027 | data-architecture.md | "6 tables" but lists 7 | Fix count |
| CODE-028 | Backend LLD correct, security-arch wrong on SameSite | Fix security-arch | |
| CODE-038 | flow-qr-payment.md | Merchant ID regex doesn't match seed data | Relax format spec |
| CODE-043 | flow-login-auth.md | Cross-refs list deprecated endpoints | Update to current |
| CONS-004 | Frontend vs backend LLD | SameSite contradiction | Fix frontend LLD |
| CONS-005 | Security vs backend LLD | SecureStore vs AsyncStorage | Fix security-arch |
| CONS-007 | ADR-012 vs deployment-arch | Health check: /api/health vs /v1/health | Standardize |
| CONS-008 | ADR-012 vs deployment-arch | Blue/green contradiction (dup of CODE-023) | Make consistent |
| CONS-009 | ADR-008 vs container-diagram | Rate limiting "in-memory", actual DB-backed | Fix ADR-008 |
| CONS-011 | data-architecture.md | "6 tables" header, 7 listed (dup of CODE-027) | Fix count |
| CONS-025 | Bank linking vs open banking | AISP consent: 180d, should be 90d per PSD2 | Use 90d (regulatory) |
| CONS-019 | flow-qr-payment.md | Fee "charged to merchant", user pays total | Clarify fee model |
| COMP-006 | DATABASE-SCHEMA.md | Missing otp_codes table reference | Document or remove dead code |
| COMP-008 | All docs | Feature flags: 8 flags, no mapping doc | Create feature-flags.md |
| COMP-009 | security-architecture.md | AML rules: 5 specific rules undocumented | Add detection rules |
| COMP-010 | flow-remittance.md | Missing /summary and /:id/receipt endpoints | Add to flow |
| COMP-012 | All docs | Middleware chain undocumented | Add request lifecycle |
| COMP-014 | flow-qr-payment.md | HMAC verification is optional, not mandatory | Clarify + security note |
| COMP-016 | All docs | Data retention cron undocumented | Add to data-lifecycle |
| COMP-020 | flow-remittance.md | PSD2 disclosure endpoint undocumented | Add /disclosure to sequence |
| CODE-033 | deployment-architecture.md | SERVICE_MODE "mock", actual "demo" | Fix value |
| CODE-034 | flow-login-auth-backend.md | Demo mode env: NEXT_PUBLIC..., actual DROP_MODE | Fix env var |
| CODE-045 | flow-login-auth.md vs backend | Frontend describes email/password as active | Update frontend LLD |
LOW Severity Findings (12)
| ID | File | Issue |
|---|---|---|
| CODE-030 | ADR-011 | Next.js 16 to 15 |
| CODE-031 | component-overview.md | Registration 4-step, actual BankID-only |
| CODE-032 | migration-strategy.md | Cross-ref path: ../lld/ should be ../hld/ |
| CODE-035 | audit-architecture.md | idx_audit_log_timestamp index doesn't exist |
| CODE-036 | security-architecture.md | bcrypt file ref (actually correct) |
| CODE-040 | container-diagram.md | "Offline-capable" contradicts component-overview "No offline" |
| CODE-041 | database-design.md | idx_tx_idempotency breaks naming convention |
| CONS-010 | component-overview vs system-context | Duplicate doc ID "HLD-001" |
Recommended Fix Priority
Batch 1: Global Find-Replace (resolves ~20 findings)
- "Next.js 16" to "Next.js 15" (all docs)
- "24h (web)" / "7d (mobile)" to "7d (all clients)" (all docs)
- "sameSite=strict" to "sameSite=Lax" (all docs)
- "middleware.ts" to correct paths (all docs)
Batch 2: Section Rewrites (resolves ~15 findings)
- Deployment architecture: mark AWS as planned, document Docker Compose current state
- Auth flow: remove email/password, document BankID-only + demo-login
- QR payment: fix amount units, fee model, HMAC optionality
- Registration: BankID auto-creation, not 4-step
Batch 3: Missing Documentation (resolves ~15 findings)
- Demo mode architecture (auth.ts, mode.ts, payments.ts branching)
- GDPR endpoints (user.ts: objection, rectification, restriction)
- Withdrawal flow (withdrawal.ts)
- Feature flag mapping (feature-flags.ts: 8 flags)
- Error handling chain (error-handler.ts, Sentry, alerts)
- AML monitoring rules and thresholds
- Data retention cron job
- PSD2 disclosure endpoint
- Middleware request lifecycle
Batch 4: Cross-Doc Consistency (resolves ~10 findings)
- Unify data classification taxonomy
- Fix ADR contradictions (blue/green, rate limiting, health check paths)
- Fix AISP consent period (180d to 90d per PSD2)
- Assign unique document IDs
Non-Doc Issues Found (for engineering backlog)
These are code issues discovered during documentation review:
| # | Issue | File | Severity |
|---|---|---|---|
| 1 | Build tools (python3, make, g++) in production Docker image | Dockerfile:82 | HIGH |
| 2 | merchant role = admin role (any merchant can access audit/screening/STR) | admin.ts:14 | HIGH |
| 3 | SEED_DEMO=true can enable demo data in production | db.ts:241 | HIGH |
| 4 | HMAC verification on QR payments is optional | transactions.ts:400 | MEDIUM |
| 5 | withdrawal_requests table created at runtime, not in schema | withdrawal.ts:34 | MEDIUM |
| 6 | No async reconciliation for transactions | transactions.ts | MEDIUM |
| 7 | Dead otp_codes cleanup code | cron.ts:84 | LOW |
| 8 | idx_tx_idempotency breaks naming convention | db.ts:190 | LOW |
Generated by drop-critics team: code-critic, consistency-critic, completeness-critic, validator