feat(residential-toggle): port-level module gate for Residential

Adds a `residential_module_enabled` port setting (default ON) that
hides/disables the entire Residential surface when an admin turns it
off, mirroring the Tenancies / Invoices / Expenses module-toggle
pattern. Disabling is a soft hide — residential clients/interests are
preserved and reappear on re-enable.

Surfaces gated:
- Route guard: new residential/layout.tsx renders ModuleDisabledPage
  (covers all 5 residential pages)
- Sidebar "Residential" section + mobile more-sheet tile (SSR-resolved
  residentialModuleByPort threaded layout → app-shell → sidebar)
- Global search: residential client/interest buckets early-return at
  the shared chokepoint so disabled-port records don't dead-end
- Public intake: /api/public/residential-inquiries 404s when off
- Admin Switch in settings-manager (writes via settings PUT)

Service TDD'd (residential-module.test.ts, 6 tests) plus a
disabled-port rejection test on the public endpoint. tsc + lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 18:49:16 +02:00
parent cb8292464c
commit 172af02f81
13 changed files with 380 additions and 1 deletions

View File

@@ -63,6 +63,14 @@ const KNOWN_SETTINGS: Array<{
type: 'boolean',
defaultValue: true,
},
{
key: 'residential_module_enabled',
label: 'Residential Module',
description:
'Enable the residential (non-berth) clients + interests pipeline for this port. On by default. Disabling hides the Residential section from the sidebar and mobile nav, blocks the /residential routes with a "module disabled" page, drops residential records out of global search, and stops the public residential-inquiry endpoint from accepting new leads. Previously-recorded residential clients and interests are preserved and reappear when you re-enable.',
type: 'boolean',
defaultValue: true,
},
{
key: 'ai_interest_scoring',
label: 'AI Interest Scoring',