diff --git a/docs/superpowers/audits/2026-05-11-prod-readiness-audit.md b/docs/superpowers/audits/2026-05-11-prod-readiness-audit.md index d1d64f19..c2d670a2 100644 --- a/docs/superpowers/audits/2026-05-11-prod-readiness-audit.md +++ b/docs/superpowers/audits/2026-05-11-prod-readiness-audit.md @@ -117,6 +117,7 @@ Right border draws on full-width-stacked element instead of bottom separator. **Fix:** `border-b sm:border-r border-r-0`. **C3-C7. 5 tap-target violations below WCAG 44×44px minimum** + - C3: chevron expand button (`folder-tree-sidebar.tsx:125`) — 20×20px - C4: row expand chevron (`documents-hub.tsx:210-216`) — no sizing - C5: "view signing details" (`entity-folder-view.tsx:82-89`) — ~20px tall @@ -167,36 +168,43 @@ v2 distinguishes Decline (recipient refuses) from Reject (admin cancels). The sw Listed by audit domain. Each has a file:line ref in its source audit; I'll quote the highlights here for triage. ### Security + - **`storagePath` + `storageBucket` exposed via aggregated files API** (`files.ts:533-534`) — internal storage paths reach authenticated rep clients via `GET /api/v1/files?entityType=X`. Auditors flagged this from both Security and Integration angles. Sanitize at service layer. - **Missing `portId` on UPDATE in folder-move route** (`api/v1/documents/[id]/folder/route.ts:41-44`) — pre-flight read scopes by portId so no current exploit, but defense-in-depth gap that breaks if pre-flight is ever refactored. - **Signer emails exposed to all `documents.view` holders** — confirm with product whether read-only roles should see signatory email addresses or get them redacted. ### Database / Migration + - **`uniq_document_folders_entity` doesn't cover `entity_type = NULL`** — rows with NULL entity_type but non-NULL entity_id can duplicate. Closes when CHECK constraint is tightened (A5 above). - **Backfill transaction holds advisory lock across N `ensureEntityFolder` calls** — at 10k files the lock is held for minutes. Batch in chunks of 500. - **`CREATE INDEX` without `CONCURRENTLY`** in migration 0051 — blocks writes briefly. Quantify: short-duration on small tables, moderate on prod-sized. Split for zero-downtime if needed. ### Concurrency / Error Paths + - **Storage blob orphaned on DB-insert failure** in `handleDocumentCompleted` — `storage.put` before `db.insert(files)`. No janitor. Long-standing tradeoff; document explicitly. - **`ensureSystemRoots`/`ensureEntityFolder` outside backfill transaction** — folder rows persist if the wrapping tx rolls back. Idempotent so re-run heals. - **`syncEntityFolderName` 50-attempt cap with concurrent renames to same target** — silent log + stale folder name. Accepted divergence. ### Performance + - **N+1 grows with linked entities** — leasing company with 50 yachts = 110 queries per page load. Worst case (5 companies + 100 yachts) = 216. Acceptable for now; future optimization: single CTE with grouping. - **Count queries can collapse via window function** — `count(*) OVER ()` halves round-trip count at scale. - **Missing composite indexes `(port_id, client_id)` / `(port_id, company_id)` / `(port_id, yacht_id)` on `files`** — same for `documents`. Add before prod backfill at scale. - **`listDocuments` calls `listTree()` twice when `includeDescendants=true`** — pass already-fetched tree into `hydrateDocumentsWithDownloadUrl`. ### Data migration (importer) + - **System-root collision risk** — bucket folders named `Clients`/`Companies`/`Yachts` silently merge into auto-created system roots. Add a pre-flight check that warns when any top-level segment matches a system root name. ### Observability + - **Archive/restore hooks missing `portId` in log context** (`companies.service.ts:215`, `yachts.service.ts:193`) — clients has it; companies and yachts don't. - **Backfill CLI has no row-count telemetry** — only "Backfill complete" on success. Want files-processed / folders-created / FKs-propagated counts. - **No log on empty aggregated projection** — `assertEntityInPort` returning false produces a silent empty result. Log warn with `portId + entityType + entityId`. - **`handleDocumentCompleted` outer catch loses `portId`** (line 1197). ### UI/UX + - **Em-dash in `SigningDetailsDialog` description** (line 62) — user-facing copy. - **Em-dashes baked into aggregated group labels** (`FROM COMPANY — ACME CORP`) — rendered on every entity folder view. `files.ts:335`, `documents.service.ts:1877`. Replace with colon or slash. - **Mixed `Loading...` (ASCII) and `Loading…` (Unicode ellipsis)** across components. Normalize. @@ -204,6 +212,7 @@ Listed by audit domain. Each has a file:line ref in its source audit; I'll quote - **"view signing details" button too subtle** — inline-text in a tight muted cluster, blends into the date. Consider `