# Monetarie PIX — Phase A Deep Codebase Audit: Consolidated Findings

**Date:** 2026-02-13
**Agents:** 10 parallel audit agents
**Status:** ALL COMPLETE

---

## Executive Summary

| Agent | Domain | CRITICAL | HIGH | MEDIUM | LOW | Total |
|-------|--------|----------|------|--------|-----|-------|
| 1 | Backend Architecture | 5 | 2 | 4 | 0 | 11 |
| 2 | Database & Migrations | 5 | 3 | 5 | 2 | 15 |
| 3 | API Surface | 3 | 4 | 3 | 3 | 13 |
| 4 | Auth & Security | 3 | 6 | 5 | 4 | 18 |
| 5 | NATS & Workers | 2 | 5 | 4 | 0 | 11 |
| 6 | Frontend Admin | 3 | 4 | 4 | 3 | 14 |
| 7 | Frontend User | 1 | 0 | 0 | 0 | 1 |
| 8 | Config & Environment | 11 | 19 | 12 | 0 | 42 |
| 9 | Dependencies & Build | 1 | 3 | 5 | 2 | 11 |
| 10 | Cross-Cutting Concerns | 5 | 5 | 6 | 13 | 29 |
| **TOTAL** | | **39** | **51** | **48** | **27** | **165** |

**Go/No-Go:** NOT READY for fresh client deployment. 39 critical findings must be resolved.

---

## Top-10 Blocking Issues (Must Fix)

### 1. REMOVE User Frontend (Agent 7) — CRITICAL
- **Recommendation:** REMOVE `frontend/user/` entirely
- 27 of 30 routes are consumer-facing (send PIX, manage personal keys, transaction history)
- End-user features belong in Core Banking IB, not PIX infrastructure platform
- PIX is back-office infrastructure for financial institution operators
- Saves: 3rd Docker image, duplicate auth system, mixed API concerns
- **Effort:** S (delete directory, remove K8s deployment, clean CI/CD)

### 2. Fresh DB Deployment WILL FAIL (Agent 2) — CRITICAL
- Messages table not partitioned (`PARTITION BY RANGE` missing from migration 7)
- `activity_log` and `login_history` base tables not created as partitioned
- Partition child tables missing PKs (migration 25)
- Composite PK `(id, operation_time)` doesn't match Ecto single PK
- Seed column names mismatch (`participant_type` vs `participation_type`)
- **Effort:** L (requires migration consolidation/rewrite for fresh deploy)

### 3. SQL Injection in PartitionManager (Agent 4) — CRITICAL
- **File:** `shared/lib/shared/partition_manager.ex:111-142`
- String interpolation of schema/table/partition names into SQL
- **Fix:** Validate identifiers against whitelist; parameterize date values
- **Effort:** S

### 4. Atom DoS — String.to_atom() on untrusted input (Agent 4) — CRITICAL
- `shared/lib/shared/bacen/simulator.ex:210` — config keys from DB
- `shared/lib/shared/validation/xsd_validator.ex:254` — field names
- `settlement_service_web/controllers/message_controller.ex:587` — user params
- **Fix:** Replace with `String.to_existing_atom()` + whitelist
- **Effort:** S

### 5. Insecure SSO Issuer Validation (Agent 4) — CRITICAL
- **File:** `settlement_service_web/plugs/sso_auth.ex:34`
- `or` logic means `iss: "monetarie"` bypasses `target_system` check
- Core tokens without `target_system: "pix"` gain unauthorized PIX access
- **Fix:** Change `or` to proper conditional: accept Core tokens explicitly
- **Effort:** S

### 6. 11 Hardcoded GCP Values (Agent 8) — CRITICAL
- Redis IP `10.6.190.108` in `shared/lib/shared/redis/connection.ex`
- NATS IP `10.10.40.5` in `deploy/backend.yaml`
- Redis IP `10.140.240.4` in `deploy/backend.yaml`
- GCP registry `southamerica-east1-docker.pkg.dev/fluxiqbr/fluxiq/` in cloudbuild.yaml
- SSO URL `https://api-dev.fluxiq.com.br` in `frontend/admin/src/services/sso.ts`
- Cloud-agnostic readiness: **25/100**
- **Fix:** Extract all to env vars / runtime config
- **Effort:** M

