diff --git a/docs/runbooks/permission-audit.md b/docs/runbooks/permission-audit.md index 5e29c75d..31914786 100644 --- a/docs/runbooks/permission-audit.md +++ b/docs/runbooks/permission-audit.md @@ -28,7 +28,6 @@ Scanned 182 route files under `src/app/api/v1/`. | `src/app/api/v1/alerts/[id]/dismiss/route.ts` | POST | Alerts are user-scoped; port-filtered via auth context. | | `src/app/api/v1/alerts/count/route.ts` | GET | Alerts are user-scoped; port-filtered via auth context. | | `src/app/api/v1/alerts/route.ts` | GET | Alerts are user-scoped; port-filtered via auth context. | -| `src/app/api/v1/berth-reservations/[id]/route.ts` | PATCH | TODO: PATCH should map to reservations:edit (not currently in catalog). | | `src/app/api/v1/currency/convert/route.ts` | POST | Currency reference data; port-scoped, no PII. | | `src/app/api/v1/currency/rates/refresh/route.ts` | POST | TODO: gate with admin:manage_settings — currently allow-listed. | | `src/app/api/v1/currency/rates/route.ts` | GET | Currency reference data; port-scoped, no PII. | diff --git a/docs/tenancies-design.md b/docs/tenancies-design.md index 4a2719c8..0d561cce 100644 --- a/docs/tenancies-design.md +++ b/docs/tenancies-design.md @@ -237,7 +237,7 @@ The `tenancies_module` integration check resolves to `tenancies_module_enabled = ## Service layer additions -`src/lib/services/tenancies.service.ts` (renamed from `berth-reservations.service.ts`): +`src/lib/services/berth-tenancies.service.ts` (renamed from `berth-reservations.service.ts`): - `listTenancies({ portId, filters, page })` — gated read. - `createTenancy(portId, data, meta)` — mints a row; also triggers the module-enable flip on first insert. diff --git a/scripts/audit-permissions.ts b/scripts/audit-permissions.ts index d1ca64e3..0431c041 100644 --- a/scripts/audit-permissions.ts +++ b/scripts/audit-permissions.ts @@ -73,10 +73,6 @@ const ALLOW_LIST: ReadonlyArray<{ pattern: RegExp; reason: string }> = [ pattern: /\/custom-fields\/\[entityId\]\//, reason: 'TODO: needs custom_fields:* permission. PUT path internally validated.', }, - { - pattern: /\/berth-reservations\/\[id\]\/route\.ts$/, - reason: 'TODO: PATCH should map to reservations:edit (not currently in catalog).', - }, ]; interface Finding { diff --git a/src/app/(dashboard)/[portSlug]/admin/import/page.tsx b/src/app/(dashboard)/[portSlug]/admin/import/page.tsx index 592344df..8a3318df 100644 --- a/src/app/(dashboard)/[portSlug]/admin/import/page.tsx +++ b/src/app/(dashboard)/[portSlug]/admin/import/page.tsx @@ -62,7 +62,7 @@ export default function DataImportPage() {
  • Dry-run preview that shows new vs. matched-existing rows before commit.
  • Conflict-resolution choices (skip, update, dedup-by-email) per import type.
  • Per-port import history with rollback.
  • -
  • Templates for clients, yachts, companies, berths, reservations, expenses.
  • +
  • Templates for clients, yachts, companies, berths, tenancies, expenses.
  • Imports run against the BullMQ import queue (concurrency 1) so partial diff --git a/src/app/api/v1/admin/users/[id]/permission-overrides/route.ts b/src/app/api/v1/admin/users/[id]/permission-overrides/route.ts index 374f05cc..0e5915c7 100644 --- a/src/app/api/v1/admin/users/[id]/permission-overrides/route.ts +++ b/src/app/api/v1/admin/users/[id]/permission-overrides/route.ts @@ -67,7 +67,7 @@ const ALLOWED_RESOURCE_ACTIONS: Record> = { yachts: new Set(['view', 'create', 'edit', 'delete', 'transfer']), companies: new Set(['view', 'create', 'edit', 'delete']), memberships: new Set(['view', 'manage']), - reservations: new Set(['view', 'create', 'activate', 'cancel']), + tenancies: new Set(['view', 'manage', 'cancel']), admin: new Set([ 'manage_users', 'view_audit_log', diff --git a/src/components/admin/admin-sections-browser.tsx b/src/components/admin/admin-sections-browser.tsx index 7168dbfb..7edcf417 100644 --- a/src/components/admin/admin-sections-browser.tsx +++ b/src/components/admin/admin-sections-browser.tsx @@ -189,7 +189,7 @@ const GROUPS: AdminGroup[] = [ { href: 'custom-fields', label: 'Custom Fields', - description: 'Tenant-defined fields for clients, yachts, and reservations.', + description: 'Tenant-defined fields for clients, yachts, and tenancies.', icon: SlidersHorizontal, }, { @@ -261,7 +261,7 @@ const GROUPS: AdminGroup[] = [ { href: 'import', label: 'Bulk Import', - description: 'CSV-driven imports for clients, yachts, and reservations.', + description: 'CSV-driven imports for clients, yachts, and tenancies.', icon: FileUp, }, { diff --git a/src/components/clients/bulk-archive-wizard.tsx b/src/components/clients/bulk-archive-wizard.tsx index 54ab030c..e92d5d83 100644 --- a/src/components/clients/bulk-archive-wizard.tsx +++ b/src/components/clients/bulk-archive-wizard.tsx @@ -170,7 +170,7 @@ function BulkArchiveWizardBody({ open, onOpenChange, clientIds, onSuccess }: Pro

    Low-stakes defaults: release available/under-offer berths, keep sold ones, cancel - reservations, leave invoices/signing requests alone. Yachts stay on the archived + tenancies, leave invoices/signing requests alone. Yachts stay on the archived client. To customise per-client, archive that client individually instead.
    diff --git a/src/components/clients/bulk-hard-delete-dialog.tsx b/src/components/clients/bulk-hard-delete-dialog.tsx index 9ba1ea89..a88a5d0b 100644 --- a/src/components/clients/bulk-hard-delete-dialog.tsx +++ b/src/components/clients/bulk-hard-delete-dialog.tsx @@ -128,8 +128,8 @@ function BulkHardDeleteDialogBody({ onOpenChange, clientIds, onDeleted }: Props)

    For each client we delete: client record + addresses, contacts, notes, tags, portal - user, GDPR records, all interests, all reservations. Signed documents, email threads, - files and reminders are detached but kept. + user, GDPR records, all interests, all tenancies. Signed documents, email threads, files + and reminders are detached but kept.
    )} diff --git a/src/components/clients/client-detail.tsx b/src/components/clients/client-detail.tsx index 38961a5e..ecaa9a9d 100644 --- a/src/components/clients/client-detail.tsx +++ b/src/components/clients/client-detail.tsx @@ -114,6 +114,7 @@ export function ClientDetail({ clientId, currentUserId }: ClientDetailProps) { 'yacht:ownership_transferred': [['clients', clientId]], 'company_membership:added': [['clients', clientId]], 'company_membership:ended': [['clients', clientId]], + 'berth_tenancy:created': [['clients', clientId]], 'berth_tenancy:activated': [['clients', clientId]], 'berth_tenancy:ended': [['clients', clientId]], 'berth_tenancy:cancelled': [['clients', clientId]], diff --git a/src/components/clients/gdpr-export-button.tsx b/src/components/clients/gdpr-export-button.tsx index 57bb965e..fe11ec70 100644 --- a/src/components/clients/gdpr-export-button.tsx +++ b/src/components/clients/gdpr-export-button.tsx @@ -120,7 +120,7 @@ export function GdprExportButton({ clientId }: { clientId: string }) { Personal data export Bundles every record we hold about this client (profile, contacts, addresses, yachts, - companies, interests, reservations, invoices, documents, audit log) into a ZIP with JSON + companies, interests, tenancies, invoices, documents, audit log) into a ZIP with JSON and HTML copies. Used to satisfy GDPR Article 15 access requests. diff --git a/src/components/clients/hard-delete-dialog.tsx b/src/components/clients/hard-delete-dialog.tsx index aa242b42..f17f4959 100644 --- a/src/components/clients/hard-delete-dialog.tsx +++ b/src/components/clients/hard-delete-dialog.tsx @@ -114,7 +114,7 @@ function HardDeleteDialogBody({ onOpenChange, clientId, clientName, onDeleted }:

    What is preserved