diff --git a/docs/superpowers/audits/2026-05-21-remaining-plan.md b/docs/superpowers/audits/2026-05-21-remaining-plan.md new file mode 100644 index 00000000..5c767e4b --- /dev/null +++ b/docs/superpowers/audits/2026-05-21-remaining-plan.md @@ -0,0 +1,221 @@ +# Remaining UAT Master Doc — Work Plan + +> **Source:** `alpha-uat-master.md` (Bucket 1-4) as of commit `d879188`. Survey done 2026-05-21 after the PDF report exporter ship. +> +> **Status:** scaffold for sequential execution. Each item has a scope summary, file pointers (copied from the source entry where helpful), effort estimate, and explicit ordering notes (blocks-on / pairs-with). Items are grouped so logically-related work lands as one PR rather than scattered. + +## How to use this doc + +- Items are in **suggested execution order** (top → bottom). Order optimises for (a) unblocking other items, (b) low-cost-high-impact wins first, (c) defer-until-design large features to the end. +- Each item is one of: + - **Q** — quick fix (< 30 min) + - **M** — medium (30 min – 2 h) + - **L** — large (2 h+) + - **DEFERRED** — captured but blocked / waiting on external decision +- We work top to bottom. When an item lands, annotate it in `alpha-uat-master.md` with the SHIPPED-in-commit line AND tick it off here. + +--- + +## Group A — Tiny copy / UI fixes (batch as one PR, ~1 h total) + +These are all <15 min each. Bundle so the commit history doesn't sprawl. + +1. **[Q] Admin Documenso settings: surface env-fallback state pills** — _src/app/(dashboard)/[portSlug]/admin/documenso/page.tsx_. Pattern from `203f543` (env-fallback tooltip on password fields) needs to be applied to all Documenso settings fields. Show `Using env fallback` / `Per-port override active` pill next to each field. ~30 min. +2. **[Q] WatchersCard empty-state padding** — small CSS fix, add `pb-2` or `pb-3` to the empty state. ~5 min. +3. **[Q] EOI empty state: add "Mark as signed without file" button (parity with Reservation + Contract tabs)** — _src/components/interests/interest-eoi-tab.tsx_ — copy the existing button from the reservation/contract tabs that fires `markStageSigned` without requiring a PDF upload. ~10 min. +4. **[Q] `/invoices/upload-receipts` guide: copy rewrite** — terse, professional, in the luxury-CRM voice. ~10 min. +5. **[Q] Pageviews chart: X-axis date ticks too cramped — drop the time component** — _src/components/website-analytics/_. Format ticks `MMM d` instead of `MMM d HH:mm`. ~5 min. +6. **[Q] Pageviews chart: inline note explaining Pageviews vs Sessions** — small `