### 7. 8 GenServers Missing catch-all handle_info (Agent 1) — CRITICAL
- BaseWorker, ErrorLookup, CertificatePool, JetStream, HealthChecker (CRITICAL)
- QueueMonitor, Settlement NATS Connection, SPI NATS Connection (MEDIUM)
- Unexpected messages crash these processes
- **Fix:** Add `def handle_info(_msg, state), do: {:noreply, state}` to each
- **Effort:** S

### 8. 13 Stub Controllers Returning Fake Data (Agent 3) — CRITICAL
- BatchController (6 actions), IntradayReportController (3 actions)
- OwnershipController (4 actions) — all return placeholder data
- Production endpoints that silently return empty/mock responses
- **Fix:** Implement real logic or return 501 Not Implemented
- **Effort:** L

### 9. Duplicate NATS Stream Definitions (Agent 5) — CRITICAL
- 6 streams defined in both `Shared.Nats.JetStream` AND individual service connections
- Stream reconciliation conflicts on multi-pod deployments
- **Fix:** Consolidate all stream definitions into Shared.Nats.JetStream
- **Effort:** M

### 10. RSA-OAEP Uses SHA-1 (Agent 6) — CRITICAL
- **File:** `frontend/admin/src/services/auth.ts:42`
- Admin login encryption uses SHA-1 hash instead of SHA-256
- **Fix:** Change to SHA-256 in Web Crypto API call
- **Effort:** S

---

## Agent 1: Backend Architecture

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A1-01 | CRITICAL | Missing catch-all handle_info in BaseWorker | shared/lib/shared/workers/base_worker.ex | S |
| A1-02 | CRITICAL | Missing catch-all handle_info in ErrorLookup | shared/lib/shared/bacen/error_lookup.ex | S |
| A1-03 | CRITICAL | Missing catch-all handle_info in CertificatePool | shared/lib/shared/crypto/certificate_pool.ex | S |
| A1-04 | CRITICAL | Missing catch-all handle_info in JetStream | shared/lib/shared/nats/jetstream.ex | S |
| A1-05 | CRITICAL | Missing catch-all handle_info in HealthChecker | settlement_service/monitoring/health_checker.ex | S |
| A1-06 | HIGH | Dead code: Shared.Schemas.Transaction (unused) | shared/lib/shared/schemas/transaction.ex | S |
| A1-07 | HIGH | Dead code: SpiService.Operations (unused) | spi_service/lib/spi_service/operations.ex | S |
| A1-08 | MEDIUM | Unnecessary delegate: DictService.Infractions.InfractionReport | dict_service/lib/dict_service/infractions/ | S |
| A1-09 | MEDIUM | Missing catch-all in QueueMonitor | settlement_service/monitoring/queue_monitor.ex | S |
| A1-10 | MEDIUM | Missing catch-all in Settlement NATS Connection | settlement_service/nats/connection.ex | S |
| A1-11 | MEDIUM | Missing catch-all in SPI NATS Connection | spi_service/nats/connection.ex | S |

---

## Agent 2: Database & Migrations

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A2-01 | CRITICAL | Messages table not partitioned (missing PARTITION BY) | migration 20260203100004 | L |
| A2-02 | CRITICAL | Partition child tables missing PKs | migration 20260210000001 | M |
| A2-03 | CRITICAL | Base partitioned tables (activity_log, login_history) not created as partitioned | migration 20260210000001 | M |
| A2-04 | CRITICAL | User ID type mismatch (binary_id in schema vs bigint in DB) | AuditLog schema | S |
| A2-05 | CRITICAL | Messages composite PK (id, operation_time) vs Ecto single PK | migration 20260203100004 + Transaction schema | M |
| A2-06 | HIGH | Seed column name mismatch (participant_type vs participation_type) | seeds.exs | S |
| A2-07 | HIGH | Seed institution_id references invalid IDs | seeds.exs | S |
| A2-08 | HIGH | Duplicate institution tables (monetarie_auth + monetarie_dict) | migrations 20260203100002/3 | M |
| A2-09 | MEDIUM | Claim data references non-existent ISPBs | seeds.exs | S |
| A2-10 | MEDIUM | Timestamp type inconsistency (utc_datetime vs utc_datetime_usec) | Multiple migrations | M |
| A2-11 | MEDIUM | Missing partition base table definition | migration 20260203100002 | M |
| A2-12 | MEDIUM | Seed data column mismatches for participants | seeds.exs | S |
| A2-13 | MEDIUM | Schema does not exist for migration 27 to partition | migrate27.exs | S |
| A2-14 | LOW | No rollback functions for partition migrations | migration 20260213000002 | S |
| A2-15 | LOW | Index names not schema-prefixed | migration 20260203000001 | S |

