Files
pn-new-crm/docs/superpowers/audits/2026-05-21-remaining-plan.md
Matt 589be0bfed
Some checks failed
Build & Push Docker Images / lint (push) Failing after 1m36s
Build & Push Docker Images / build-and-push (push) Has been skipped
docs(uat): annotate U66 SHIPPED in plan + master doc
Plan item 66 (EOI bundle UX rework) fully closed:
- (a) defaults flip — 05e727f (prior session)
- (b) LinkedBerthsList rename — PR10 (prior session)
- (c) picker inside EoiGenerateDialog — ef37901 (this session)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:08:17 +02:00

243 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Remaining UAT Master Doc — Work Plan
> **STATUS (2026-05-21 23:55):** Groups AT worked through end-to-end.
> Group U (EOI bundle UX rework) explicitly deferred — see note at the
> bottom. Per-group commits:
>
> - **A** `e33313b` + doc annotations `670ca16`
> - **B** `7ecf4ee` + doc annotations `a0a4a5d`
> - **C** `991e222`
> - **D + E** `431375d`
> - **F + G + H** `94c24a1`
> - **I** `989cc4d`
> - **J + K** `03a7521`
> - **L** `65ff596`
> - **M** `0ddaf46`
> - **N** `a147cbc`
> - **O** `a7cbee0`
> - **P** `0ed03fc`
> - **Q** `c14f80a`
> - **R + T** `aa1f5d2`
> - **U** parked
>
> Each commit message documents what shipped vs. what stayed parked.
> Vitest 1454/1454 and tsc clean across every group.
>
> **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 — [SHIPPED in e33313b]
All 12 items closed. 7 new ships + 5 verified pre-shipped (annotation gap in master doc).
1. **[SHIPPED — e33313b]** Admin Documenso settings env-fallback pills — collapsed legacy SettingsFormCard blocks into RegistryDrivenForm sections (`documenso.behavior` + `documenso.templates`).
2. **[SHIPPED — e33313b]** WatchersCard empty-state padding — `mb-3``mb-4 pb-1`.
3. **[SHIPPED — 52342ee, verified]** EOI "Mark as signed without file" button — already in place.
4. **[SHIPPED — e33313b]** /invoices/upload-receipts copy rewrite — ~50% body-copy reduction, terse luxury-CRM voice.
5. **[SHIPPED — e33313b]** Pageviews X-axis ticks — `interval="preserveStartEnd"` + `minTickGap={52}`.
6. **[SHIPPED earlier, verified]** Pageviews vs Sessions explainer — Info popover already in `website-analytics-shell.tsx`.
7. **[SHIPPED — e33313b]** Inbox section order — docstring fixed; JSX already had Reminders before Alerts.
8. **[SHIPPED earlier, verified]** BulkAddBerthsWizard CurrencySelect — already wired at apply-to-all + per-row.
9. **[SHIPPED — e33313b]** CommandList scroll-cap — `max-h-[min(300px,var(--radix-popover-content-available-height,300px))]`.
10. **[SHIPPED — e33313b]** DropdownMenu max-h cap — `max-h-[min(24rem,var(--radix-dropdown-menu-content-available-height,24rem))]`.
11. **[SHIPPED — e33313b]** Residential InterestsTab whole-row navigate — `<tr onClick>` + first-cell Link stopPropagation.
12. **[SHIPPED — e33313b]** StageStepper visible stage names — stage-name row below the bar; `size="xs"` hides labels.
---
## 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. **[SHIPPED in 91be0f9] Form-template fields bind to Interest/Client data — autofill, override-preservation history, dual-surface audit trail** — `bindable-fields.ts` catalog + `formFieldSchema.bindTo` allow-list + admin sheet "Bind to" picker; `applySubmission` extended to write phone + yacht diffs (was silently updating) and address-insert overrides; `/api/v1/clients/[id]/field-history` mirror endpoint; `<FieldHistoryProvider>` + `<FieldHistoryIcon>` mount on Client + Interest Overview tabs and ContactsEditor. Note: addresses tab + yacht detail surface still need the icon wired (5-min follow-up).
---
## 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 <name>)" 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. **[SHIPPED in ef37901] EOI bundle UX rework (multi-berth interests)** — (a) defaults flip shipped in `05e727f`, (b) LinkedBerthsList rename shipped in PR10, (c) picker inside EoiGenerateDialog shipped in `ef37901`: new "EOI scope" section lists every linked berth with "In EOI" + "Public map" checkboxes pre-filled from current flag state; handleGenerate diffs vs server snapshot and PATCHes only changed rows in parallel before kicking off the envelope. Plan item closed.
---
## 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 <sha>:**` 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.