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>
197 lines
8.0 KiB
Markdown
197 lines
8.0 KiB
Markdown
# 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.ts`
|
||
fetches 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/ready`
|
||
and 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_changes` table,
|
||
`/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()` honours `skipMigration` flag
|
||
|
||
### Backup management
|
||
|
||
- Real `/admin/backup` page driven by new `backup_jobs` table
|
||
- `runBackup()` service spawns `pg_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/ai` page consolidating master switch +
|
||
monthly token cap + provider credentials
|
||
- Per-feature settings (OCR, berth-PDF parser, recommender)
|
||
linked from the same page
|
||
|
||
### Onboarding
|
||
|
||
- Real `/admin/onboarding` page 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_notes`
|
||
tables (mirror marina-side shape)
|
||
- Polymorphic `notes.service.ts` extended with two new entity types
|
||
through verifyParent + listForEntity + create + update + delete
|
||
- New `<NotesList>` accepts `residential_clients` /
|
||
`residential_interests` entity 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.tsx`
|
||
built using the marina-side `DetailLayout` pattern (Overview +
|
||
Notes + Activity tabs, Interests tab on the client)
|
||
- Detail header components mirror the marina-side strip
|
||
- `useBreadcrumbHint` wired into both detail components
|
||
|
||
### Residential pipeline stages — configurable
|
||
|
||
- New `residential-stages.service.ts` with list/save + orphan-check
|
||
- `/api/v1/residential/stages` GET/PUT
|
||
- `/admin/residential-stages` admin UI with reassign-on-remove
|
||
modal (select new stage per affected interest before save)
|
||
- Validators relaxed from `z.enum(...)` to `z.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-invitation` endpoint 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 `diffEntity` to 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.
|