---

## Agent 3: API Surface

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A3-01 | CRITICAL | 13 stub controllers returning fake/empty data | BatchController, IntradayReportController, OwnershipController | L |
| A3-02 | CRITICAL | Duplicate route definitions (/api/v1/keys appears twice) | dict_service_web/router.ex:121-131 | S |
| A3-03 | CRITICAL | FallbackController reports wrong source ("SPI" instead of "Settlement") | settlement_service_web/fallback_controller.ex:18,23 | S |
| A3-04 | HIGH | 29 controllers missing action_fallback (inconsistent error handling) | Multiple controllers | M |
| A3-05 | HIGH | Inconsistent response serialization (3 different formats) | All controllers | L |
| A3-06 | HIGH | snake_case vs camelCase inconsistency across API | All controllers | L |
| A3-07 | HIGH | ParticipantController.get_stats returns all zeros (placeholder) | dict_service_web/participant_controller.ex:75-105 | M |
| A3-08 | MEDIUM | Missing RBAC enforcement on some gateway controllers | settlement_service_web/controllers/gateway/ | M |
| A3-09 | MEDIUM | Missing PUT operations for several resources | Multiple controllers | M |
| A3-10 | MEDIUM | Proxy controllers return 503 for all errors (no distinction) | Gateway proxy controllers | M |
| A3-11 | LOW | Inconsistent pagination parameter names (page_size/pageSize/limit/per_page) | All controllers | M |
| A3-12 | LOW | Health endpoint paths inconsistent across services | All 3 services | S |
| A3-13 | LOW | Unused/dead duplicate routes | dict_service_web/router.ex:127-132 | S |

---

## Agent 4: Auth & Security

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A4-01 | CRITICAL | SQL injection in PartitionManager | shared/lib/shared/partition_manager.ex:111-142 | S |
| A4-02 | CRITICAL | Atom DoS (3 locations: simulator, xsd_validator, message_controller) | Multiple | S |
| A4-03 | CRITICAL | Insecure SSO issuer validation (or logic bypass) | settlement_service_web/plugs/sso_auth.ex:34 | S |
| A4-04 | HIGH | Fallback RSA keys generated in production | shared/lib/shared/auth/rsa_crypto.ex:92-118 | S |
| A4-05 | HIGH | Missing RBAC on SSO users (no local user validation) | shared/lib/shared/plugs/require_permission.ex | M |
| A4-06 | HIGH | Login rate limit bypass via X-Forwarded-For spoofing | settlement_service_web/plugs/rate_limit.ex | M |
| A4-07 | HIGH | Insufficient token expiry (24h, no refresh) | dict_service_web/auth_controller.ex:18 | M |
| A4-08 | HIGH | CSRF cookie not HttpOnly (by design, double-submit pattern) | dict_service_web/auth_controller.ex:580 | — |
| A4-09 | HIGH | Idempotency TOCTOU (partially fixed with SET NX) | shared/lib/shared/plugs/idempotency.ex | S |
| A4-10 | MEDIUM | Hardcoded dev credentials in config/dev.exs | config/dev.exs | S |
| A4-11 | MEDIUM | String.to_existing_atom still risky in error formatting | tracking_graph_controller.ex:86 | S |
| A4-12 | MEDIUM | Missing header validation on X-Participant-ISPB | rate_limit.ex:241 | S |
| A4-13 | MEDIUM | Insufficient security event logging | Multiple auth controllers | M |
| A4-14 | MEDIUM | ReDoS potential in CSRF regex | tracking_graph_controller.ex:85 | S |
| A4-15 | LOW | Password expiry field not enforced on creation | auth_controller.ex:405-411 | S |
| A4-16 | LOW | Error message leaks (minimal) | Multiple | S |
| A4-17 | LOW | Missing security headers (CSP, X-Frame-Options, HSTS) | Router pipelines | S |
| A4-18 | LOW | JWT algorithm not validated in custom implementation | shared/lib/shared/auth/mfa.ex:153 | S |

---

