feat(admin): inquiry inbox, send log, email-template overrides, reports dashboard, recommender keys, role-editor coverage; replace placeholder pages
Closes the bulk of audit-pass-#1 admin gaps in one batch. New admin pages: - /admin/inquiries reads website_submissions with filter chips for berth/residence/contact + payload viewer per row. - /admin/sends reads document_sends with sent/failed filter chips and expandable body markdown; failures surface errorReason and any fallback-to-link reason from the SMTP retry. - /admin/email-templates lets per-port admins override the subject of each transactional template (8 templates catalogued in template-catalog.ts). Body editing is a follow-on; portal_activation + portal_reset are wired to honor the override via loadSubjectOverride. - /admin/reports replaces the "Coming in Layer 3" placeholder with a KPI dashboard: 4 KPI tiles, pipeline funnel bars, berth occupancy donut-bars, conversion %, refresh every 60s. - backup/import/onboarding admin pages replace placeholders with actionable guidance: backup posture + planned features, available CLI imports + planned UI, ordered onboarding checklist linking to admin pages. Existing pages widened: - settings-manager exposes the 9 berth-recommender tunables that were previously code-only (recommender_*, heat_weight_*, fallthrough_*, tier_ladder_hide_late_stage). - role-form covers all 19 RolePermissions schema groups; previously missing yachts/companies/memberships/reservations + missing documents.edit + files.edit checkboxes. snake_case residential labels replaced with friendly text. portal-auth.service.ts now also writes audit_log rows for portal invite, resend, activate, password-reset request, and reset (closes one more audit-pass-#2 gap while we were touching the file). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -118,6 +118,77 @@ const KNOWN_SETTINGS: Array<{
|
||||
approver: { name: 'Abbie May', email: 'sales@portnimara.com' },
|
||||
},
|
||||
},
|
||||
// ─── Berth recommender (src/lib/services/berth-recommender.service.ts) ──────
|
||||
{
|
||||
key: 'recommender_max_oversize_pct',
|
||||
label: 'Recommender — max oversize %',
|
||||
description:
|
||||
'Cap on how much larger a berth can be than the desired length/width/draft before it stops being suggested. Default 30.',
|
||||
type: 'number',
|
||||
defaultValue: 30,
|
||||
},
|
||||
{
|
||||
key: 'recommender_top_n_default',
|
||||
label: 'Recommender — default result count',
|
||||
description: 'Default number of berth recommendations returned per request. Default 8.',
|
||||
type: 'number',
|
||||
defaultValue: 8,
|
||||
},
|
||||
{
|
||||
key: 'fallthrough_policy',
|
||||
label: 'Recommender — fall-through policy',
|
||||
description:
|
||||
'How berths re-enter the recommender after a lost deal. One of: immediate_with_heat, cooldown, never_auto_recommend.',
|
||||
type: 'string',
|
||||
defaultValue: 'immediate_with_heat',
|
||||
},
|
||||
{
|
||||
key: 'fallthrough_cooldown_days',
|
||||
label: 'Recommender — fall-through cooldown (days)',
|
||||
description:
|
||||
'Days a berth stays out of the recommender after a lost deal when the policy is `cooldown`. Default 30.',
|
||||
type: 'number',
|
||||
defaultValue: 30,
|
||||
},
|
||||
{
|
||||
key: 'heat_weight_recency',
|
||||
label: 'Heat weight — recency',
|
||||
description: 'Weight given to how recently the prior interest fell through. Default 30.',
|
||||
type: 'number',
|
||||
defaultValue: 30,
|
||||
},
|
||||
{
|
||||
key: 'heat_weight_furthest_stage',
|
||||
label: 'Heat weight — furthest stage',
|
||||
description:
|
||||
'Weight given to how close the prior interest got to closing before falling through. Default 40.',
|
||||
type: 'number',
|
||||
defaultValue: 40,
|
||||
},
|
||||
{
|
||||
key: 'heat_weight_interest_count',
|
||||
label: 'Heat weight — historical interest count',
|
||||
description:
|
||||
'Weight given to how often this berth has attracted interest historically. Default 15.',
|
||||
type: 'number',
|
||||
defaultValue: 15,
|
||||
},
|
||||
{
|
||||
key: 'heat_weight_eoi_count',
|
||||
label: 'Heat weight — historical EOI count',
|
||||
description:
|
||||
'Weight given to how often interest in this berth has reached EOI signing. Default 15.',
|
||||
type: 'number',
|
||||
defaultValue: 15,
|
||||
},
|
||||
{
|
||||
key: 'tier_ladder_hide_late_stage',
|
||||
label: 'Recommender — hide late-stage tier',
|
||||
description:
|
||||
'Hide berths whose only active interests are late-stage (close to closing) from recommendations.',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function SettingsManager() {
|
||||
|
||||
Reference in New Issue
Block a user