feat(permissions): add yacht, company, membership, reservation keys

This commit is contained in:
Matt Ciaccio
2026-04-24 12:30:06 +02:00
parent b053a6388e
commit f743169354
4 changed files with 414 additions and 48 deletions

View File

@@ -1,12 +1,4 @@
import {
pgTable,
text,
boolean,
timestamp,
jsonb,
index,
uniqueIndex,
} from 'drizzle-orm/pg-core';
import { pgTable, text, boolean, timestamp, jsonb, index, uniqueIndex } from 'drizzle-orm/pg-core';
import { ports } from './ports';
// ─── Permission Types ─────────────────────────────────────────────────────────
@@ -92,6 +84,29 @@ export type RolePermissions = {
generate: boolean;
manage: boolean;
};
yachts: {
view: boolean;
create: boolean;
edit: boolean;
delete: boolean;
transfer: boolean;
};
companies: {
view: boolean;
create: boolean;
edit: boolean;
delete: boolean;
};
memberships: {
view: boolean;
manage: boolean;
};
reservations: {
view: boolean;
create: boolean;
activate: boolean;
cancel: boolean;
};
admin: {
manage_users: boolean;
view_audit_log: boolean;
@@ -132,7 +147,9 @@ export const account = pgTable('account', {
id: text('id').primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: text('user_id').notNull().references(() => user.id),
userId: text('user_id')
.notNull()
.references(() => user.id),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
@@ -163,7 +180,9 @@ export const verification = pgTable('verification', {
export const userProfiles = pgTable(
'user_profiles',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
userId: text('user_id').notNull().unique(), // references Better Auth user ID
displayName: text('display_name').notNull(),
avatarUrl: text('avatar_url'),
@@ -179,10 +198,15 @@ export const userProfiles = pgTable(
);
export const roles = pgTable('roles', {
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
name: text('name').notNull(),
description: text('description'),
permissions: jsonb('permissions').$type<RolePermissions>().notNull().default({} as RolePermissions),
permissions: jsonb('permissions')
.$type<RolePermissions>()
.notNull()
.default({} as RolePermissions),
isGlobal: boolean('is_global').notNull().default(true),
isSystem: boolean('is_system').notNull().default(false),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
@@ -192,7 +216,9 @@ export const roles = pgTable('roles', {
export const portRoleOverrides = pgTable(
'port_role_overrides',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
portId: text('port_id')
.notNull()
.references(() => ports.id, { onDelete: 'cascade' }),
@@ -215,7 +241,9 @@ export const portRoleOverrides = pgTable(
export const userPortRoles = pgTable(
'user_port_roles',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
userId: text('user_id').notNull(), // references Better Auth user ID
portId: text('port_id')
.notNull()

View File

@@ -19,82 +19,332 @@ import type { RolePermissions } from './schema/users';
const ALL_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, generate_eoi: true, export: true },
interests: {
view: true,
create: true,
edit: true,
delete: true,
change_stage: true,
generate_eoi: true,
export: true,
},
berths: { view: true, edit: true, import: true, manage_waiting_list: true },
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: 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 },
documents: {
view: true,
create: true,
send_for_signing: true,
upload_signed: true,
delete: 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,
},
files: { view: true, upload: 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 },
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 },
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: 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 },
reservations: { view: true, create: true, activate: 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: true,
},
};
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, generate_eoi: true, export: true },
interests: {
view: true,
create: true,
edit: true,
delete: true,
change_stage: true,
generate_eoi: true,
export: true,
},
berths: { view: true, edit: true, import: true, manage_waiting_list: true },
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: 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 },
documents: {
view: true,
create: true,
send_for_signing: true,
upload_signed: true,
delete: 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,
},
files: { view: true, upload: 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 },
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 },
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 },
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 },
reservations: { view: true, create: true, activate: 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,
},
};
const SALES_MANAGER_PERMISSIONS: RolePermissions = {
clients: { view: true, create: true, edit: true, delete: false, merge: true, export: true },
interests: { view: true, create: true, edit: true, delete: false, change_stage: true, generate_eoi: true, export: true },
interests: {
view: true,
create: true,
edit: true,
delete: false,
change_stage: true,
generate_eoi: true,
export: true,
},
berths: { view: true, edit: false, import: false, manage_waiting_list: true },
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: false },
expenses: { view: true, create: true, edit: true, delete: false, export: true, scan_receipt: true },
invoices: { view: true, create: true, edit: true, delete: false, send: true, record_payment: true, export: true },
documents: {
view: true,
create: true,
send_for_signing: true,
upload_signed: true,
delete: false,
},
expenses: {
view: true,
create: true,
edit: true,
delete: false,
export: true,
scan_receipt: true,
},
invoices: {
view: true,
create: true,
edit: true,
delete: false,
send: true,
record_payment: true,
export: true,
},
files: { view: true, upload: true, delete: false, 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 },
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: false },
admin: { manage_users: false, view_audit_log: false, manage_settings: false, manage_webhooks: false, manage_reports: false, manage_custom_fields: false, manage_forms: false, manage_tags: true, system_backup: false },
yachts: { view: true, create: true, edit: true, delete: false, transfer: true },
companies: { view: true, create: true, edit: true, delete: false },
memberships: { view: true, manage: true },
reservations: { view: true, create: true, activate: true, cancel: true },
admin: {
manage_users: false,
view_audit_log: false,
manage_settings: false,
manage_webhooks: false,
manage_reports: false,
manage_custom_fields: false,
manage_forms: false,
manage_tags: true,
system_backup: false,
},
};
const SALES_AGENT_PERMISSIONS: RolePermissions = {
clients: { view: true, create: true, edit: true, delete: false, merge: false, export: true },
interests: { view: true, create: true, edit: true, delete: false, change_stage: true, generate_eoi: true, export: true },
interests: {
view: true,
create: true,
edit: true,
delete: false,
change_stage: true,
generate_eoi: true,
export: true,
},
berths: { view: true, edit: false, import: false, manage_waiting_list: true },
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: false },
expenses: { view: true, create: true, edit: true, delete: false, export: true, scan_receipt: true },
invoices: { view: true, create: true, edit: true, delete: false, send: true, record_payment: true, export: true },
documents: {
view: true,
create: true,
send_for_signing: true,
upload_signed: true,
delete: false,
},
expenses: {
view: true,
create: true,
edit: true,
delete: false,
export: true,
scan_receipt: true,
},
invoices: {
view: true,
create: true,
edit: true,
delete: false,
send: true,
record_payment: true,
export: true,
},
files: { view: true, upload: true, delete: false, manage_folders: false },
email: { view: true, send: true, configure_account: true },
reminders: { view_own: true, view_all: false, create: true, edit_own: true, edit_all: false, assign_others: false },
reminders: {
view_own: true,
view_all: false,
create: true,
edit_own: true,
edit_all: false,
assign_others: false,
},
calendar: { connect: true, view_events: true },
reports: { view_dashboard: true, view_analytics: true, export: true },
document_templates: { view: true, generate: true, manage: false },
admin: { manage_users: false, view_audit_log: false, manage_settings: false, manage_webhooks: false, manage_reports: false, manage_custom_fields: false, manage_forms: false, manage_tags: true, system_backup: false },
yachts: { view: true, create: true, edit: true, delete: false, transfer: false },
companies: { view: true, create: true, edit: false, delete: false },
memberships: { view: true, manage: false },
reservations: { view: true, create: true, activate: true, cancel: false },
admin: {
manage_users: false,
view_audit_log: false,
manage_settings: false,
manage_webhooks: false,
manage_reports: false,
manage_custom_fields: false,
manage_forms: false,
manage_tags: true,
system_backup: false,
},
};
const VIEWER_PERMISSIONS: RolePermissions = {
clients: { view: true, create: false, edit: false, delete: false, merge: false, export: false },
interests: { view: true, create: false, edit: false, delete: false, change_stage: false, generate_eoi: false, export: false },
interests: {
view: true,
create: false,
edit: false,
delete: false,
change_stage: false,
generate_eoi: false,
export: false,
},
berths: { view: true, edit: false, import: false, manage_waiting_list: false },
documents: { view: true, create: false, send_for_signing: false, upload_signed: false, delete: false },
expenses: { view: true, create: false, edit: false, delete: false, export: false, scan_receipt: false },
invoices: { view: true, create: false, edit: false, delete: false, send: false, record_payment: false, export: false },
documents: {
view: true,
create: false,
send_for_signing: false,
upload_signed: false,
delete: false,
},
expenses: {
view: true,
create: false,
edit: false,
delete: false,
export: false,
scan_receipt: false,
},
invoices: {
view: true,
create: false,
edit: false,
delete: false,
send: false,
record_payment: false,
export: false,
},
files: { view: true, upload: false, delete: false, manage_folders: false },
email: { view: true, send: false, configure_account: false },
reminders: { view_own: true, view_all: false, create: false, edit_own: false, edit_all: false, assign_others: false },
reminders: {
view_own: true,
view_all: false,
create: false,
edit_own: false,
edit_all: false,
assign_others: false,
},
calendar: { connect: false, view_events: true },
reports: { view_dashboard: true, view_analytics: false, export: false },
document_templates: { view: true, generate: false, manage: false },
admin: { manage_users: false, view_audit_log: false, manage_settings: false, manage_webhooks: false, manage_reports: false, manage_custom_fields: false, manage_forms: false, manage_tags: false, system_backup: false },
yachts: { view: true, create: false, edit: false, delete: false, transfer: false },
companies: { view: true, create: false, edit: false, delete: false },
memberships: { view: true, manage: false },
reservations: { view: true, create: false, activate: false, cancel: false },
admin: {
manage_users: false,
view_audit_log: false,
manage_settings: false,
manage_webhooks: false,
manage_reports: false,
manage_custom_fields: false,
manage_forms: false,
manage_tags: false,
system_backup: false,
},
};
// ─── Seed Function ────────────────────────────────────────────────────────────
@@ -158,7 +408,8 @@ async function seed() {
{
id: crypto.randomUUID(),
name: 'sales_agent',
description: 'Standard sales role. View/create/edit clients and interests, manage own reminders.',
description:
'Standard sales role. View/create/edit clients and interests, manage own reminders.',
permissions: SALES_AGENT_PERMISSIONS,
isGlobal: true,
isSystem: true,