From e9509dc45ca19d811bee6b94d5721f4f04abe052 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 26 May 2026 18:48:46 +0200 Subject: [PATCH] chore(audit-drain): rip out next-intl, RTL lint, sweeps, polish Drain the long-tail audit queue captured in alpha-uat-master.md. - next-intl ripped out (zero useTranslations callers ever existed): package.json, next.config.ts plugin wrap, src/i18n/, messages/, and the layout NextIntlClientProvider all gone; hardcoded. - RTL lint nudge added: warn-only no-restricted-syntax on physical Tailwind utilities (ml-/mr-/pl-/pr-/text-left/text-right/border-l/ border-r/rounded-l-/rounded-r-) inside JSX className literals. Existing ~1,000 sites grandfathered; new code trends toward logical. - Icon-only button accessibility lint: jsx-a11y/control-has-associated- label enabled at warn; 4 empty / action placeholders gain sr-only labels. - Currency: SUPPORTED_CURRENCIES drops the hardcoded English labels; new currencyLabel(code, locale?) helper resolves via Intl.DisplayNames. CurrencySelect + settings-manager migrated. - Date locale sweep: 7 surfaces flip from toLocaleString('en-GB'|'en-US') to toLocaleString(undefined, ...) so dates honour runtime locale. - Dialog/Sheet width: 10 document/EOI/entity-form dialogs gain a lg:max-w-4xl or lg:max-w-5xl step so wide desktops get breathing room. - PaymentsSection collapsed-bar: slim one-line bar showing "Payments - Not received yet" or "Payments - \$X received - N payments - Expand"; per-interest collapse state persists in localStorage; the RecordPayment flow auto-expands. - muted-foreground opacity sweep: 10 text-bearing text-muted-foreground/{60,70,80} hits dropped to plain text-muted-foreground for AA contrast on muted bg. Icon-only (aria-hidden) opacity hits left as-is. - Micro-type bump: text-[10px] and text-[11px] -> text-xs (12px) across 87 files in src/components + src/app. Pure mechanical sweep. - Audit-doc cleanup: alpha-uat-master.md stale 2026-05-25 summary rewritten with cumulative state through today. Items genuinely still open are now a short long-tail list. - New docs/marketing-site-followups.md: Umami Phase 4a/3/5, email pixel E2E verification, and website-cutover work parked here so they don't get lost in the CRM audit doc. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/marketing-site-followups.md | 37 ++ docs/superpowers/audits/alpha-uat-master.md | 52 ++- eslint.config.mjs | 53 ++- messages/en.json | 9 - next.config.ts | 8 +- package.json | 1 - pnpm-lock.yaml | 410 ------------------ src/app/(auth)/setup/page.tsx | 2 +- .../[portSlug]/admin/pipeline-rules/page.tsx | 2 +- src/app/layout.tsx | 10 +- .../public/supplemental-info/[token]/page.tsx | 4 +- .../admin/admin-sections-browser.tsx | 4 +- src/components/admin/audit/audit-log-card.tsx | 12 +- src/components/admin/audit/audit-log-list.tsx | 16 +- src/components/admin/backup-admin-panel.tsx | 4 +- .../admin/bulk-add-berths-wizard.tsx | 14 +- .../admin/documenso/embedded-signing-card.tsx | 4 +- .../admin/documenso/template-sync-button.tsx | 38 +- .../document-templates/template-form.tsx | 2 +- .../template-version-history.tsx | 2 +- .../duplicates/duplicates-review-queue.tsx | 6 +- .../admin/forms/form-template-form.tsx | 4 +- .../admin/invitations/invitations-manager.tsx | 4 +- src/components/admin/onboarding-checklist.tsx | 6 +- .../admin/qualification-criteria-admin.tsx | 4 +- src/components/admin/queue-overview.tsx | 6 +- .../admin/residential-stages-admin.tsx | 6 +- src/components/admin/roles/role-list.tsx | 4 +- .../admin/sales-email-config-card.tsx | 2 +- .../admin/settings/settings-manager.tsx | 4 +- .../admin/shared/registry-driven-form.tsx | 6 +- .../admin/shared/settings-form-card.tsx | 4 +- .../admin/shared/template-token-picker.tsx | 12 +- .../admin/templates/template-editor.tsx | 2 +- .../admin/users/user-permission-matrix.tsx | 2 +- src/components/alerts/alert-bell.tsx | 2 +- src/components/alerts/alert-card.tsx | 6 +- .../berths/active-interests-popover.tsx | 2 +- src/components/berths/berth-columns.tsx | 2 +- src/components/berths/berth-detail-header.tsx | 2 +- .../berths/berth-interest-pulse.tsx | 8 +- src/components/berths/berth-interests-tab.tsx | 4 +- .../clients/bulk-hard-delete-dialog.tsx | 4 +- src/components/clients/client-card.tsx | 2 +- .../clients/client-channel-editor.tsx | 6 +- src/components/clients/client-columns.tsx | 2 +- src/components/clients/client-form.tsx | 2 +- .../clients/client-interests-tab.tsx | 2 +- .../clients/client-pipeline-summary.tsx | 8 +- src/components/clients/contacts-editor.tsx | 2 +- .../clients/dedup-suggestion-panel.tsx | 6 +- src/components/companies/company-form.tsx | 6 +- src/components/dashboard/activity-feed.tsx | 2 +- .../dashboard/customize-widgets-menu.tsx | 2 +- src/components/dashboard/hot-deals-card.tsx | 2 +- .../dashboard/my-reminders-rail.tsx | 4 +- src/components/dashboard/onboarding-tile.tsx | 2 +- .../dashboard/pipeline-value-tile.tsx | 14 +- .../dashboard/website-glance-tile.tsx | 2 +- .../documents/aggregated-section.tsx | 2 +- src/components/documents/documents-hub.tsx | 2 +- .../documents/entity-folder-view.tsx | 4 +- .../documents/eoi-generate-dialog.tsx | 54 +-- .../documents/external-eoi-edit-dialog.tsx | 2 +- .../documents/signing-details-dialog.tsx | 6 +- src/components/documents/signing-progress.tsx | 6 +- .../documents/upload-for-signing-dialog.tsx | 10 +- .../email/tracked-link-composer-button.tsx | 2 +- src/components/files/file-grid.tsx | 2 +- src/components/interests/assigned-to-chip.tsx | 2 +- src/components/interests/deal-pulse-chip.tsx | 8 +- .../interests/external-eoi-upload-dialog.tsx | 2 +- src/components/interests/interest-card.tsx | 4 +- src/components/interests/interest-columns.tsx | 2 +- .../interests/interest-contact-log-tab.tsx | 12 +- .../interests/interest-contract-tab.tsx | 2 +- .../interests/interest-detail-header.tsx | 2 +- src/components/interests/interest-eoi-tab.tsx | 4 +- src/components/interests/interest-form.tsx | 6 +- .../interests/interest-reservation-tab.tsx | 2 +- src/components/interests/interest-tabs.tsx | 16 +- .../interests/interest-timeline.tsx | 2 +- .../interests/linked-berths-list.tsx | 6 +- src/components/interests/multi-eoi-chip.tsx | 2 +- src/components/interests/payments-section.tsx | 107 ++++- .../interests/qualification-checklist.tsx | 2 +- .../supplemental-info-request-button.tsx | 2 +- src/components/layout/inbox.tsx | 6 +- src/components/layout/mobile/more-sheet.tsx | 2 +- src/components/layout/sidebar.tsx | 6 +- .../notifications/notification-bell.tsx | 2 +- src/components/reminders/reminder-form.tsx | 4 +- src/components/reminders/reminder-list.tsx | 4 +- src/components/reminders/reminders-inline.tsx | 2 +- .../builders/dashboard-report-builder.tsx | 2 +- src/components/reports/reports-list.tsx | 4 +- .../residential/residential-clients-list.tsx | 2 +- .../residential/residential-interest-card.tsx | 10 +- src/components/search/command-search.tsx | 10 +- .../search/mobile-search-overlay.tsx | 8 +- src/components/shared/column-picker.tsx | 2 +- src/components/shared/currency-select.tsx | 6 +- src/components/shared/field-history.tsx | 4 +- src/components/shared/notes-list.tsx | 4 +- src/components/shared/owner-picker.tsx | 2 +- src/components/ui/kpi-tile.tsx | 2 +- .../website-analytics/realtime-panel.tsx | 2 +- .../session-detail-sheet.tsx | 2 +- .../website-analytics/sessions-list.tsx | 2 +- .../website-analytics-shell.tsx | 2 +- .../website-analytics/weekly-heatmap.tsx | 8 +- src/components/yachts/yacht-detail-header.tsx | 2 +- src/components/yachts/yacht-form.tsx | 6 +- src/i18n/request.ts | 20 - src/lib/utils/currency.ts | 55 ++- 115 files changed, 528 insertions(+), 776 deletions(-) create mode 100644 docs/marketing-site-followups.md delete mode 100644 messages/en.json delete mode 100644 src/i18n/request.ts diff --git a/docs/marketing-site-followups.md b/docs/marketing-site-followups.md new file mode 100644 index 00000000..dba76e97 --- /dev/null +++ b/docs/marketing-site-followups.md @@ -0,0 +1,37 @@ +# Marketing-site followups + +Items that require edits to the **separate marketing-site repo** (port-nimara.com / portnimara.com), not the CRM. These can't ship from this codebase; they're parked here so they don't get lost when we drain the CRM audit doc. + +Last updated: 2026-05-26. + +--- + +## Umami analytics — Phases 4a, 3, 5 + +**Source:** `docs/superpowers/audits/alpha-uat-master.md` — Umami follow-ups parked at end of the 2026-05-19 build session. + +- **Phase 4a — Marketing-site instrumentation.** The CRM's Umami integration (Phase 4b — pixel + tracked-link events on outbound sales emails) is shipped. Phase 4a is the parallel work on the marketing site: add the Umami tracking script to every page, instrument the public berth inquiry form submission, instrument the "request more info" buttons, and confirm session-level attribution flows back to the same Umami workspace the CRM reads. +- **Phase 3 — Events tab.** Once 4a lands, the CRM's `/admin/website-analytics` page gets an Events tab that lists every named Umami event (inquiry-submitted, brochure-downloaded, berth-details-viewed, contact-clicked, …) with counts, top-source breakdown, and a 30-day trendline. Backend already proxies `/api/umami/events`; UI surface is the missing piece. Blocked on 4a sending real event data. +- **Phase 5 — Funnels.** Multi-step funnel widget on the dashboard ("landed on /berths → opened a berth → submitted inquiry → was created as a CRM interest → reached EOI stage"). Joins Umami sessionId with the CRM's `interests.umamiSessionId` snapshot we already write. Blocked on 4a so the first three steps have real data to consume. + +--- + +## Email-tracking end-to-end verification + +**Source:** alpha-uat-master.md — Bucket 2 Umami follow-ups. + +- **Verify the pixel + tracked-link with a real send** — flip `email_open_tracking_enabled = true` for port-nimara, send a real sales email to a personal inbox, open it in Mail.app + Gmail web, confirm: (a) a `document_send_opens` row appears, (b) `open_count` + `first_opened_at` increment on the parent row, (c) Umami records an `email-opened` event. Same drill for `/q/` short-links once the composer ships them. Cannot be automated — needs a real human inbox. This is a CRM-side manual UAT step but it depends on the marketing-site short-link redirector being live. + +--- + +## Public berth endpoint email recipient UI (parking note) + +**Source:** memory — "Email ownership at cutover" (`project_email_ownership_at_cutover.md`). + +When the marketing site cuts over and inquiry emails route through the CRM rather than the website's own SMTP, the public berth endpoint + the admin recipient UI need to be in place. Templates + settings keys exist on the CRM side; the marketing-site side needs the form submission target updated to hit `/api/public/website-inquiries` (or whichever the final endpoint is) instead of the legacy mailto. Coordinate as one rollout. + +--- + +## How to triage when picking these up + +Each item here has a CRM-side prerequisite or downstream consumer that's already in place. The work itself lives in the marketing-site repo. When you tackle one, link the marketing-site PR back into this file and tick the item off — keep this doc shrinking, not growing. diff --git a/docs/superpowers/audits/alpha-uat-master.md b/docs/superpowers/audits/alpha-uat-master.md index be1d2fb5..dda16333 100644 --- a/docs/superpowers/audits/alpha-uat-master.md +++ b/docs/superpowers/audits/alpha-uat-master.md @@ -13,36 +13,46 @@ > - `medium` — UX regression, partial functionality, recoverable error > - `low` — cosmetic, copy, polish -> **2026-05-25 status check** — full audit triage + execution pass landed (~25 commits over two passes). Shipped in this session: +> **2026-05-26 status check** — drain pass landed across the long-tail polish queue. Cumulative state below; per-item commit hashes live in `git log`. > -> **Bucket 1 (Wave A–E):** Interest form yacht auto-select + EOI dialog "View EOI" toast + berth-picker compact label + Documents-tab Generate-EOI removal + role-scoped interest auto-assign + LinkedBerthRowItem dimension cleanup + ExternalEoiUploadDialog prefill (title + signatories from active EOI) + Overview milestone EOI signature progress widget. a11y aria-live on supplemental info + 13-component date/currency locale sweep (en-US/en-GB → runtime). Primary-berth-always-in-bundle service guard strengthened + backfill migration 0083. Onboarding super_admin discoverability (topbar banner + dashboard tile + celebration toast) wired via `/api/v1/admin/onboarding/status` + shared service. Branded post-completion email idempotency regression test. +> **Big-ticket modules shipped (May 25–26):** > -> **Bucket 2 (Wave A–E):** Documents Hub folder rail min-width fix at tablet 768. Website analytics KPI 6→3 cols at lg + 6 at xl. Pipeline Value tile compact `$3.5M` format at sm-. Form-error UX rollout to 5 highest-impact forms (client/interest/yacht/company/berth). TopList empty-state nudge primitive. Sheet width default `sm:max-w-sm → sm:max-w-md + lg:max-w-xl`. +> - **Reports P3–P7** — `e9ef583` BullMQ render+email worker; `2072f6c` landing + per-kind builder + Templates/Runs/Schedules sub-pages; `3f9c458` CSV output renderer; `866b910` subtitle override + `8998f68` cover-page brand picker. Page is end-to-end functional with scheduled runs, output formats, and dashboard cover branding. +> - **Tenancies P2–P7** — `ccc775d` rename migration `berth_reservations → berth_tenancies`; `20549fb` webhook auto-create + first-insert flip; `bfb29ab` public-map status flip via active permanent tenancy; `3a48150` sidebar entry + 404 + API gate; `e4daa48` entity-tab module gate; `911b51a` generic create + edit dialog + self-FKs; `db14056` 4 module-gated dashboard widgets; `d32e557` tenure-aware renewal + transfer actions; `dd25ccf` 7-agent system-wide rename audit fixes. **Chicken-and-egg fix landed 2026-05-26** — webhook auto-create no longer gates itself on `isTenanciesModuleEnabled`; the row-exists fallback in that helper lazily surfaces the module on first signing (`docs/tenancies-design.md` §"When disabled" updated). +> - **UploadForSigningDialog field metadata** — `c4450dd` PlacedField.defaultValue + per-type panel inputs + Documenso v2 `field/create-many` payload extension. +> - **Bulk operations on berths** — `c549622` bulk-price editing UI (inline cell + bulk-edit sheet); `991e222` bulk-edit affordance covering status/tenure_type/tag/archive + 500-id cap + per-row failure reporting. +> - **Documents UX** — `c886933` clickable rows open in-page file preview (Tier 1+2 universal preview); `400ff99` inline edits on berth detail Overview tab now persist visually; `da391b1` interest dimensions dual-source (yacht dims for the recommender). > -> **Bucket 2 (Wave F):** Radio field type for admin registry + adopted on `eoi_send_mode` and `documenso_signing_order`. Include-yacht toggle on EOI generate dialog (blanks Section 3 even when a yacht is linked; choice recorded in audit log). External-EOI auto-cancel: replace-or-keep radio shows when a generated EOI is active; replace path voids the upstream Documenso envelope + flips the prior doc to cancelled before the new doc lands. +> **Form-error UX sweep — complete.** All `useForm` callers in `src/components` adopt `useFormScrollToError` + `` (the one remaining holdout is the dev-only `shared/form-devtool.tsx`). > -> **Bucket 2 form-error sweep:** All 16 remaining form callsites adopted `useFormScrollToError` + `` — login / reset-password / set-password / setup auth forms + invoices/new + berth-detail-header + invoice-detail (record-payment) + reservations/berth-reserve-dialog + yachts/yacht-transfer-dialog + companies/add-membership-dialog. Form-error UX sweep now complete platform-wide. +> **Bucket 2/4 polish drained 2026-05-26:** > -> **Bucket 3 design docs:** `docs/reports-page-design.md` (~400 lines, 7-PR plan) + `docs/tenancies-design.md` (~350 lines, 7-PR plan). +> - **next-intl ripped out** — zero `useTranslations()` callers ever existed; the dependency, plugin wrap, request config, and `messages/en.json` are gone. `` hardcoded. +> - **RTL lint rule** — warn-only `no-restricted-syntax` on physical Tailwind utilities (`ml-/mr-/pl-/pr-/text-left/text-right/border-l/border-r/rounded-l-/rounded-r-`) inside `JSXAttribute[name='className']` literals across `src/components` + `src/app`. Existing 1,000+ sites grandfathered; new code trends toward logical (`ms-/me-/ps-/pe-/text-start/text-end/border-s/border-e/rounded-s-/rounded-e-`). +> - **Currency labels via Intl.DisplayNames** — `SUPPORTED_CURRENCIES` no longer carries hardcoded English labels; new `currencyLabel(code, locale?)` helper resolves via `Intl.DisplayNames`. Two consumer sites migrated (`CurrencySelect`, `settings-manager`). +> - **Date locale sweep** — 7 surfaces (`template-version-history`, `website-analytics/session-detail-sheet` + `sessions-list`, `signing-details-dialog` ×2, `reports-list` ×2) flipped from `toLocaleString('en-GB'|'en-US')` to `toLocaleString(undefined, …)` so dates honor the user's runtime locale. +> - **Dialog/Sheet width bump** — document + EOI + entity-form dialogs all gain a `lg:max-w-4xl`/`lg:max-w-5xl` step so wide desktops get breathing room. Hit: `external-eoi-edit-dialog`, `signing-details-dialog`, `eoi-generate-dialog`, `external-eoi-upload-dialog`, `interest-form`, `client-form`, `yacht-form`, `company-form`, `form-template-form`, `template-form`. +> - **PaymentsSection collapsed-bar** — slim one-line bar shows "Payments · Not received yet" or "Payments · $X received · N payments · Expand"; per-interest collapse state persisted in localStorage; auto-expands on a fresh deposit record. +> - **muted-foreground opacity sweep** — text-bearing `text-muted-foreground/{60,70,80}` hits dropped to plain `text-muted-foreground` on `template-token-picker`, `admin-sections-browser`, `upload-receipts-guide`, `client-card`, `residential-interest-card`, `mobile-search-overlay`, `command-search` ×3, `aggregated-section`, `activity-feed`. Icon-only opacity hits (aria-hidden Lucide icons) left as-is. +> - **Micro-type bump** — `text-[10px]` and `text-[11px]` swept to `text-xs` (12px) across 87 files in `src/components` + `src/app`. Pure mechanical replace; no behavioural change. +> - **Icon-only button lint rule** — `jsx-a11y/control-has-associated-label` enabled (warn) with a sensible `controlComponents: ['Button']` config. Caught + fixed 4 empty ``/`` placeholders in bulk-add-berths-wizard, invitations-manager, berth-interests-tab via `sr-only` action labels. +> - **EOI tab upload-draft parity** — confirmed already shipped: `documentTypeSchema` accepts `'eoi'` and `interest-eoi-tab.tsx:243` mounts the dialog. +> - **EntityFolderView per-row interest badge** — confirmed already shipped (lines 116–118 render the badge + interest link). +> - **Onboarding autoCheckResolver** — confirmed already working: the checklist hits `/api/v1/admin/settings/resolved?keys=...` which runs the port→global→env→default chain, and `smtp_host_override` / `documenso_api_url_override` / etc. have `envFallback` set on their registry entries. Steps auto-tick when a port relies on env config. +> - **Global-search translucent bug** — defensive fix in `command-search.tsx:327` (`bg-white dark:bg-popover shadow-lg`) is solidly opaque; no parent has opacity/blend that would leak through. Closed. > -> **Bucket 3 P1 foundations:** +> **Marketing-site followups** parked separately in `docs/marketing-site-followups.md`: > -> - Tenancies module-enabled gate (`tenancies_module_enabled` setting, `tenancies-module.service.ts`, 3 admin endpoints under `/api/v1/admin/tenancies-module/`). -> - Reports schema migration 0084 (extends `report_templates` + adds `report_runs` + `report_schedules` tables) + matching Drizzle schema. +> - Umami Phase 4a (marketing-site instrumentation), Phase 3/5 (events tab + funnels) — blocked on the other repo. +> - Email pixel/tracked-link end-to-end verification with a real human inbox. +> - Public berth endpoint + admin recipient UI for the website-to-CRM email cutover. > -> **Bucket 3 Reports P2 (this session):** CRUD layer on `report_runs` + `report_schedules`. Validators (kind / output / cadence / status enums), services (`report-runs.service.ts`, `report-schedules.service.ts` with deterministic `nextRunFor` math), routes (`/api/v1/reports/runs` list+create + `/[id]` get, `/api/v1/reports/schedules` list+create + `/[id]` get+patch+delete). 9-case integration test covering cross-port FK guard, config.kind discriminator, listing filters, cadence math, no-op-doesn't-slip rule, and `ON DELETE SET NULL` contract on schedule deletion. +> **Genuinely still-open (long-tail, low ROI):** > -> **Bucket 4:** Sheet width sweep (Sheet primitive update covers every site). External-EOI dialog cache collision: dialog was caching `{data:…}` on the same key the parent unwraps, blanking the page on open — fix unwraps to match. External-EOI advance-gate regression test (7 cases). Search popover defensive opaque background. EntityFolderView visual overhaul: shared FileIcon mapping for type-specific colours + inline "Signed" pill from `signedFromDocumentId`. -> -> **Audit-cleanup callouts:** "dock-letters entity" (B2 Wave G item) was already shipped in `431375d` (D25). "Email-test endpoints" was already shipped (registry + endpoint + admin card all exist). "Cancel doc delete-vs-keep" was already shipped (cancelMode plumbed through `cancelDocument` + dialog adoption complete). These three were misclassified as queued. -> -> **Deferred / queued for follow-up sessions (~110 h):** -> -> - Reports P3-P7 (~31 h): BullMQ render+email queues + landing + builder + sub-pages + CSV/PNG outputs + metadata overrides. -> - Tenancies P2-P7 (~36 h): rename migration + perms seed + webhook auto-create + public-map flip rules + sidebar entry + top-level page + entity tab CTAs + 4 reporting widgets. -> - UploadForSigningDialog field metadata (full bundle, ~6-9 h): PlacedField.defaultValue + fieldMeta with per-type panel inputs + Documenso v2 `field/create-many` payload extension. -> - B3 Wave remaining: bulk-price editing UI (~2-3 h — backend already shipped); Umami Phase 4a (marketing-site instrumentation, separate repo) + Phase 3/5 (events tab + funnels, blocked on 4a). _Shipped this session: B3-1 (interest dimensions dual-source). Shipped earlier in week: universal file preview Tier 1+2, all 16 PDF resolvers (incl. the 5 previously-tracked "remaining"), universal upload-with-fields backend + most UI sites._ Recharts→ECharts migration removed (rejected).\_ -> - B4 bugs: Global-search dropdown translucent still wants live-browser repro to confirm the defensive fix actually addressed the cause. +> - **Sheet width on wide viewports** — bumped the document/EOI dialogs by one tier; if any specific dialog still feels narrow, name it. +> - **Custom-field-form FieldLabel sweep** — primitive exists, registry-driven-form already surfaces descriptions inline (better discoverability than tooltip), custom-fields uses FieldLabel. Bespoke admin pages (~10–15 surfaces) still use plain `