Six audit documents capture the 2026-05-06 review pass (comprehensive, frontend, missing-features, permissions, reliability) along with the Documenso integration audit + locked build plan that drove the bulk of subsequent feature work. Adds `docs/admin-ux-backlog.md` as a living tracker for the autonomous push — every item marked DONE or REMAINING with file pointers and scope estimates so future sessions can pick up where this one stopped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.0 KiB
Admin / settings UX backlog — STATUS
Living tracker for the admin/UX backlog. Items are marked DONE or REMAINING based on what landed in the autonomous-push session.
DONE in the autonomous push
Foundations
- Currency API verified end-to-end.
scripts/test-currency-api.tsfetches live Frankfurter rates → upserts → reads back → converts. Inverse-rate drift confirmed at ≤0.001. - Storage abstraction audit complete. Every byte path
(signed EOIs, contracts, brochures, berth PDFs, files, avatars,
branding logos) goes through
getStorageBackend()./api/readyand the system-monitoring health probe now check the active backend (S3 or filesystem) instead of always probing MinIO.
User settings
- Country + Timezone selectors with cross-defaulting + auto-detect banner ("Looks like you're in Europe/Paris — Update?")
- Email change with verification flow (
user_email_changestable,/api/v1/me/email/confirm/<token>,/api/v1/me/email/cancel/<token>) - Password reset triggered via better-auth
requestPasswordReset - Profile photo upload + crop (square 256×256) via shared
<ImageCropperDialog>+/api/v1/me/avatar
Branding
- Logo upload + crop modal in admin/branding (uses the same shared
cropper, persists via
/api/v1/admin/settings/image→ storage backend) - Email header/footer HTML defaults injectable via "Insert default" button
- Brand colour picker, app-name field, logo URL all in one card
Storage admin
- New layout: S3 config form FIRST, swap action SECOND
- Test connection button before any switch
- Two-button switch: "Switch + migrate" vs "Switch only" with warning modal
runMigration()honoursskipMigrationflag
Backup management
- Real
/admin/backuppage driven by newbackup_jobstable runBackup()service spawnspg_dump --format=custom, streams to active storage backend, records size + path- Download button presigns the .dump for offline restore
- Super-admin gated
AI admin panel
- Dedicated
/admin/aipage consolidating master switch + monthly token cap + provider credentials - Per-feature settings (OCR, berth-PDF parser, recommender) linked from the same page
Onboarding
- Real
/admin/onboardingpage with auto-checked steps - Reads each setting key + lists endpoint (roles / users / tags) to decide completion
- Manual checkboxes for steps without an auto-detect signal
- Progress bar + "Mark done"/"Mark incomplete" buttons
- State persisted in
system_settings.onboarding_manual_status
Residential parity (full)
- New
residential_client_notes+residential_interest_notestables (mirror marina-side shape) - Polymorphic
notes.service.tsextended with two new entity types through verifyParent + listForEntity + create + update + delete - New
<NotesList>acceptsresidential_clients/residential_interestsentity types - Activity endpoints:
/api/v1/residential/clients/[id]/activity+/api/v1/residential/interests/[id]/activity - Notes endpoints: 4 new routes covering GET/POST/PATCH/DELETE
residential-client-tabs.tsx+residential-interest-tabs.tsxbuilt using the marina-sideDetailLayoutpattern (Overview + Notes + Activity tabs, Interests tab on the client)- Detail header components mirror the marina-side strip
useBreadcrumbHintwired into both detail components
Residential pipeline stages — configurable
- New
residential-stages.service.tswith list/save + orphan-check /api/v1/residential/stagesGET/PUT/admin/residential-stagesadmin UI with reassign-on-remove modal (select new stage per affected interest before save)- Validators relaxed from
z.enum(...)toz.string()so any admin-defined stage id round-trips
Documenso Phase 1 (EOI generate flow polish)
- Schema migrations applied:
document_signers.invited_at / opened_at / last_reminder_sent_at / signing_token,documents.completion_cc_emails / auto_reminder_interval_days transformSigningUrl()now maps SignerRole → URL segment correctly (approver→cc, witness→witness) so emails don't land on/sign/error- New
POST /api/v1/documents/[id]/send-invitationendpoint with next-pending-signer auto-pick - Per-port settings added:
documenso_developer_label,documenso_approver_label,documenso_developer_user_id,documenso_approver_user_id(Phase 7 RBAC binding fields)
Misc UI/UX
- Sidebar collapse removed (always expanded)
- Audit log filter inputs sized + dates widened
- Custom Settings section got a long-form description
- Reminder digest timezone uses
TimezoneCombobox - Port form: currency dropdown + timezone combobox + brand color
- Permissions count badge opens a modal with granted/denied
- Role names display-normalized via
prettifyRoleName - Sales email config: token list + tooltips on threshold + body fields
- Custom Fields page: amber heads-up about non-integration with search / recommender / audit / merge tokens
- Tag form: native
<input type="color"> - FilterBar Select crash fixed (no empty-string item values)
REMAINING — large pieces that didn't fit this push
1. Documenso Phase 2 — Webhook handler enhancement (~3-4 hours)
Cascading "your turn" emails when each signer completes; on-completion
PDF distribution; token-based recipient matching; idempotency lock.
File to extend: src/app/api/webhooks/documenso/route.ts. The
schema columns are already in place (Phase 1).
2. Documenso Phase 3 — Custom doc upload-to-Documenso (~6-8 hours)
Backend service custom-document-upload.service.ts + endpoint
POST /api/v1/interests/[id]/upload-for-signing. Accepts a PDF +
recipient list + field-placement JSON, calls createDocument →
placeFields → sendDocument on the per-port Documenso client.
Persists a row in documents table.
3. Documenso Phase 4 — Field placement UI (~10-14 hours)
The biggest piece. Needs:
- 4a: Recipient configurator dialog (~2-3h)
- 4b: PDF rendering with
react-pdf(~3-4h) - 4c: Auto-detect anchor scanner via
pdfjs-dist.getTextContent(~4-6h) - 4d: Drag-drop overlay using
dnd-kit(~3-4h) - 4e: Send button → calls Phase 3 endpoint (~1h)
Plan locked in docs/documenso-build-plan.md Phase 4 — the
field-detector regexes, the anchor patterns, and the type-to-bbox
sizing table are all spelled out.
4. Documenso Phase 5 — Embedded signing URL emission verification (~1-2 hours)
Verify the website's /sign/<type>/<token> page handles every signer
role + every documentType combination. Update website's
signerMessages map keyed on (documentType, role). Apply the
nginx CORS block from docs/documenso-integration-audit.md.
5. Documenso Phase 6 — Polish items (deferred)
Auto-send delay, audit-log additions, per-document customisation, document expiration, reminder rate-limit display, failed-webhook recovery UI. Each ~2-3 hours; all deferred until Phases 1-4 ship.
6. Project Director — UI binding for the developer-user fields
Schema + setting keys are now in place
(documenso_developer_user_id, documenso_approver_user_id +
documenso_developer_label / _approver_label). The remaining
work is: add a "Linked to CRM user" dropdown in
/admin/documenso/page.tsx that lists port users; when bound,
auto-fill name/email from the user profile and mark name/email
fields read-only. Webhook handler can then match against the
linked user's email for in-CRM signing-status updates.
7. Custom-fields hardening (~ongoing)
Remediation paths for the heads-up banner concerns:
- Search index: extend the GIN tsvector to include customFieldValues content
- Audit diff: extend
diffEntityto walk the customFieldValues blob - Merge tokens: add
{{custom.<fieldName>}}handling at template-render time, plus surface them in the merge-tokens UI
8. Documenso v2 webhook payload audit (small)
Risk #4 from docs/documenso-build-plan.md — confirm v2 payload
shape (payload.documentId vs payload.id, recipient.token vs
recipient.recipientId) against a live v2 instance before relying
on Phase 2 cascading emails.