## Agent 5: NATS & Workers

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A5-01 | CRITICAL | Duplicate stream definitions across services | jetstream.ex + 3 connection modules | M |
| A5-02 | CRITICAL | No message payload validation/schema enforcement | BaseWorker + all workers | L |
| A5-03 | HIGH | Stream subject overlap (MONETARIE_SETTLEMENT vs NETTING) | jetstream.ex + SettlementService NATS | M |
| A5-04 | HIGH | Graceful shutdown incomplete (Task.async_stream not tracked) | base_worker.ex:265-314 | M |
| A5-05 | HIGH | Consumer max_ack_pending=100 too low for 5000 TPS | jetstream.ex:273-284 | S |
| A5-06 | HIGH | DLQ subject format malformed (nested monetarie.dlq.monetarie.spi...) | base_worker.ex:509 | S |
| A5-07 | HIGH | Heartbeat doesn't detect stalled workers | base_worker.ex:247-256 | S |
| A5-08 | MEDIUM | No size validation in NatsPublisher | dict_service/events/nats_publisher.ex | S |
| A5-09 | MEDIUM | NATS connection retry: no exponential backoff | All 3 connection modules | S |
| A5-10 | MEDIUM | DLQ payloads lose original headers | base_worker.ex:493-505 | S |
| A5-11 | MEDIUM | Worker telemetry incomplete (no failure events) | base_worker.ex:171-240 | S |

---

## Agent 6: Frontend Admin

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A6-01 | CRITICAL | RSA-OAEP hash uses SHA-1 (should be SHA-256) | frontend/admin/src/services/auth.ts:42 | S |
| A6-02 | CRITICAL | Missing method export in auth store | frontend/admin/src/stores/auth.ts | S |
| A6-03 | CRITICAL | WebSocket reconnection has no backoff (hangs on disconnect) | frontend/admin/src/stores/monitoring.ts:99-110 | S |
| A6-04 | HIGH | i18n pt-BR missing diacritics on several keys | frontend/admin/src/locales/pt-BR.json | S |
| A6-05 | HIGH | No request body size limit on API calls | frontend/admin/src/services/api.ts | S |
| A6-06 | HIGH | Status labels not shared (duplicated across views) | Multiple view files | M |
| A6-07 | HIGH | Chart components lack TypeScript generics | frontend/admin/src/components/charts/ | S |
| A6-08 | MEDIUM | Timezone formatting not global (scattered utility calls) | Multiple views | M |
| A6-09 | MEDIUM | Error handling inconsistency across views | Multiple views | M |
| A6-10 | MEDIUM | Notification badge missing for NATS/system alerts | frontend/admin/src/App.vue | S |
| A6-11 | MEDIUM | Env var validation missing at build time | frontend/admin/vite.config.ts | S |
| A6-12 | LOW | Unused i18n keys across locales | All 5 locale files | S |
| A6-13 | LOW | Missing tests (0 test files found) | frontend/admin/ | L |
| A6-14 | LOW | No error boundary component | frontend/admin/src/ | M |

---

## Agent 7: Frontend User — CRITICAL EVALUATION

| ID | Severity | Finding | Recommendation | Effort |
|----|----------|---------|----------------|--------|
| A7-01 | CRITICAL | **REMOVE User Frontend entirely** | Delete `frontend/user/`, remove K8s deployment, clean CI/CD | S |

**Rationale:** 27/30 routes are consumer-facing end-user features (send PIX, manage personal keys, personal transaction history). All 10 Pinia stores manage personal data. PIX is a back-office infrastructure platform for financial institution operators — end-user payment features belong in Core Banking Internet Banking module.

**What to keep (move to Admin with RBAC):**
- Institution key management (admin function) → merge into Admin
- Transaction monitoring (operator function) → already in Admin

---

