# Master backlog index **Single source of truth for everything outstanding.** Start here when asking "what's left to build/fix?". Items are grouped by source doc; each entry links back to the original spec for full context. Last updated: 2026-05-07 (after the audit-final-deferred sweep — partial archived indexes, document_sends interestId port-verify, custom-fields per-entity permission gate, recommender bool parsing, expense PDF cursor math, berth PDF silent-drop logging, YachtForm preset-owner + interest form member-company yacht filter + add-new shortcut, invoice detail typed). Many older items in §C and §F were already resolved by earlier fix-audit commit waves; the audit doc was stale. --- ## A. Documenso build (deferred for later) **Source:** [`docs/documenso-build-plan.md`](./documenso-build-plan.md) — full phase plan with locked decisions (Q1–Q10). **Tracker delta:** [`docs/admin-ux-backlog.md`](./admin-ux-backlog.md) — what landed in Phase 1. Phase 1 (EOI generate flow polish + APPROVER-as-CC + per-port settings + signing-URL fix) is **DONE** and committed. Remaining phases — explicitly back-burnered by the user on 2026-05-07: | Phase | Scope | Estimate | Notes | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Phase 2** | Webhook handler enhancement: cascading "your turn" emails, on-completion PDF distribution, token-based recipient matching, idempotency lock | ~3–4h | Schema columns already in place from Phase 1 (`document_signers.invited_at / opened_at / signing_token`, `documents.completion_cc_emails`). | | **Phase 3** | Custom doc upload-to-Documenso: `custom-document-upload.service.ts` + `POST /api/v1/interests/[id]/upload-for-signing` | ~6–8h | Depends on Phase 2 webhook UX in anger before locking the upload UX. | | **Phase 4** | Field placement UI: react-pdf + dnd-kit overlay + auto-detect anchor scanner via pdfjs `getTextContent` | ~10–14h | Largest piece. Plan locked in build-plan Phase 4 — regexes, anchors, type-to-bbox sizing all spelled out. Best done in a focused session with the user watching. | | **Phase 5** | Embedded signing URL emission verification: confirm website's `/sign//` page handles every signer-role × documentType combination; update `signerMessages` map; apply nginx CORS block from integration audit | ~1–2h | | | **Phase 6** | Polish: auto-send delay, audit-log additions, per-document customisation, document expiration, reminder rate-limit display, failed-webhook recovery UI | each ~2–3h | All deferred until Phases 1–4 ship. | | **Phase 7** | Project Director RBAC — UI binding for the developer-user fields. Add "Linked to CRM user" dropdown in `/admin/documenso/page.tsx`; auto-fill name/email; webhook handler matches against linked user's email for in-CRM signing-status updates. Schema + setting keys (`documenso_developer_user_id`, `documenso_approver_user_id`, `_label`) already in place from Phase 1. | ~1h | Smallest piece; could be picked off independently of Phase 2. | | **Risk #4** | v2 webhook payload audit against a live v2 instance (`payload.documentId` vs `payload.id`, `recipient.token` vs `recipient.recipientId`) before relying on Phase 2 cascading emails | ~1h | Needs a live v2 instance. | --- ## B. Custom-fields hardening (~ongoing, deferred) **Source:** [`docs/admin-ux-backlog.md`](./admin-ux-backlog.md) §7. Custom Settings page already shows the amber warning banner. Remediation work: - **Search index** — extend the GIN tsvector to include `customFieldValues` content - **Audit diff** — extend `diffEntity` to walk the `customFieldValues` blob - **Merge tokens** — add `{{custom.}}` handling at template-render time, plus surface them in the merge-tokens UI --- ## C. Audit-final deferred items **Source:** [`docs/audit-final-deferred.md`](./audit-final-deferred.md) — pre-merge + post-merge audit findings explicitly carried over. The 2026-05-07 backlog sweep landed every small/concrete item. Remaining entries are deferred because they need design decisions, live external instances, or cross-cutting refactors: ### Deferred — needs design or larger refactor - **Storage proxy token does not bind to port_id** — `src/lib/storage/filesystem.ts:73-84`. Adding a `p` (portId) claim is mechanical; the meaningful security gain requires the proxy verifier to look up the file's owning row + assert `owner.portId === payload.p`. That requires either a routing prefix in the key (currently `${portSlug}/...` already, so a prefix check is plausible) or a per-table lookup across all owners. Decide which approach before implementing — current state ships with `validateStorageKey` + per-issuer port scoping, so this is defense-in-depth rather than an open hole. - **Documenso webhook does not enforce port_id on document lookups** — `src/app/api/webhooks/documenso/route.ts:96-148`. Adding port scope requires either including the originating Documenso instance/team id in the lookup (Documenso doesn't surface that on the webhook payload today) OR proving `documents(documenso_id)` is globally unique with a DB constraint and a backfill check. Pick the strategy with the audit doc open. - **Webhook dedup vs per-recipient signed events** — `src/app/api/webhooks/documenso/route.ts:103-110`. Replacing the body-hash dedup with a `(documensoDocumentId, recipientEmail, eventType)` composite unique requires schema column for recipient_email on `documentEvents`. Right place to do this is alongside Documenso Phase 2 (webhook handler enhancement) since they touch the same code. - **v2 voidDocument endpoint shape verification** — `src/lib/services/documenso-client.ts:450-466`. Needs a live Documenso 2.x instance to confirm `POST /api/v2/envelope/delete` body shape. Bundle with Documenso Phase 5. - **Public POST routes bypass service layer** — `src/app/api/public/{interests,website-inquiries,residential-inquiries}/route.ts`. Multi-route refactor extracting a shared `publicInterestService.create(...)`. Worth doing but big enough to deserve its own session. - **Inconsistent response shapes** — most endpoints return `{ data: ... }`, but `notifications/[notificationId]` returns `{ success: true }`, `website-inquiries` returns `{ id, deduped }`. Codebase-wide migration; document a convention in CLAUDE.md first. - **`systemSettings` PK / unique-index drift** — `src/lib/db/schema/system.ts:119-133`. Schema declares `uniqueIndex` on `(key, port_id)`, migration uses `key` as PK. `port_id` is nullable so `(key, port_id)` cannot serve as a PK with default NULLs-not-equal semantics. Reconcile by either making `portId` non-null with a sentinel ("**global**") and declaring composite PK, OR by dropping the schema-level unique index and using partial unique indexes for global vs per-port. Either path is a data migration. ### Done in 2026-05-07 sweep (commits in this session) - ✅ Partial archived indexes (migration 0046) — `clients`, `interests`, `yachts`, `residential_clients`, `residential_interests` - ✅ `document_sends` interestId port-verification helper - ✅ Custom-fields per-entity permission gate (replaces hardcoded `clients.view/edit`) - ✅ EOI Berth Range warn log (was already in place) - ✅ v1 `placeFields` retry with backoff (was already in place) - ✅ S3 bucket-exists check at boot (was already in place) - ✅ Filesystem dev HMAC fallback warn (was already in place) - ✅ Storage cache fingerprint documentation comment - ✅ AI worker cost ledger writes (was already in place) - ✅ Logger redact paths covering headers, encrypted blobs, two-level nesting (was already in place) - ✅ `loadRecommenderSettings` accepts string `"true"`/`"false"` JSONB booleans - ✅ `renderReceiptHeader` cursor math anchored to captured `baseY` - ✅ Berth PDF apply: silent-drop logging for non-finite numeric coercions - ✅ Saved-views: confirmed by-design owner-only (existing inline doc) - ✅ Alerts ack/dismiss: confirmed by-design port-wide (service correctly bounded) - ✅ Storage admin migration toasts (already in place) - ✅ Invoice send/payment toasts + permission gates (already in place) - ✅ Admin user list edit + remove gates (added remove gate) - ✅ Email threads list skeleton + empty state (already in place) - ✅ Scan page error state for OCR failures (already in place) - ✅ Invoice detail typed (replaced `any` with `InvoiceDetailData` interface) - ✅ All FK indexes called out in audit doc (already in place — audit was stale) - ✅ `documentSends.sentByUserId` FK (already had `.references(...)`) ### Still open — small enough to bundle next time - **`berths.current_pdf_version_id` lacks Drizzle FK** — `src/lib/db/schema/berths.ts:83`. The in-line comment fully documents why (circular FK between `berths` ↔ `berth_pdf_versions` makes column-level `.references()` infeasible). FK is enforced via migration 0030. Treat as documented limitation; revisit if Drizzle adds deferred-FK support. - **`req.json()` without `parseBody` helper** — admin custom-fields routes use `await req.json(); schema.parse(body)` directly. Migrate for uniform 400 error shapes when the surface area calms down. --- ## D. Inline TODOs in code (2 remaining) | File:line | Note | Status | | ------------------------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------ | | ~~`client-yachts-tab.tsx:93`~~ | YachtForm preset owner prop | ✅ landed 2026-05-07 (`initialOwner` prop) | | ~~`interest-form.tsx:329`~~ | Include company-owned yachts where client is a member | ✅ landed 2026-05-07 (`yachtOwnerFilter` array filter) | | ~~`interest-form.tsx:330`~~ | "Add new yacht" inline shortcut | ✅ landed 2026-05-07 (Plus button + YachtForm sheet) | | [`src/lib/queue/scheduler.ts:44`](../src/lib/queue/scheduler.ts#L44) | Per-user reminder schedule configurable from `user_settings` | Open — needs `user_settings` UI surface | | [`src/lib/queue/workers/import.ts:13`](../src/lib/queue/workers/import.ts#L13) | Import job handlers — worker is a stub | Open — entire feature surface | --- ## E. Hidden / stubbed UI tabs - **Company Documents tab** — `src/components/companies/company-tabs.tsx:229`. Hidden until `/api/v1/files` accepts a `companyId` filter (schema supports it, validator doesn't). - **Berth Waiting List + Maintenance Log tabs** — `src/components/berths/berth-tabs.tsx:346`. Removed entirely; revisit if/when product asks. - **Interest Contract / Reservation tabs** — `src/components/interests/interest-{contract,reservation}-tab.tsx`. Render a "coming soon" friendly card; the real flow is gated on Documenso Phases 2–6. --- ## F. Historical audit docs (mostly resolved) These dossiers drove the audit-fix commit waves on 2026-05-05/06. Items not surfaced in §C above were resolved via the `fix(audit): …` commits (`588f8bc`, `94331bd`, `a8c6c07`, `5fc68a5`, `da7ede7`, `c5b41ca`, `b4fb3b2`, `0f648a9`, `c312cd3`, `0a5f085`, `1a87f28`, `f3143d7`, `05babe5`). Keep for historical context: - [`audit-comprehensive-2026-05-05.md`](./audit-comprehensive-2026-05-05.md) — pre-merge audit (1 CRIT + 18 HIGH at start) - [`audit-comprehensive-2026-05-06.md`](./audit-comprehensive-2026-05-06.md) — post-merge audit (1 CRIT + 7 HIGH + 10 MED + 7 LOW) - [`audit-frontend-2026-05-06.md`](./audit-frontend-2026-05-06.md) — frontend-only sweep - [`audit-missing-features-2026-05-06.md`](./audit-missing-features-2026-05-06.md) — admin-promised-but-unwired features (V1–V12) - [`audit-permissions-2026-05-06.md`](./audit-permissions-2026-05-06.md) — permission-gate gaps - [`audit-reliability-2026-05-06.md`](./audit-reliability-2026-05-06.md) — transactional integrity / TOCTOU - [`berth-feature-handoff-prompt.md`](./berth-feature-handoff-prompt.md) — berth recommender handoff (shipped, kept as reference) - [`berth-recommender-and-pdf-plan.md`](./berth-recommender-and-pdf-plan.md) — berth recommender + per-berth PDF plan (Phases 0–8 shipped) - [`documenso-integration-audit.md`](./documenso-integration-audit.md) — Documenso integration spec (drives §A) - [`website-refactor.md`](./website-refactor.md) — public website cutover plan