` under the chart title. ~5 min. +7. **[Q] Inbox: swap section order — Reminders above Alerts** — _src/components/inbox/_. Single JSX reorder. ~3 min. +8. **[Q] BulkAddBerthsWizard: currency field should use ``** — _src/components/admin/bulk-add-berths-wizard.tsx_. Swap raw input for the existing component. ~5 min. +9. **[Q] CommandList scroll-cap bug** — _src/components/ui/command.tsx_. CommandList inside Popover scrolls short of the bottom. Add `max-h-[var(--radix-popover-content-available-height)]` to the inner scroll container. Affects every cmdk dropdown. ~10 min. +10. **[Q] DropdownMenu content stretches to fill viewport — cap it** — _src/components/ui/dropdown-menu.tsx_. Add `max-h-[80vh]` to the content variant. ~5 min. +11. **[Q] Residential InterestsTab: whole row should navigate to the interest, not just the "View" link** — wrap row in `` or add `onClick` to the row. ~10 min. +12. **[Q] StageStepper: surface stage names visibly on reached slices** — _src/components/interests/stage-stepper.tsx_. Currently shows just an icon; add `aria-label` + visible text below the icon on reached slices. ~15 min. + +**Commit shape:** one PR titled `chore(uat-batch): group-A copy + UI quick fixes (12 items)`. + +--- + +## Group B — Interest detail polish (~2 h total) + +Surfaces all touch `interest-tabs.tsx` / `interest-overview` / linked-berths. Grouping keeps the diff focused on one entity. + +13. **[M] Inbox → Reminders: move filter row inline with the "New Reminder" button (embedded mode)** — _src/components/reminders/reminders-list.tsx_. Add an `embedded?: boolean` prop that consolidates the filter row + the New button into one row when set. ~45 min. +14. **[M] Interest Overview Email + Phone rows: combobox picker across client's contacts + quick-add new contact** — _src/components/interests/interest-tabs.tsx_ + _src/components/clients/client-contacts-picker.tsx (new)_. The Email + Phone rows on the Overview currently show only the primary; reps want to pick any of the client's contacts and add new ones inline. ~1 h. +15. **[M] Inline phone editor on the Contact row** — adjacent to #14; add `InlineEditableField variant="phone"` (or similar) using the country-code + national-number split. ~30 min. +16. **[M] Client Overview should summarize current interest's requirements** — one-line "current interest needs L × W × D, source X" on the Client detail Overview tab. ~30 min. +17. **[M] Notes Latest-note teaser missing round / stage context pill** — _src/components/interests/interest-tabs.tsx_ around the latest-note teaser. Pull the stage at the time of the note (from `audit_logs`) and render as a chip next to the timestamp. ~45 min. +18. **[M] InterestBerthStatusBanner: name + link the competing deal** — _src/components/interests/interest-berth-status-banner.tsx_. Today says "this berth is also linked to another interest"; should name the client + link to the interest. ~30 min. +19. **[M] Qualification auto-confirm "intent confirmed" once stage ≥ EOI (extend `computeAutoSatisfied`)** — _src/lib/services/qualification.service.ts_. Add the auto-confirm rule. Most of the work shipped earlier; this is the final tightening. ~30 min. + +**Commit shape:** one PR titled `feat(uat-batch): Interest detail polish (Group B — 7 items)`. + +--- + +## Group C — Berth list features (~2.5 h) + +20. **[M] Berth list: hide "Rates (USD)" + "Pricing valid" columns by default (or remove)** — _src/components/berths/berth-columns.tsx_ + `BERTH_DEFAULT_HIDDEN`. Short-term rental fields irrelevant to purchase/long-term ports. Update default visibility; do not remove columns (other ports may still use them). ~10 min. +21. **[M] Dimensions columns: add ft↔m toggle in the column header (persisted to user prefs); skip per-row entry-unit indicator** — _src/components/berths/berth-columns.tsx_, _src/components/yachts/yacht-columns.tsx_, _src/components/clients/client-yachts-tab.tsx_, _src/components/companies/company-owned-yachts-tab.tsx_, plus _new_ `src/lib/utils/dimensions.ts` for the conversion + format helper, and _src/lib/db/schema/users.ts_ `user_profiles.preferences` for the persisted preference key. ~1 h. +22. **[M] ft ↔ m unit switching on Berth Requirements** — _src/components/interests/interest-tabs.tsx_ — the three inline-editable dim rows hard-code `(ft)` in the label. The interest already carries `desiredLengthUnit`; honour it. ~30 min. +23. **[L] Berth list: bulk-edit affordance (parity with bulk-add)** — _src/components/berths/_, _src/lib/services/berths.service.ts_, _new endpoint_ `POST /api/v1/berths/bulk`. Backend mirrors `/interests/bulk` shape; UI gets a `DataTable bulkActions` toolbar. ~5-7 h. **Pairs with:** Bucket 3 #2 Bulk-price editing UI — the inline-price-edit + bulk-price-sheet should land alongside this. Combined effort ~7-10 h. + +**Commit shape:** two PRs — `feat(berths): dimensions column toggle + hide rental columns` (B-20/21/22), `feat(berths): bulk-edit + bulk-price UI` (B-23 + Bucket 3 #2). + +--- + +## Group D — BulkAddBerthsWizard polish (~1.5 h) + +24. **[M] BulkAddBerthsWizard + single-berth editor: toggleable input units (ft/m) for dimension fields** — _src/components/admin/bulk-add-berths-wizard.tsx_ + _src/components/berths/berth-form.tsx_. Tiny segmented toggle above the dimension inputs (ft / m). Convert on submit so the canonical column stays consistent. ~45 min. +25. **[M] BulkAddBerthsWizard: allow defining new dock/pontoon letters in-flow (or surface the admin path)** — _src/components/admin/bulk-add-berths-wizard.tsx_. Currently fixed to A/B/C/D/E. Add "+ New letter" affordance or a clear "manage letters in /admin/vocabularies" link. ~30 min. + +**Commit shape:** one PR titled `feat(berth-admin): wizard polish (Group D)`. + +--- + +## Group E — Supplemental-info-request (~1 h) + +26. **[M] Supplemental-info-request: distinct Regenerate vs Resend actions + issue history** — _src/components/interests/supplemental-info-request-button.tsx_. Today's UI has a single Generate + Send button; add: Regenerate (new token, invalidates old), Resend (re-email existing token), and a small history list of past issuances + their status. Builds on what `a4e30ea` already shipped (generate vs send split). ~1 h. + +**Note:** Supplemental-info-request _separate generate link and send email_ + _link reusable_ already SHIPPED (a4e30ea, b74fc56). + +--- + +## Group F — DocumentsHub + signing flow polish (~3 h) + +27. **[M] DocumentsHub: hide breadcrumb on root "All documents" view, move PageHeader up** — _src/components/documents/hub-root-view.tsx_ + the surrounding shell. Conditional render. ~30 min. +28. **[M] Past-milestones strip → expandable history with inline doc preview** — _src/components/interests/interest-tabs.tsx_ around line 863 (past-milestones strip). Convert to accordion; each past milestone expands to show its associated docs + sub-status timeline + inline PDF preview using the existing pdf-viewer primitive. ~3-4 h. +29. **[M] Watchers configurable at document creation time** — _src/components/documents/eoi-generate-dialog.tsx_, _src/components/documents/upload-for-signing-dialog.tsx_, _src/components/interests/external-eoi-upload-dialog.tsx_, _src/components/documents/create-document-wizard.tsx:157_ + service-side defaults. ~1.5 h. + +--- + +## Group G — Admin sections consolidation (~6 h) + +30. **[L] Merge `/admin/invitations` into `/admin/users`** — _src/app/(dashboard)/[portSlug]/admin/users/page.tsx_, _src/app/(dashboard)/[portSlug]/admin/invitations/page.tsx_ (to be removed), _src/components/admin/users/_, _src/components/admin/admin-sections-browser.tsx:90-95_. Add a state filter `All | Active | Invited (pending) | Disabled | Archived`. Default to Active. ~3-4 h. +31. **[L] Consolidate every AI-feature admin control onto `/admin/ai`** — _src/app/(dashboard)/[portSlug]/admin/ai/page.tsx_ + per-feature embedded forms. Berth PDF parser AI fallback, AI/OCR pipeline, plus deferred sections (recommender embeddings, contact-log extraction, inquiry parsing). Berth PDF parser AI fallback is the only currently-LLM-using feature without a section — surface its provider override, confidence threshold, per-call budget cap. ~2 h for the present one + UI hooks for the deferred sections. + +--- + +## Group H — Email + branding (~2 h) + +32. **[M] Email settings page: add explainer copy clarifying why sales send-from and noreply have separate credentials** — _src/app/(dashboard)/[portSlug]/admin/email/page.tsx_ — small description block. ~15 min. +33. **[L] Supplemental-info-request email: branded HTML styling** — _src/lib/email/templates/_ — rebuild the template to match the table-based, max-width 600, logo + blurred overhead background look. ~1-2 h. + +--- + +## Group I — Residential parity (~10 h, single coordinated PR) + +34. **[M] Residential client detail header: match the main ClientDetailHeader layout** — _src/components/residential/residential-client-detail-header.tsx_ + _src/components/clients/client-detail-header.tsx_. Restructure. ~1 h. +35. **[L] Residential interests list: visual + functional parity with the main InterestList** — _src/components/residential/residential-interests-list.tsx_ vs _src/components/interests/interest-list.tsx_. Card / table / kanban view modes, full FilterBar, ColumnPicker, bulk actions, realtime invalidation, kebab actions. ~6-8 h. +36. **[L] Residential inquiry → auto-forward to external partner email(s)** — _src/lib/services/residential.service.ts_ + admin settings UI + new template + BullMQ enqueue. ~2-3 h. +37. **[L] Auto-link residential interests to existing main-client records (same person)** — schema migration + service join + UI surfaces on both sides + backfill script. ~3-4 h. + +--- + +## Group J — Activity feed + EntityActivityFeed (~2 h) + +38. **[M] EntityActivityFeed: rewrite per-row rendering to surface _what_ changed** — _src/components/shared/entity-activity-feed.tsx_. Current rows are flat "user X did Y"; rewrite to show the field-level diff (`old → new`) using the existing audit-log diff shape. ~2 h. +39. **[M] Client → Companies tab: add CTA to link or create a company membership** — _src/components/clients/client-companies-tab.tsx_. Empty-state CTA + dialog. ~1 h. + +--- + +## Group K — OnboardingChecklist + nudges (~6-8 h, single big PR) + +40. **[L] OnboardingChecklist: auto-check resolver-chain fix + super_admin discoverability** — _src/components/admin/onboarding-checklist.tsx_ + _src/lib/services/port-config.ts_ + new dashboard tile + new topbar banner. Two linked issues: + - **(a)** Replace each `autoCheckSettingKey` with an `autoCheckResolver` function that runs the full resolver chain and returns `true` when the functional config is complete. Belt-and-braces: surface what's resolving from where ("Email: ✓ Using global SMTP" vs "Per-port override"). + - **(b)** Topbar banner (slim chip "Setup X% complete · Continue →" dismissible per-session), dashboard rail tile "Continue setup", in-app weekly notification, 🎉 100% celebration. Gate all on `super_admin`. + +--- + +## Group L — UploadForSigningDialog comprehensive rework (~12-16 h, dedicated PR) + +41. **[L] UploadForSigningDialog comprehensive rework — 4 linked issues** — Documenso PDF preview rebuild, metadata + draft persistence, dialog width responsive sizing, field-placement UX. Bundles with Documenso v2 follow-ups. Single coordinated PR. + +--- + +## Group M — Universal preview + form-templates (~12-16 h) + +42. **[L] Universal in-system preview for every file type** — extend FilePreviewDialog beyond PDF + images. .docx / .xlsx / .pptx via google-doc-viewer iframe or libreoffice headless; .txt / .csv / .md inline; .eml / .msg via mailparser; .zip see-into. ~6-10 h. +43. **[L] Form-template fields bind to Interest/Client data — autofill, override-preservation history, dual-surface audit trail** — _src/lib/db/schema/documents.ts:290-309_ (`formTemplates.fields` JSONB) + the New-form-template dialog UI + supplemental-forms.service.ts + new `interest_field_history` table + Interest/Client detail surfaces. ~8-12 h. + +--- + +## Group N — Dashboard upgrades (~10-14 h) + +44. **[L] Pipeline Value tile should respect dashboard timeframe** — Dashboard-wide timeframe context (Zustand store or React Query keyed by range); forecast/KPI service variants accept a `range`; "realized vs forecast" line. ~3-4 h. +45. **[L] "Clients by country" dashboard widget** — compact ranked list with mini bars per row, deep-link `/clients?country=DE`. ~2-3 h. +46. **[L] Drag-and-drop rearrangable dashboard widgets** — extend `useDashboardWidgets` to read a `dashboardWidgetOrder` preference; `@dnd-kit/core` + `@dnd-kit/sortable`; persist via PATCH `/api/v1/me/preferences`. ~4-6 h. + +--- + +## Group O — Umami analytics phases 3 / 4 / 5 (~14-18 h) + +47. **[L] Umami Phase 4a — Marketing-site instrumentation** — _BLOCKS Phase 3 + Phase 5._ Wire `umami.track()` calls into the marketing site for every CRM event we want to surface (inquiry submitted, brochure download, contact-form, etc.). ~3-4 h on the marketing-site repo + alignment with this repo. +48. **[L] Umami Phase 4c UI — Tracked-link composer button** — _src/components/email/email-composer.tsx_ or wherever the rep writes a templated email; add a button that opens a tracked-link composer + injects the resulting URL. ~2-3 h. +49. **[L] Umami Phase 3 — Events tab** — _src/components/website-analytics/events-list.tsx (new)_. Blocked on 4a. ~3-4 h. +50. **[L] Umami Phase 5 — Funnels + Journeys** — Funnel builder + journey-flow sankey. Blocked on 4a. ~6-8 h. +51. **[M] Umami: Empty-state nudges on quiet ranges** — _src/components/website-analytics/_. Stable copy when the range has < N events ("Nothing happened here; try a wider range"). ~30 min. +52. **[M] Umami: Apple Mail privacy disclaimer copy** — _src/components/email/email-open-rate-pill.tsx_ — small tooltip explaining that Apple Mail Privacy Protection inflates open rates. ~15 min. +53. **[M] Umami: Open-rate column on the document_sends list** — _src/components/documents/document-sends-list.tsx_. New column reading the per-send open count. ~30 min. +54. **[M] Umami: Click-to-filter the page from the world map** — _src/components/website-analytics/visitor-world-map.tsx_. Wire `onCountryClick(iso2)` into a new country filter store + thread through every `useUmami*` hook. ~2-3 h. +55. **[M] Umami: Verify pixel + tracked-link end-to-end with a real send** — manual UAT. ~15 min once 4a is live. + +--- + +## Group P — Nested document subfolders — phases 2/3 (~5-6 h) + +56. **[L] Nested document subfolders — phases 2 and 3** — foundation shipped in `e91055f`. Remaining: + - **(a)** UploadZone gains `scopeOptions` radio: "This deal (Interest )" vs "Client-level (all deals)". Single-scope contexts (client/yacht/company) hide the radio. + - **(b)** Lifecycle hooks: interest outcome → folder rename (`Deal A1-A3 (Won)`); soft-rescue on outcome change. + - **(c)** `listFilesAggregatedByEntity` rewrite — surface BOTH "This deal" subheading + "From client" subheading on the InterestDocumentsTab "Attachments" list. + - **(d)** Documents Hub tree rendering for nested interest folders + outcome chip per interest folder. + - **(e)** Backfill script `pnpm tsx scripts/backfill-nested-document-folders.ts --apply` — idempotent, per-port advisory-locked. + +--- + +## Group Q — Platform-wide refactors (~14-18 h, do as coordinated passes when time allows) + +57. **[L] Platform-wide chart library migration: recharts → ECharts** — port the 8 existing recharts components to ECharts. ~6-10 h. +58. **[L] SelectTrigger height (`h-9`) doesn't match Input height (`h-11`)** — _src/components/ui/select.tsx_. Introduce `size` variant; default to `h-11`. Audit compact-context call sites for explicit `size="sm"` override. ~1 h. +59. **[L] Platform-wide table density: column min-widths + nowrap defaults** — _src/components/shared/data-table.tsx_ + per-table column definitions. Add a `widthPx` / `nowrap` field to column defs; default text cells to `whitespace-nowrap`; surface horizontal scroll only when content actually exceeds. ~2-3 h. +60. **[L] Platform-wide admin-settings tooltip audit** — _src/components/admin/_. Sweep every admin setting; add `FieldLabel` + tooltip wherever the setting isn't self-explanatory to a basic admin user. Use the FieldLabel primitive shipped in PR4.2 / `552b966`. ~3-4 h. +61. **[L] Platform-wide error message audit for prod debuggability** — _cross-cutting_. The Documenso 502 / "Invalid token" diagnosis loop showed errors don't self-describe in prod. Two layers: (a) service-side: wrap upstream errors with the resolver chain that's actually in effect; (b) UI: render the wrapped error verbatim in the toast / dialog so operators can see "fell back to env, env value is stale" without reading logs. ~4-6 h. + +--- + +## Group R — Documenso-first templates (~6-8 h) + +62. **[L] Documenso-first templates: pull templates from Documenso instead of uploading through CRM** — _src/components/admin/document-templates/template-form.tsx_ + new admin endpoint `GET /api/v1/admin/documenso/templates` + per-template field-mapping editor + "Sync now" button + template-list badges. Generalizes the existing per-port EOI sync. ~5-7 h. **Pairs nicely with:** Group L (UploadForSigningDialog rework) — they share the same Documenso-side surface area. + +--- + +## Group S — AI assistance + extraction (~10-14 h, deferred until user asks) + +63. **[DEFERRED] AI-assisted action extraction from contact-log entries** — _src/components/interests/interest-contact-log-tab.tsx_ + new LLM service. "Extract action items" button next to Save; LLM-parses body + returns proposed follow-ups; rep approves each individually. ~6-10 h. Defer until a user is genuinely asking. + +--- + +## Group T — Deferred bugs (~1 h each, do when surfacing) + +64. **[DEFERRED] Duplicate row for berth E17 in port-nimara + missing unique index** — DB cleanup + partial unique index `(port_id, mooring_number) WHERE archived_at IS NULL`. Deferred per session call. +65. **[DEFERRED] Stage advance allowed without berth price** — `ValidationError` gate in `changeInterestStage` for stages ≥ eoi. Deferred per session call. + +--- + +## Group U — EOI bundle UX rework (~10-14 h) + +66. **[L] EOI bundle UX rework (multi-berth interests)** — _src/lib/services/interest-berths.service.ts_, _src/components/interests/linked-berths-list.tsx_, _src/components/documents/eoi-generate-dialog.tsx_. Per the locked design notes in master line ~492. Refines the "which berths sign the EOI?" UX now that the underlying schema supports it. ~10-14 h. Partially shipped (a) in `05e727f`; remaining is the picker-inside-generate-dialog. + +--- + +## Execution discipline + +For each item we tackle: + +1. **Quote the master-doc bullet** so we're aligned on scope. +2. **Verify it isn't already shipped** — re-read the master entry for sub-bullets with SHIPPED markers I may have missed. +3. **Implement to production quality** — tests where the feature has logic worth testing; tsc clean; vitest 1454+/1454+; commit with a descriptive message. +4. **Annotate the master doc** — add `**SHIPPED in :**` line under the original entry. +5. **Tick off this plan** — once a group lands, mark the item as `[SHIPPED]` here. + +When in doubt about an item's scope, surface the question first rather than guessing — several items already locked design decisions in the source entry that we should reuse verbatim.