## Agent 8: Config & Environment

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A8-01 | CRITICAL | Hardcoded GCP Redis IP (10.6.190.108) | shared/lib/shared/redis/connection.ex:149 | S |
| A8-02 | CRITICAL | Hardcoded GCP project/registry in cloudbuild.yaml | backend/cloudbuild.yaml | S |
| A8-03 | CRITICAL | Hardcoded NATS cluster IP (10.10.40.5) | deploy/backend.yaml:86 | S |
| A8-04 | CRITICAL | Hardcoded Memorystore IP (10.140.240.4) | deploy/backend.yaml:96 | S |
| A8-05 | CRITICAL | Hardcoded SSO URL in frontend | frontend/admin/src/services/sso.ts:9-11 | S |
| A8-06 | CRITICAL | Hardcoded K8s namespace/cluster names | deploy/*.yaml | S |
| A8-07 | CRITICAL | Hardcoded Ingress hostnames | deploy/backend.yaml, admin.yaml | S |
| A8-08 | CRITICAL | Hardcoded BACEN API endpoints | shared/lib/shared/bacen/client.ex | S |
| A8-09 | CRITICAL | Hardcoded GCP network CIDRs in NetworkPolicy | deploy/network-policy.yaml:199-219 | S |
| A8-10 | CRITICAL | Hardcoded CORS origins | Router/endpoint configs | S |
| A8-11 | CRITICAL | Missing Redis auth/TLS config | redis/connection.ex | S |
| A8-12 | HIGH | Incomplete env var documentation | No central reference file | M |
| A8-13 | HIGH | Unpinned Docker base images | backend/Dockerfile | S |
| A8-14 | HIGH | Missing user portal Dockerfile (if kept) | frontend/user/ | S |
| A8-15 | HIGH | Rate limit bypass default still risky | rate_limit.ex config | S |
| A8-16 | HIGH | K8s secrets without encryption at rest | deploy/*.yaml | M |
| A8-17 | HIGH | Cloud SQL private IP with no fallback | deploy/backend.yaml | S |
| A8-18 | HIGH | Nginx config not parameterizable | frontend/admin/nginx.conf | S |
| A8-19 | HIGH | No Vite env var documentation | frontend/admin/ | S |
| A8-20 | HIGH | No Helm charts or Kustomize overlays | deploy/ | L |
| A8-21 | HIGH | No cloud abstraction layer | All service configs | L |
| A8-22 | HIGH | Certificate paths not documented | shared/lib/shared/crypto/ | S |
| A8-23 | HIGH | Backend Dockerfile uses Debian (should use Alpine) | backend/Dockerfile | M |
| A8-24 | HIGH | Health check endpoint inconsistency | All 3 services | S |
| A8-25 | HIGH | NATS config references wrong namespace | deploy/backend.yaml | S |
| A8-26 | HIGH | No init containers for DB migration | deploy/backend.yaml | M |
| A8-27 | HIGH | No PVC for audit log cold storage | deploy/ | M |
| A8-28 | HIGH | Resource limits inconsistency across pods | deploy/*.yaml | S |
| A8-29 | HIGH | Rate limit configuration not documented | backend/config/ | S |
| A8-30 | HIGH | Image registry assumes GCP Artifact Registry | cloudbuild.yaml + deploy/*.yaml | M |
| A8-31+ | MEDIUM | 12 additional medium-priority config issues | Various | — |

---

## Agent 9: Dependencies & Build

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A9-01 | CRITICAL | Missing .dockerignore files (all build contexts) | backend/, frontend/admin/, frontend/user/ | S |
| A9-02 | HIGH | Backend Dockerfile layer caching inefficient | backend/Dockerfile | M |
| A9-03 | HIGH | Postgrex version ">= 0.0.0" (unpinned) | backend/mix.exs | S |
| A9-04 | HIGH | User portal Tailwind version mismatch | frontend/user/package.json | S |
| A9-05 | MEDIUM | --legacy-peer-deps flag in npm install | frontend/admin/Dockerfile | S |
| A9-06 | MEDIUM | SPI service has 4 unused deps | spi_service/mix.exs | S |
| A9-07 | MEDIUM | Missing .tool-versions / .mise.toml for Elixir version | backend/ | S |
| A9-08 | MEDIUM | Node.js version inconsistency between frontends | frontend/admin/ vs frontend/user/ | S |
| A9-09 | MEDIUM | User portal nginx config inline (not parameterized) | frontend/user/nginx.conf | S |
| A9-10 | LOW | Floki dep unused | backend/mix.exs | S |
| A9-11 | LOW | Bandit version range too wide | backend/mix.exs | S |

---

## Agent 10: Cross-Cutting Concerns

| ID | Severity | Finding | File | Effort |
|----|----------|---------|------|--------|
| A10-01 | CRITICAL | Frontend date/time timezone bugs (UTC midnight → wrong day in Brazil) | Multiple frontend views | S |
| A10-02 | CRITICAL | Silent Postgrex.Error rescues swallow DB errors | Multiple controllers | M |
| A10-03 | CRITICAL | Task.start without error handling (fire-and-forget) | Audit logging, BACEN calls | M |
| A10-04 | CRITICAL | No structured logging format (plain text in production) | All backend apps | M |
| A10-05 | CRITICAL | Missing error code catalog (no centralized reference) | Entire codebase | L |
| A10-06 | HIGH | NaiveDateTime mixing with DateTime | Multiple schemas/controllers | M |
| A10-07 | HIGH | Telemetry gaps (no custom metrics for business events) | shared/lib/shared/telemetry.ex | M |
| A10-08 | HIGH | i18n: missing translations in zh-CN and fr locales | frontend/admin/src/locales/ | M |
| A10-09 | HIGH | Code style: no .formatter.exs in umbrella root | backend/ | S |
| A10-10 | HIGH | Inconsistent module naming (aliased vs full paths) | Multiple modules | M |
| A10-11 | MEDIUM | Logger.info used for errors in some rescue blocks | Multiple controllers | S |
| A10-12 | MEDIUM | No code documentation (missing @doc on public functions) | ~60% of public functions | L |
| A10-13 | MEDIUM | Telemetry: no distributed tracing correlation in logs | Backend apps | M |
| A10-14 | MEDIUM | Error atoms inconsistent (mixed :error, :not_found, custom) | Multiple modules | M |
| A10-15 | MEDIUM | No code style documentation (CONTRIBUTING.md) | Repository root | S |
| A10-16 | MEDIUM | i18n locale fallback not configured | frontend/admin/src/i18n/ | S |
| A10-17-29 | LOW | 13 additional documentation/style items | Various | — |

---

## Fix Priority Matrix

### Immediate (Before Any Client Deployment)

| Priority | Finding IDs | Description | Effort |
|----------|-------------|-------------|--------|
| P0 | A7-01 | Remove User Frontend | S |
| P0 | A4-01, A4-02, A4-03 | Security: SQL injection, Atom DoS, SSO bypass | S |
| P0 | A1-01 to A1-05 | GenServer catch-all handle_info (5 modules) | S |
| P0 | A6-01 | RSA SHA-1 → SHA-256 in admin auth | S |
| P0 | A2-01 to A2-05 | Migration/schema fixes for fresh DB deploy | L |
| P0 | A8-01 to A8-11 | Extract hardcoded GCP values to env vars | M |

### Sprint 1 (Week 1-2)

| Priority | Finding IDs | Description | Effort |
|----------|-------------|-------------|--------|
| P1 | A5-01, A5-02 | Consolidate NATS streams, add message validation | M |
| P1 | A3-01, A3-02, A3-03 | Fix stubs, duplicate routes, fallback source | M |
| P1 | A4-04 to A4-07 | RSA fallback, RBAC SSO, rate limit, token expiry | M |
| P1 | A9-01 | Add .dockerignore files | S |
| P1 | A1-06, A1-07 | Remove dead code modules | S |

### Sprint 2 (Week 3-4)

| Priority | Finding IDs | Description | Effort |
|----------|-------------|-------------|--------|
| P2 | A3-04 to A3-06 | Standardize error handling, serialization | L |
| P2 | A5-03 to A5-07 | NATS: subject overlap, shutdown, DLQ format | M |
| P2 | A8-20, A8-21 | Helm charts, cloud abstraction | L |
| P2 | A10-01 to A10-05 | Cross-cutting: timezone, logging, error catalog | M |

### Backlog

| Priority | Finding IDs | Description | Effort |
|----------|-------------|-------------|--------|
| P3 | A6-04 to A6-14 | Frontend admin improvements | M |
| P3 | A8-12 to A8-30 | Config/env documentation and hardening | M |
| P3 | A10-06 to A10-29 | Cross-cutting improvements | L |

---

## Cloud-Agnostic Readiness Score: 25/100

**Blockers for multi-cloud deployment:**
- 11 hardcoded GCP IPs/URLs in code and configs
- No Helm charts or Kustomize overlays
- cloudbuild.yaml is GCP-specific (no generic CI/CD)
- Docker images reference GCP Artifact Registry
- NetworkPolicy uses GCP-specific CIDRs
- No Terraform modules for any cloud provider
- No on-premises deployment scripts

---

## Next Steps

1. **Phase B, Stream 1:** Fix all P0 findings (code fixes)
2. **Phase B, Stream 2:** Create cloud-agnostic deployment artifacts (Helm, Docker Compose, Terraform, on-prem scripts)
3. **Phase B, Stream 3:** VitePress implementation guide (PT-BR, EN-US, ZH-CN)
