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