Lays out the plan to replace pdfme with @react-pdf/renderer, add unpdf
for berth-PDF tier-2 rasterization, and add port-level logo upload
(sharp normalization + react-image-crop UI + svgo sanitization +
rasterize-SVG-to-PNG-on-upload).
Scope locked to internal-only PDFs (reports, expenses, record exports).
Invoice + admin TipTap-to-PDF removed entirely; in-app EOI pathway
(pdf-lib AcroForm fill) stays untouched.
14 commits planned. Single source of truth for tokens. Three orthogonal
PDF paths post-migration with no overlap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lint-staged reformat after the previous commit added the file. Same
content, prettier's preferred line wrap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the bare "+ New document" Button on the documents hub with a
NewDocumentMenu dropdown so reps explicitly pick between:
- "Upload file" → opens a Dialog with FileUploadZone scoped to the
current folder + entity context. No signing flow attached.
- "Generate document for signing" → navigates to /documents/new wizard.
Avoids the prior ambiguity where reps clicked "+ New document" intending
to attach a file and were dropped into the Documenso signer wizard.
Also adds FolderDropZone wrapping FlatFolderListing and EntityFolderView.
Dragging files from the OS over the current folder shows a drop overlay;
drop fires N parallel uploads carrying the folder + entity context.
Mirrors the per-entity Files tab UX but works in-place on the hub.
Both surfaces hit /api/v1/files/upload with folderId + entityType/Id +
the legacy clientId/companyId/yachtId FKs so files land on the right
entity AND inside the correct folder.
Also includes the in-flight prettier reformat from lint-staged on a
few previously-touched files (create-document-wizard, file-upload-zone,
admin/documenso/page) and adds the standalone prod-readiness audit
report to docs/superpowers/audits/ for permanent reference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-format all files modified during the documents-hub-split feature
branch that were not yet aligned with the project's Prettier config
(single quotes, semicolons, trailing commas).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
19-task implementation plan layering on top of Wave 11.B. Builds three
system-managed roots (Clients/Companies/Yachts), per-entity auto-
subfolders, Documenso auto-deposit on completion, owner-aggregated
projection (symmetric reach, file-FK source of truth, defense-in-depth
port_id), and the hub UI rebuild. Hard cutover; backfill via idempotent
script.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prettier reformatting on files touched in the wave 11.B sequence —
markdown italics _underscore-style_, single-line conditionals, minor
whitespace fixes. No semantic changes. .env.example reformatting left
unstaged (blocked by pre-commit hook).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Design for unifying /documents and /documents/files under a single hub
with stacked Signing/Files sections, owner-grouped aggregation across
the relationship graph, and three system-managed entity-folder roots
(Clients/Companies/Yachts) with lazy per-entity subfolders. Documents
hub stays anchored on document_folders; files gain folder_id; signed
PDFs auto-deposit on Documenso completion. Includes 14+ edge-case
decisions, schema deltas, backfill plan, and implementation surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tasks 1-7 done in subagent-driven mode (11 commits 5bed62d → a0ffa1b).
The entire DB + service + API layer for folders is shipped: schema,
manage_folders perm, listTree/createFolder/renameFolder/moveFolder/
deleteFolderSoftRescue, validators, all 4 folder routes, the per-doc
move endpoint, and the listDocuments folder filter (with descendant
expansion). Reps can already manage folders end-to-end via direct
API calls.
Records the design decisions made mid-execution: hybrid storage
strategy (UUID-flat + path-style download URLs), permission split,
soft-rescue delete semantics, cycle prevention with port-scoped
ancestor walk, PATCH-body exclusivity via .strict(), and the
updatedAt bump rule (per-doc move yes, bulk soft-rescue no).
Tests at pause: 1213/1213 vitest, tsc clean. Resume prompt + task
ordering for Task 8 onwards included so a fresh session can pick up
without context.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User chose the hybrid storage strategy after reviewing the cost
analysis: storage paths stay UUID-flat (preserves the established
pattern across brochures, berth PDFs, invoices, reports, templates,
expense receipts, and the migrate-storage byte-verbatim copy), but
documents gain a path-style download URL so reps see meaningful
paths in shared links and browser tabs.
Task 18 wires the new /api/v1/documents/[id]/download/[...slug]
catch-all route + a downloadUrl field on list/detail responses.
The slug is validated for truth so a hand-edited URL with a
stale path 404s instead of silently serving the wrong file.
Task 19 is the importer the user mentioned: a one-shot script
that walks an organized legacy bucket, creates matching folder
tree + document rows pointing at existing storage keys verbatim.
Idempotent via the sibling-uniqueness index.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the audit findings from a 2026-05-03 read-only NocoDB review
plus the algorithm and migration plan for porting the legacy data
into the new client / interest / contacts / addresses model.
Highlights:
- 252 NocoDB Interests rows ≈ ~190–200 unique humans (~20–25% dup
rate). Six duplicate patterns documented from real data, including
"same person, multiple yachts" — exactly the case the new
client/interest split is designed to handle.
- Reuses the battle-tested `client-portal/server/utils/duplicate-
detection.ts` algorithm (blocking + weighted rules) with additions:
metaphone for non-English surnames, compounded confidence when
multiple rules match, negative evidence for split-signal cases.
- Three runtime surfaces (at-create suggestion, interest-level
same-berth guard, background scoring + admin review queue) plus a
one-shot migration script with --dry-run / --apply / --rollback.
- Configurable thresholds via per-port system_settings so the merge
policy can be tuned (defaults to "always confirm" — never
auto-merges out of the box).
- Reversible: every merge writes a clientMergeLog row with the
loser's full pre-state JSON, enabling 7-day undo without engineering.
Implementation decomposes into three plans (P1 library / P2 runtime /
P3 migration) sequenced after the mobile branch lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-execution baseline for the mobile foundation PR:
- Mobile audit harness (tests/e2e/audit/mobile.spec.ts + mobile-audit Playwright project) — visits every page at four anchor iPhone viewports (375/393/402/440), screenshots full-page to .audit/mobile/, generates index.md
- Design spec (docs/superpowers/specs/2026-04-29-mobile-optimization-design.md) — adaptive shell + responsive content; full active-iPhone-range coverage; foundation + per-page migration phases
- Implementation plan (docs/superpowers/plans/2026-04-29-mobile-foundation.md) — 24 TDD tasks for the foundation PR
- .gitignore: ignore /client-portal/ (legacy nested Nuxt repo) and /.audit/ (regenerable screenshots)
- Remove phantom client-portal gitlink (mode 160000 with no .gitmodules)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surveys what it actually takes to ship the AI inbox-triage feature
gated on Google Workspace integration. Walks through three deployment
models with their real costs:
- Model A (Marketplace OAuth app): 4-6 months calendar, $15k-$75k for
the required CASA security assessment, recurring re-verification
- Model B (per-customer Internal OAuth app): ~5 weeks engineering, $0
Google-side, scoped to one workspace per customer
- Model C (forward-to-CRM mailbox): ~1 week, receive-only, no reply
drafts possible
Recommends Model B for the current customer profile, with B → A
promotion only if 3+ customers ask unprompted.
Documents what's already scaffolded (email_accounts/threads/messages
tables, syncInbox stub, BullMQ email queue, ai_usage_ledger, per-port
aiEnabled flag, withRateLimit('ai')) vs what's new (OAuth flow, Pub/
Sub push receiver, gws_user_tokens + email_triage tables, /inbox UI).
End-to-end flow, schema additions, AI cost interaction with the
Phase 3b token budgets, 5-phase build plan (G1-G5), and 5 open
decisions to resolve before scheduling the build. Explicitly out of
scope: M365, sentiment analysis, smart-drafts, cross-staff triage
queue.
No code changes — this is a design doc to drive a go/no-go decision.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Full execution plan for the next phase. Closes the seven priority gaps
the 2026-04-28 Nuxt→Next audit surfaced (analytics, alerts,
interests-by-berth, expense dedup, EOI queue, OCR, audit log read view).
Scope:
- Analytics dashboard with KPI tiles, pipeline funnel, occupancy
timeline, revenue breakdown, lead-source attribution; cached via
`analytics_snapshots` recurring job.
- Alert framework: 10-rule v1 catalog, rule engine evaluates on cron,
fingerprint dedupes, auto-resolves when condition clears, surfaces
in dashboard right rail + dedicated /alerts page.
- Interests-by-berth tab on berth detail.
- Expense duplicate detection (vendor + amount + date ±3d) with
merge action.
- OCR for expense receipts via Claude Vision (Haiku 4.5 + ephemeral
system-prompt cache).
- Audit log admin read view with tsvector search + cursor pagination.
- EOI queue: saved-view tab on the documents hub.
11 PRs, ~10-13 dev days, calendar 2.5-3 weeks. Critical path
graphed. Risk register includes alert false-positive mitigation,
OCR cost ceiling via Haiku + cache, and audit-log scale.
Four open questions for the user in the spec footer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Integration tests use makePort() which writes ports with slug 'test-port-{rand}'
and never cleans up. Result: 17,564 leaked rows in dev that slowed every page
load fetching the port-switcher list (and was contributing to smoke flakes).
Adds tests/global-setup.ts with a teardown() that DELETEs every 'test-port-%'
row plus its dependent rows across 30+ tables in one CTE. Wires it into
vitest.config.ts via globalSetup. Adds closeDb() helper so the teardown can
end the postgres-js pool cleanly (kills the 'Tests closed but Vite server
won't exit' warning).
Also lands docs/superpowers/specs/2026-04-28-country-phone-timezone-design.md
— full-scope agenda for the country dropdown / E.164 phone input /
country-driven timezone autofill work, ~7 dev days across 10 PRs. Per
user request: 'let's do this full-fledged if we're gonna do it'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces yachts and companies as first-class entities with memberships,
ownership history, berth reservations, and dual-path EOI templates.
Explicit non-goals (importer, merge endpoint) carved out as Specs 2 and 3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers migrating ActivePieces inquiry flow into the CRM:
client confirmation emails, sales team notifications,
client addresses table, and admin configuration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>