feat(admin): single Sales role, welcome-email password setup, Director=sales
All checks were successful
Build & Push Docker Images / lint (push) Successful in 3m5s
Build & Push Docker Images / build-and-push (push) Successful in 9m24s

- Collapse the two sales roles in the create-user dropdown to one "Sales"
  (sales_manager relabelled). Hide super_admin + sales_agent from selection
  via NON_ASSIGNABLE_ROLE_NAMES; the form keeps a user's *current* role even
  if hidden so existing assignments stay editable.
- Director becomes a senior-title twin of Sales: DIRECTOR_PERMISSIONS now
  equals SALES_MANAGER_PERMISSIONS (no admin/settings — Super-Admin only).
  Migration 0097 updates the existing global director row (idempotent,
  data-only; 0 users assigned on prod, so no blast radius).
- Admin create-user defaults to emailing a set-password link instead of an
  inline password (manual entry still available via a toggle). createUserSchema:
  password optional + sendSetupEmail; createUser provisions with a throwaway
  password then triggers the set-password email.
- New users get a dedicated, unique WELCOME email (crmWelcomeEmail), not the
  self-service "reset your password" email. A pending-welcome flag routes the
  shared better-auth sendResetPassword callback via account-setup-email.ts.
- Phone confirmed already optional for staff accounts (no change needed).

Tests: +welcome-routing, +create-user-setup; permission-matrix director block
realigned to no-admin. 1662 vitest pass; tsc + eslint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 12:40:55 +02:00
parent 5b9560531e
commit 93989b1e1d
16 changed files with 593 additions and 156 deletions

View File

@@ -98,92 +98,10 @@ export const ALL_PERMISSIONS: RolePermissions = {
},
};
export const DIRECTOR_PERMISSIONS: RolePermissions = {
clients: { view: true, create: true, edit: true, delete: true, merge: true, export: true },
interests: {
view: true,
create: true,
edit: true,
delete: true,
change_stage: true,
override_stage: true,
generate_eoi: true,
export: true,
},
berths: { view: true, edit: true, import: true, manage_waiting_list: true, update_prices: true },
documents: {
view: true,
create: true,
edit: true,
send_for_signing: true,
upload_signed: true,
delete: true,
manage_folders: true,
},
expenses: {
view: true,
create: true,
edit: true,
delete: true,
export: true,
scan_receipt: true,
},
invoices: {
view: true,
create: true,
edit: true,
delete: true,
send: true,
record_payment: true,
export: true,
},
payments: { view: true, record: true, delete: true },
files: { view: true, upload: true, edit: true, delete: true, manage_folders: true },
email: { view: true, send: true, configure_account: true },
reminders: {
view_own: true,
view_all: true,
create: true,
edit_own: true,
edit_all: true,
assign_others: true,
},
calendar: { connect: true, view_events: true },
reports: { view_dashboard: true, view_analytics: true, export: true },
document_templates: { view: true, generate: true, manage: true },
yachts: { view: true, create: true, edit: true, delete: true, transfer: true },
companies: { view: true, create: true, edit: true, delete: true },
memberships: { view: true, manage: true },
tenancies: { view: true, manage: true, cancel: true },
admin: {
manage_users: true,
view_audit_log: true,
manage_settings: true,
manage_webhooks: true,
manage_reports: true,
manage_custom_fields: true,
manage_forms: true,
manage_tags: true,
system_backup: false,
permanently_delete_clients: false,
},
residential_clients: { view: true, create: true, edit: true, delete: true },
residential_interests: {
view: true,
create: true,
edit: true,
delete: true,
change_stage: true,
},
inquiries: {
view: true,
manage: true,
},
client_groups: {
view: true,
manage: true,
},
};
// DIRECTOR_PERMISSIONS is defined just below SALES_MANAGER_PERMISSIONS — it is a
// senior-title twin of the single "Sales" role with identical capabilities and
// no admin/settings access (reserved for Super Admin). Kept there so it can
// reference the sales map directly.
export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
clients: { view: true, create: true, edit: true, delete: false, merge: true, export: true },
@@ -272,6 +190,11 @@ export const SALES_MANAGER_PERMISSIONS: RolePermissions = {
},
};
// Director is now a senior-title twin of the single "Sales" role: identical
// capabilities, no admin/settings access (admin stays Super-Admin-only). It
// remains a distinct, selectable role purely so the title can differ.
export const DIRECTOR_PERMISSIONS: RolePermissions = SALES_MANAGER_PERMISSIONS;
export const SALES_AGENT_PERMISSIONS: RolePermissions = {
clients: { view: true, create: true, edit: true, delete: false, merge: false, export: true },
interests: {