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.
|