refactor: scope dashboard records by organization
Attach clients, rooms, services, bookings, contacts, addresses, invoices, and contracts to organizations. Filter dashboard loads and related option lists by the active organization from the session. Ensure create, update, and archive actions only affect records in the active organization.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { clients } from './clients.schema';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const addresses = sqliteTable(
|
||||
@@ -8,6 +9,9 @@ export const addresses = sqliteTable(
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
clientId: text('client_id')
|
||||
.notNull()
|
||||
.references(() => clients.id, { onDelete: 'restrict' }),
|
||||
@@ -21,5 +25,8 @@ export const addresses = sqliteTable(
|
||||
isPrimary: integer('is_primary', { mode: 'boolean' }).notNull().default(false),
|
||||
...timestamps
|
||||
},
|
||||
(table) => [index('addresses_client_id_idx').on(table.clientId)]
|
||||
(table) => [
|
||||
index('addresses_organization_id_idx').on(table.organizationId),
|
||||
index('addresses_client_id_idx').on(table.clientId)
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { index, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { clients } from './clients.schema';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { rooms } from './rooms.schema';
|
||||
import { services } from './services.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
@@ -10,6 +11,9 @@ export const bookings = sqliteTable(
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
clientId: text('client_id')
|
||||
.notNull()
|
||||
.references(() => clients.id, { onDelete: 'restrict' }),
|
||||
@@ -24,6 +28,7 @@ export const bookings = sqliteTable(
|
||||
...timestamps
|
||||
},
|
||||
(table) => [
|
||||
index('bookings_organization_id_idx').on(table.organizationId),
|
||||
index('bookings_client_id_idx').on(table.clientId),
|
||||
index('bookings_room_id_idx').on(table.roomId),
|
||||
index('bookings_service_id_idx').on(table.serviceId)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { text, sqliteTable } from 'drizzle-orm/sqlite-core';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const clients = sqliteTable('clients', {
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
name: text('name').notNull(),
|
||||
type: text('type').notNull().default('business'),
|
||||
status: text('status').notNull().default('active'),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { clients } from './clients.schema';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const contacts = sqliteTable(
|
||||
@@ -8,6 +9,9 @@ export const contacts = sqliteTable(
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
clientId: text('client_id')
|
||||
.notNull()
|
||||
.references(() => clients.id, { onDelete: 'restrict' }),
|
||||
@@ -19,5 +23,8 @@ export const contacts = sqliteTable(
|
||||
notes: text('notes'),
|
||||
...timestamps
|
||||
},
|
||||
(table) => [index('contacts_client_id_idx').on(table.clientId)]
|
||||
(table) => [
|
||||
index('contacts_organization_id_idx').on(table.organizationId),
|
||||
index('contacts_client_id_idx').on(table.clientId)
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { index, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { clients } from './clients.schema';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const contracts = sqliteTable(
|
||||
@@ -8,6 +9,9 @@ export const contracts = sqliteTable(
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
clientId: text('client_id')
|
||||
.notNull()
|
||||
.references(() => clients.id, { onDelete: 'restrict' }),
|
||||
@@ -19,5 +23,8 @@ export const contracts = sqliteTable(
|
||||
notes: text('notes'),
|
||||
...timestamps
|
||||
},
|
||||
(table) => [index('contracts_client_id_idx').on(table.clientId)]
|
||||
(table) => [
|
||||
index('contracts_organization_id_idx').on(table.organizationId),
|
||||
index('contracts_client_id_idx').on(table.clientId)
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { index, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { clients } from './clients.schema';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const invoices = sqliteTable(
|
||||
@@ -8,6 +9,9 @@ export const invoices = sqliteTable(
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
clientId: text('client_id')
|
||||
.notNull()
|
||||
.references(() => clients.id, { onDelete: 'restrict' }),
|
||||
@@ -21,5 +25,8 @@ export const invoices = sqliteTable(
|
||||
notes: text('notes'),
|
||||
...timestamps
|
||||
},
|
||||
(table) => [index('invoices_client_id_idx').on(table.clientId)]
|
||||
(table) => [
|
||||
index('invoices_organization_id_idx').on(table.organizationId),
|
||||
index('invoices_client_id_idx').on(table.clientId)
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { integer, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const rooms = sqliteTable('rooms', {
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
name: text('name').notNull(),
|
||||
type: text('type').notNull().default('meeting_room'),
|
||||
sqFt: integer('sq_ft'),
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { organizations } from './organizations.schema';
|
||||
import { timestamps } from './shared.schema';
|
||||
|
||||
export const services = sqliteTable('services', {
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
organizationId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => organizations.id, { onDelete: 'restrict' }),
|
||||
name: text('name').notNull(),
|
||||
category: text('category'),
|
||||
unit: text('unit').notNull().default('each'),
|
||||
|
||||
Reference in New Issue
Block a user