diff --git a/src/lib/server/db/addresses.schema.ts b/src/lib/server/db/addresses.schema.ts index 308954b..a097a10 100644 --- a/src/lib/server/db/addresses.schema.ts +++ b/src/lib/server/db/addresses.schema.ts @@ -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) + ] ); diff --git a/src/lib/server/db/bookings.schema.ts b/src/lib/server/db/bookings.schema.ts index aa709b5..67baec5 100644 --- a/src/lib/server/db/bookings.schema.ts +++ b/src/lib/server/db/bookings.schema.ts @@ -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) diff --git a/src/lib/server/db/clients.schema.ts b/src/lib/server/db/clients.schema.ts index c251055..1105ea6 100644 --- a/src/lib/server/db/clients.schema.ts +++ b/src/lib/server/db/clients.schema.ts @@ -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'), diff --git a/src/lib/server/db/contacts.schema.ts b/src/lib/server/db/contacts.schema.ts index 0198b58..ce18e50 100644 --- a/src/lib/server/db/contacts.schema.ts +++ b/src/lib/server/db/contacts.schema.ts @@ -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) + ] ); diff --git a/src/lib/server/db/contracts.schema.ts b/src/lib/server/db/contracts.schema.ts index be75044..5708061 100644 --- a/src/lib/server/db/contracts.schema.ts +++ b/src/lib/server/db/contracts.schema.ts @@ -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) + ] ); diff --git a/src/lib/server/db/invoices.schema.ts b/src/lib/server/db/invoices.schema.ts index 97056b2..d8ae2f4 100644 --- a/src/lib/server/db/invoices.schema.ts +++ b/src/lib/server/db/invoices.schema.ts @@ -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) + ] ); diff --git a/src/lib/server/db/rooms.schema.ts b/src/lib/server/db/rooms.schema.ts index b5c119e..e02f396 100644 --- a/src/lib/server/db/rooms.schema.ts +++ b/src/lib/server/db/rooms.schema.ts @@ -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'), diff --git a/src/lib/server/db/services.schema.ts b/src/lib/server/db/services.schema.ts index 55cad37..a65e80d 100644 --- a/src/lib/server/db/services.schema.ts +++ b/src/lib/server/db/services.schema.ts @@ -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'), diff --git a/src/routes/dashboard/+layout.svelte b/src/routes/dashboard/+layout.svelte index f2a1caa..b10aa25 100644 --- a/src/routes/dashboard/+layout.svelte +++ b/src/routes/dashboard/+layout.svelte @@ -5,7 +5,7 @@ import { Separator } from '$lib/components/ui/separator/index.js'; import * as Sidebar from '$lib/components/ui/sidebar/index.js'; - const { children } = $props(); + const { data, children } = $props(); type BreadcrumbItem = { label: string; @@ -79,7 +79,7 @@ - +
diff --git a/src/routes/dashboard/addresses/+page.server.ts b/src/routes/dashboard/addresses/+page.server.ts index e0f44aa..c255305 100644 --- a/src/routes/dashboard/addresses/+page.server.ts +++ b/src/routes/dashboard/addresses/+page.server.ts @@ -1,16 +1,17 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { addresses, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -18,22 +19,24 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(addresses) - .where(isNull(addresses.archivedAt)) + .where(and(eq(addresses.organizationId, activeOrganizationId), isNull(addresses.archivedAt))) .orderBy(asc(addresses.label)); return { records, - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), archiveForm: await superValidate(zod4(archiveSchema), { id: 'addresses-archive' }) }; }; export const actions: Actions = { archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'addresses-archive' }); if (!form.valid) return message(form, 'Address id is required.', { status: 400 }); @@ -41,7 +44,9 @@ export const actions: Actions = { await db .update(addresses) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(addresses.id, form.data.id)); + .where( + and(eq(addresses.id, form.data.id), eq(addresses.organizationId, activeOrganizationId)) + ); return message(form, 'Address archived.'); } diff --git a/src/routes/dashboard/bookings/+page.server.ts b/src/routes/dashboard/bookings/+page.server.ts index 836dfca..f00fd82 100644 --- a/src/routes/dashboard/bookings/+page.server.ts +++ b/src/routes/dashboard/bookings/+page.server.ts @@ -1,27 +1,28 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { bookings, clients, rooms, services } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const [clientRows, roomRows, serviceRows] = await Promise.all([ db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)), db .select({ id: rooms.id, name: rooms.name }) .from(rooms) - .where(isNull(rooms.archivedAt)) + .where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt))) .orderBy(asc(rooms.name)), db .select({ id: services.id, name: services.name }) .from(services) - .where(isNull(services.archivedAt)) + .where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt))) .orderBy(asc(services.name)) ]); @@ -35,22 +36,24 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(bookings) - .where(isNull(bookings.archivedAt)) + .where(and(eq(bookings.organizationId, activeOrganizationId), isNull(bookings.archivedAt))) .orderBy(asc(bookings.startsAt)); return { records, - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), archiveForm: await superValidate(zod4(archiveSchema), { id: 'bookings-archive' }) }; }; export const actions: Actions = { archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'bookings-archive' }); if (!form.valid) return message(form, 'Booking id is required.', { status: 400 }); @@ -58,7 +61,7 @@ export const actions: Actions = { await db .update(bookings) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(bookings.id, form.data.id)); + .where(and(eq(bookings.id, form.data.id), eq(bookings.organizationId, activeOrganizationId))); return message(form, 'Booking archived.'); } diff --git a/src/routes/dashboard/clients/+page.server.ts b/src/routes/dashboard/clients/+page.server.ts index 714f636..931b37f 100644 --- a/src/routes/dashboard/clients/+page.server.ts +++ b/src/routes/dashboard/clients/+page.server.ts @@ -1,17 +1,19 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { addresses, clients, contacts } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { clientEditSchema, clientOnboardingCreateSchema } from '$lib/schemas/clients.schema'; import type { Actions, PageServerLoad } from './$types'; -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, activeOrganizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -34,6 +36,7 @@ export const load: PageServerLoad = async () => { export const actions: Actions = { create: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(clientOnboardingCreateSchema), { id: 'clients-create' }); @@ -47,6 +50,7 @@ export const actions: Actions = { await tx.insert(clients).values({ id: clientId, + organizationId: activeOrganizationId, name: form.data.name, type: form.data.type, status: form.data.status, @@ -58,6 +62,7 @@ export const actions: Actions = { await tx.insert(contacts).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId, name: form.data.primaryContactName, role: form.data.primaryContactRole || null, @@ -71,6 +76,7 @@ export const actions: Actions = { await tx.insert(addresses).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId, label: form.data.primaryAddressLabel, line1: form.data.primaryAddressLine1, @@ -92,6 +98,7 @@ export const actions: Actions = { }, edit: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(clientEditSchema), { id: 'clients-edit' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); @@ -107,7 +114,7 @@ export const actions: Actions = { notes: form.data.notes || null, updatedAt: new Date() }) - .where(eq(clients.id, form.data.id)); + .where(and(eq(clients.id, form.data.id), eq(clients.organizationId, activeOrganizationId))); } catch { return message(form, 'Unable to update client.', { status: 400 }); } @@ -116,6 +123,7 @@ export const actions: Actions = { }, archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'clients-archive' }); if (!form.valid) return message(form, 'Client id is required.', { status: 400 }); @@ -123,7 +131,7 @@ export const actions: Actions = { await db .update(clients) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(clients.id, form.data.id)); + .where(and(eq(clients.id, form.data.id), eq(clients.organizationId, activeOrganizationId))); return message(form, 'Client archived.'); } diff --git a/src/routes/dashboard/clients/[id]/+layout.server.ts b/src/routes/dashboard/clients/[id]/+layout.server.ts index fcc1f61..d17ecac 100644 --- a/src/routes/dashboard/clients/[id]/+layout.server.ts +++ b/src/routes/dashboard/clients/[id]/+layout.server.ts @@ -11,6 +11,7 @@ import { rooms, services } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { clientEditSchema } from '$lib/schemas/clients.schema'; import type { LayoutServerLoad } from './$types'; import { superValidate } from 'sveltekit-superforms/server'; @@ -30,22 +31,22 @@ function formValues(row: typeof clients.$inferSelect) { }; } -async function loadOptions() { +async function loadOptions(organizationId: string) { const [clientRows, roomRows, serviceRows] = await Promise.all([ db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)), db .select({ id: rooms.id, name: rooms.name }) .from(rooms) - .where(isNull(rooms.archivedAt)) + .where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt))) .orderBy(asc(rooms.name)), db .select({ id: services.id, name: services.name }) .from(services) - .where(isNull(services.archivedAt)) + .where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt))) .orderBy(asc(services.name)) ]); @@ -59,11 +60,18 @@ async function loadOptions() { }; } -export const load: LayoutServerLoad = async ({ params }) => { +export const load: LayoutServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const [client] = await db .select() .from(clients) - .where(and(eq(clients.id, params.id), isNull(clients.archivedAt))) + .where( + and( + eq(clients.id, params.id), + eq(clients.organizationId, activeOrganizationId), + isNull(clients.archivedAt) + ) + ) .limit(1); if (!client) error(404, 'Client not found'); @@ -73,29 +81,59 @@ export const load: LayoutServerLoad = async ({ params }) => { db .select() .from(addresses) - .where(and(eq(addresses.clientId, params.id), isNull(addresses.archivedAt))) + .where( + and( + eq(addresses.clientId, params.id), + eq(addresses.organizationId, activeOrganizationId), + isNull(addresses.archivedAt) + ) + ) .orderBy(asc(addresses.label)), db .select() .from(contacts) - .where(and(eq(contacts.clientId, params.id), isNull(contacts.archivedAt))) + .where( + and( + eq(contacts.clientId, params.id), + eq(contacts.organizationId, activeOrganizationId), + isNull(contacts.archivedAt) + ) + ) .orderBy(asc(contacts.name)), db .select() .from(invoices) - .where(and(eq(invoices.clientId, params.id), isNull(invoices.archivedAt))) + .where( + and( + eq(invoices.clientId, params.id), + eq(invoices.organizationId, activeOrganizationId), + isNull(invoices.archivedAt) + ) + ) .orderBy(asc(invoices.invoiceNumber)), db .select() .from(contracts) - .where(and(eq(contracts.clientId, params.id), isNull(contracts.archivedAt))) + .where( + and( + eq(contracts.clientId, params.id), + eq(contracts.organizationId, activeOrganizationId), + isNull(contracts.archivedAt) + ) + ) .orderBy(asc(contracts.title)), db .select() .from(bookings) - .where(and(eq(bookings.clientId, params.id), isNull(bookings.archivedAt))) + .where( + and( + eq(bookings.clientId, params.id), + eq(bookings.organizationId, activeOrganizationId), + isNull(bookings.archivedAt) + ) + ) .orderBy(asc(bookings.startsAt)), - loadOptions() + loadOptions(activeOrganizationId) ]); return { diff --git a/src/routes/dashboard/clients/[id]/addresses/+page.server.ts b/src/routes/dashboard/clients/[id]/addresses/+page.server.ts index fc7ef0a..d1d76b2 100644 --- a/src/routes/dashboard/clients/[id]/addresses/+page.server.ts +++ b/src/routes/dashboard/clients/[id]/addresses/+page.server.ts @@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { addresses, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { addressCreateSchema, addressEditSchema } from '$lib/schemas/addresses.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -19,11 +20,18 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(addresses) - .where(and(eq(addresses.clientId, params.id), isNull(addresses.archivedAt))) + .where( + and( + eq(addresses.clientId, params.id), + eq(addresses.organizationId, activeOrganizationId), + isNull(addresses.archivedAt) + ) + ) .orderBy(asc(addresses.label)); return { @@ -42,7 +50,7 @@ export const load: PageServerLoad = async ({ params }) => { isPrimary: record.isPrimary ? 'true' : 'false' } })), - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(addressCreateSchema), { id: 'addresses-create' }), @@ -52,7 +60,8 @@ export const load: PageServerLoad = async ({ params }) => { }; export const actions: Actions = { - create: async ({ params, request }) => { + create: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(addressCreateSchema), { @@ -64,6 +73,7 @@ export const actions: Actions = { try { await db.insert(addresses).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId: form.data.clientId, label: form.data.label, line1: form.data.line1, @@ -83,7 +93,8 @@ export const actions: Actions = { return message(form, 'Address created.'); }, - edit: async ({ params, request }) => { + edit: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(addressEditSchema), { id: 'addresses-edit' }); @@ -105,7 +116,13 @@ export const actions: Actions = { isPrimary: form.data.isPrimary === 'true', updatedAt: new Date() }) - .where(and(eq(addresses.id, form.data.id), eq(addresses.clientId, params.id))); + .where( + and( + eq(addresses.id, form.data.id), + eq(addresses.clientId, params.id), + eq(addresses.organizationId, activeOrganizationId) + ) + ); } catch { return message(form, 'Unable to update address.', { status: 400 }); } @@ -113,7 +130,8 @@ export const actions: Actions = { return message(form, 'Address updated.'); }, - archive: async ({ params, request }) => { + archive: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'addresses-archive' }); @@ -123,7 +141,13 @@ export const actions: Actions = { await db .update(addresses) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(addresses.id, form.data.id), eq(addresses.clientId, params.id))); + .where( + and( + eq(addresses.id, form.data.id), + eq(addresses.clientId, params.id), + eq(addresses.organizationId, activeOrganizationId) + ) + ); return message(form, 'Address archived.'); } diff --git a/src/routes/dashboard/clients/[id]/bookings/+page.server.ts b/src/routes/dashboard/clients/[id]/bookings/+page.server.ts index 3c7574a..095aba6 100644 --- a/src/routes/dashboard/clients/[id]/bookings/+page.server.ts +++ b/src/routes/dashboard/clients/[id]/bookings/+page.server.ts @@ -3,26 +3,27 @@ import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { bookings, clients, rooms, services } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { bookingCreateSchema, bookingEditSchema } from '$lib/schemas/bookings.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const [clientRows, roomRows, serviceRows] = await Promise.all([ db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)), db .select({ id: rooms.id, name: rooms.name }) .from(rooms) - .where(isNull(rooms.archivedAt)) + .where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt))) .orderBy(asc(rooms.name)), db .select({ id: services.id, name: services.name }) .from(services) - .where(isNull(services.archivedAt)) + .where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt))) .orderBy(asc(services.name)) ]); @@ -36,11 +37,18 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(bookings) - .where(and(eq(bookings.clientId, params.id), isNull(bookings.archivedAt))) + .where( + and( + eq(bookings.clientId, params.id), + eq(bookings.organizationId, activeOrganizationId), + isNull(bookings.archivedAt) + ) + ) .orderBy(asc(bookings.startsAt)); return { @@ -57,7 +65,7 @@ export const load: PageServerLoad = async ({ params }) => { notes: record.notes ?? '' } })), - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(bookingCreateSchema), { id: 'bookings-create' }), @@ -67,7 +75,8 @@ export const load: PageServerLoad = async ({ params }) => { }; export const actions: Actions = { - create: async ({ params, request }) => { + create: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(bookingCreateSchema), { @@ -79,6 +88,7 @@ export const actions: Actions = { try { await db.insert(bookings).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId: form.data.clientId, roomId: form.data.roomId, serviceId: form.data.serviceId || null, @@ -96,7 +106,8 @@ export const actions: Actions = { return message(form, 'Booking created.'); }, - edit: async ({ params, request }) => { + edit: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(bookingEditSchema), { @@ -118,7 +129,13 @@ export const actions: Actions = { notes: form.data.notes || null, updatedAt: new Date() }) - .where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id))); + .where( + and( + eq(bookings.id, form.data.id), + eq(bookings.clientId, params.id), + eq(bookings.organizationId, activeOrganizationId) + ) + ); } catch { return message(form, 'Unable to update booking.', { status: 400 }); } @@ -126,7 +143,8 @@ export const actions: Actions = { return message(form, 'Booking updated.'); }, - archive: async ({ params, request }) => { + archive: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'bookings-archive' }); @@ -136,7 +154,13 @@ export const actions: Actions = { await db .update(bookings) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id))); + .where( + and( + eq(bookings.id, form.data.id), + eq(bookings.clientId, params.id), + eq(bookings.organizationId, activeOrganizationId) + ) + ); return message(form, 'Booking archived.'); } diff --git a/src/routes/dashboard/clients/[id]/contacts/+page.server.ts b/src/routes/dashboard/clients/[id]/contacts/+page.server.ts index 03c4d83..86e0bd2 100644 --- a/src/routes/dashboard/clients/[id]/contacts/+page.server.ts +++ b/src/routes/dashboard/clients/[id]/contacts/+page.server.ts @@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { contacts, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { contactCreateSchema, contactEditSchema } from '$lib/schemas/contacts.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -19,11 +20,18 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(contacts) - .where(and(eq(contacts.clientId, params.id), isNull(contacts.archivedAt))) + .where( + and( + eq(contacts.clientId, params.id), + eq(contacts.organizationId, activeOrganizationId), + isNull(contacts.archivedAt) + ) + ) .orderBy(asc(contacts.name)); return { @@ -40,7 +48,7 @@ export const load: PageServerLoad = async ({ params }) => { notes: record.notes ?? '' } })), - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(contactCreateSchema), { id: 'contacts-create' }), @@ -50,7 +58,8 @@ export const load: PageServerLoad = async ({ params }) => { }; export const actions: Actions = { - create: async ({ params, request }) => { + create: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contactCreateSchema), { @@ -62,6 +71,7 @@ export const actions: Actions = { try { await db.insert(contacts).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId: form.data.clientId, name: form.data.name, role: form.data.role || null, @@ -79,7 +89,8 @@ export const actions: Actions = { return message(form, 'Contact created.'); }, - edit: async ({ params, request }) => { + edit: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contactEditSchema), { id: 'contacts-edit' }); @@ -99,7 +110,13 @@ export const actions: Actions = { notes: form.data.notes || null, updatedAt: new Date() }) - .where(and(eq(contacts.id, form.data.id), eq(contacts.clientId, params.id))); + .where( + and( + eq(contacts.id, form.data.id), + eq(contacts.clientId, params.id), + eq(contacts.organizationId, activeOrganizationId) + ) + ); } catch { return message(form, 'Unable to update contact.', { status: 400 }); } @@ -107,7 +124,8 @@ export const actions: Actions = { return message(form, 'Contact updated.'); }, - archive: async ({ params, request }) => { + archive: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'contacts-archive' }); @@ -117,7 +135,13 @@ export const actions: Actions = { await db .update(contacts) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(contacts.id, form.data.id), eq(contacts.clientId, params.id))); + .where( + and( + eq(contacts.id, form.data.id), + eq(contacts.clientId, params.id), + eq(contacts.organizationId, activeOrganizationId) + ) + ); return message(form, 'Contact archived.'); } diff --git a/src/routes/dashboard/clients/[id]/contracts/+page.server.ts b/src/routes/dashboard/clients/[id]/contracts/+page.server.ts index e9dd191..84ef8d6 100644 --- a/src/routes/dashboard/clients/[id]/contracts/+page.server.ts +++ b/src/routes/dashboard/clients/[id]/contracts/+page.server.ts @@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { contracts, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { contractCreateSchema, contractEditSchema } from '$lib/schemas/contracts.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -19,11 +20,18 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(contracts) - .where(and(eq(contracts.clientId, params.id), isNull(contracts.archivedAt))) + .where( + and( + eq(contracts.clientId, params.id), + eq(contracts.organizationId, activeOrganizationId), + isNull(contracts.archivedAt) + ) + ) .orderBy(asc(contracts.title)); return { @@ -40,7 +48,7 @@ export const load: PageServerLoad = async ({ params }) => { notes: record.notes ?? '' } })), - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(contractCreateSchema), { id: 'contracts-create' }), @@ -50,7 +58,8 @@ export const load: PageServerLoad = async ({ params }) => { }; export const actions: Actions = { - create: async ({ params, request }) => { + create: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contractCreateSchema), { @@ -62,6 +71,7 @@ export const actions: Actions = { try { await db.insert(contracts).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId: form.data.clientId, title: form.data.title, startDate: form.data.startDate, @@ -79,7 +89,8 @@ export const actions: Actions = { return message(form, 'Contract created.'); }, - edit: async ({ params, request }) => { + edit: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contractEditSchema), { @@ -101,7 +112,13 @@ export const actions: Actions = { notes: form.data.notes || null, updatedAt: new Date() }) - .where(and(eq(contracts.id, form.data.id), eq(contracts.clientId, params.id))); + .where( + and( + eq(contracts.id, form.data.id), + eq(contracts.clientId, params.id), + eq(contracts.organizationId, activeOrganizationId) + ) + ); } catch { return message(form, 'Unable to update contract.', { status: 400 }); } @@ -109,7 +126,8 @@ export const actions: Actions = { return message(form, 'Contract updated.'); }, - archive: async ({ params, request }) => { + archive: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'contracts-archive' }); @@ -119,7 +137,13 @@ export const actions: Actions = { await db .update(contracts) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(contracts.id, form.data.id), eq(contracts.clientId, params.id))); + .where( + and( + eq(contracts.id, form.data.id), + eq(contracts.clientId, params.id), + eq(contracts.organizationId, activeOrganizationId) + ) + ); return message(form, 'Contract archived.'); } diff --git a/src/routes/dashboard/clients/[id]/invoices/+page.server.ts b/src/routes/dashboard/clients/[id]/invoices/+page.server.ts index ce9c5cb..964c3c8 100644 --- a/src/routes/dashboard/clients/[id]/invoices/+page.server.ts +++ b/src/routes/dashboard/clients/[id]/invoices/+page.server.ts @@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { invoices, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { invoiceCreateSchema, invoiceEditSchema } from '$lib/schemas/invoices.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -19,11 +20,18 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ locals, params }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(invoices) - .where(and(eq(invoices.clientId, params.id), isNull(invoices.archivedAt))) + .where( + and( + eq(invoices.clientId, params.id), + eq(invoices.organizationId, activeOrganizationId), + isNull(invoices.archivedAt) + ) + ) .orderBy(asc(invoices.invoiceNumber)); return { @@ -42,7 +50,7 @@ export const load: PageServerLoad = async ({ params }) => { notes: record.notes ?? '' } })), - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(invoiceCreateSchema), { id: 'invoices-create' }), @@ -52,7 +60,8 @@ export const load: PageServerLoad = async ({ params }) => { }; export const actions: Actions = { - create: async ({ params, request }) => { + create: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(invoiceCreateSchema), { @@ -64,6 +73,7 @@ export const actions: Actions = { try { await db.insert(invoices).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, clientId: form.data.clientId, invoiceNumber: form.data.invoiceNumber, issueDate: form.data.issueDate, @@ -83,7 +93,8 @@ export const actions: Actions = { return message(form, 'Invoice created.'); }, - edit: async ({ params, request }) => { + edit: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(invoiceEditSchema), { id: 'invoices-edit' }); @@ -105,7 +116,13 @@ export const actions: Actions = { notes: form.data.notes || null, updatedAt: new Date() }) - .where(and(eq(invoices.id, form.data.id), eq(invoices.clientId, params.id))); + .where( + and( + eq(invoices.id, form.data.id), + eq(invoices.clientId, params.id), + eq(invoices.organizationId, activeOrganizationId) + ) + ); } catch { return message(form, 'Unable to update invoice.', { status: 400 }); } @@ -113,7 +130,8 @@ export const actions: Actions = { return message(form, 'Invoice updated.'); }, - archive: async ({ params, request }) => { + archive: async ({ locals, params, request }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'invoices-archive' }); @@ -123,7 +141,13 @@ export const actions: Actions = { await db .update(invoices) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(and(eq(invoices.id, form.data.id), eq(invoices.clientId, params.id))); + .where( + and( + eq(invoices.id, form.data.id), + eq(invoices.clientId, params.id), + eq(invoices.organizationId, activeOrganizationId) + ) + ); return message(form, 'Invoice archived.'); } diff --git a/src/routes/dashboard/contacts/+page.server.ts b/src/routes/dashboard/contacts/+page.server.ts index 6aa04c6..f5a3e36 100644 --- a/src/routes/dashboard/contacts/+page.server.ts +++ b/src/routes/dashboard/contacts/+page.server.ts @@ -1,16 +1,17 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { contacts, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -18,22 +19,24 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(contacts) - .where(isNull(contacts.archivedAt)) + .where(and(eq(contacts.organizationId, activeOrganizationId), isNull(contacts.archivedAt))) .orderBy(asc(contacts.name)); return { records, - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), archiveForm: await superValidate(zod4(archiveSchema), { id: 'contacts-archive' }) }; }; export const actions: Actions = { archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'contacts-archive' }); if (!form.valid) return message(form, 'Contact id is required.', { status: 400 }); @@ -41,7 +44,7 @@ export const actions: Actions = { await db .update(contacts) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(contacts.id, form.data.id)); + .where(and(eq(contacts.id, form.data.id), eq(contacts.organizationId, activeOrganizationId))); return message(form, 'Contact archived.'); } diff --git a/src/routes/dashboard/contracts/+page.server.ts b/src/routes/dashboard/contracts/+page.server.ts index 2d45db9..cca177b 100644 --- a/src/routes/dashboard/contracts/+page.server.ts +++ b/src/routes/dashboard/contracts/+page.server.ts @@ -1,16 +1,17 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { contracts, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -18,22 +19,24 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(contracts) - .where(isNull(contracts.archivedAt)) + .where(and(eq(contracts.organizationId, activeOrganizationId), isNull(contracts.archivedAt))) .orderBy(asc(contracts.title)); return { records, - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), archiveForm: await superValidate(zod4(archiveSchema), { id: 'contracts-archive' }) }; }; export const actions: Actions = { archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'contracts-archive' }); if (!form.valid) return message(form, 'Contract id is required.', { status: 400 }); @@ -41,7 +44,9 @@ export const actions: Actions = { await db .update(contracts) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(contracts.id, form.data.id)); + .where( + and(eq(contracts.id, form.data.id), eq(contracts.organizationId, activeOrganizationId)) + ); return message(form, 'Contract archived.'); } diff --git a/src/routes/dashboard/invoices/+page.server.ts b/src/routes/dashboard/invoices/+page.server.ts index 4e7b793..5a9f44c 100644 --- a/src/routes/dashboard/invoices/+page.server.ts +++ b/src/routes/dashboard/invoices/+page.server.ts @@ -1,16 +1,17 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { invoices, clients } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import type { Actions, PageServerLoad } from './$types'; -async function loadOptions() { +async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) - .where(isNull(clients.archivedAt)) + .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { @@ -18,22 +19,24 @@ async function loadOptions() { }; } -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(invoices) - .where(isNull(invoices.archivedAt)) + .where(and(eq(invoices.organizationId, activeOrganizationId), isNull(invoices.archivedAt))) .orderBy(asc(invoices.invoiceNumber)); return { records, - options: await loadOptions(), + options: await loadOptions(activeOrganizationId), archiveForm: await superValidate(zod4(archiveSchema), { id: 'invoices-archive' }) }; }; export const actions: Actions = { archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'invoices-archive' }); if (!form.valid) return message(form, 'Invoice id is required.', { status: 400 }); @@ -41,7 +44,7 @@ export const actions: Actions = { await db .update(invoices) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(invoices.id, form.data.id)); + .where(and(eq(invoices.id, form.data.id), eq(invoices.organizationId, activeOrganizationId))); return message(form, 'Invoice archived.'); } diff --git a/src/routes/dashboard/rooms/+page.server.ts b/src/routes/dashboard/rooms/+page.server.ts index 51c8397..c874002 100644 --- a/src/routes/dashboard/rooms/+page.server.ts +++ b/src/routes/dashboard/rooms/+page.server.ts @@ -1,17 +1,19 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { rooms } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { roomCreateSchema, roomEditSchema } from '$lib/schemas/rooms.schema'; import type { Actions, PageServerLoad } from './$types'; -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(rooms) - .where(isNull(rooms.archivedAt)) + .where(and(eq(rooms.organizationId, activeOrganizationId), isNull(rooms.archivedAt))) .orderBy(asc(rooms.name)); return { @@ -39,11 +41,13 @@ export const load: PageServerLoad = async () => { export const actions: Actions = { create: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(roomCreateSchema), { id: 'rooms-create' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); const sharedValues = { + organizationId: activeOrganizationId, name: form.data.name, type: form.data.type, sqFt: null, @@ -96,6 +100,7 @@ export const actions: Actions = { }, edit: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(roomEditSchema), { id: 'rooms-edit' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); @@ -140,7 +145,10 @@ export const actions: Actions = { }; try { - await db.update(rooms).set(roomValues).where(eq(rooms.id, form.data.id)); + await db + .update(rooms) + .set(roomValues) + .where(and(eq(rooms.id, form.data.id), eq(rooms.organizationId, activeOrganizationId))); } catch { return message(form, 'Unable to update room.', { status: 400 }); } @@ -149,6 +157,7 @@ export const actions: Actions = { }, archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'rooms-archive' }); if (!form.valid) return message(form, 'Room id is required.', { status: 400 }); @@ -156,7 +165,7 @@ export const actions: Actions = { await db .update(rooms) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(rooms.id, form.data.id)); + .where(and(eq(rooms.id, form.data.id), eq(rooms.organizationId, activeOrganizationId))); return message(form, 'Room archived.'); } diff --git a/src/routes/dashboard/services/+page.server.ts b/src/routes/dashboard/services/+page.server.ts index 65d67b0..62d28f2 100644 --- a/src/routes/dashboard/services/+page.server.ts +++ b/src/routes/dashboard/services/+page.server.ts @@ -1,17 +1,19 @@ -import { asc, eq, isNull } from 'drizzle-orm'; +import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { services } from '$lib/server/db/schema'; +import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { serviceCreateSchema, serviceEditSchema } from '$lib/schemas/services.schema'; import type { Actions, PageServerLoad } from './$types'; -export const load: PageServerLoad = async () => { +export const load: PageServerLoad = async ({ locals }) => { + const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(services) - .where(isNull(services.archivedAt)) + .where(and(eq(services.organizationId, activeOrganizationId), isNull(services.archivedAt))) .orderBy(asc(services.name)); return { @@ -34,6 +36,7 @@ export const load: PageServerLoad = async () => { export const actions: Actions = { create: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(serviceCreateSchema), { id: 'services-create' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); @@ -41,6 +44,7 @@ export const actions: Actions = { try { await db.insert(services).values({ id: crypto.randomUUID(), + organizationId: activeOrganizationId, name: form.data.name, category: form.data.category || null, unit: form.data.unit, @@ -57,6 +61,7 @@ export const actions: Actions = { }, edit: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(serviceEditSchema), { id: 'services-edit' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); @@ -72,7 +77,9 @@ export const actions: Actions = { description: form.data.description || null, updatedAt: new Date() }) - .where(eq(services.id, form.data.id)); + .where( + and(eq(services.id, form.data.id), eq(services.organizationId, activeOrganizationId)) + ); } catch { return message(form, 'Unable to update service.', { status: 400 }); } @@ -81,6 +88,7 @@ export const actions: Actions = { }, archive: async (event) => { + const { activeOrganizationId } = await loadOrganizationContext(event.locals); const form = await superValidate(event, zod4(archiveSchema), { id: 'services-archive' }); if (!form.valid) return message(form, 'Service id is required.', { status: 400 }); @@ -88,7 +96,7 @@ export const actions: Actions = { await db .update(services) .set({ archivedAt: new Date(), updatedAt: new Date() }) - .where(eq(services.id, form.data.id)); + .where(and(eq(services.id, form.data.id), eq(services.organizationId, activeOrganizationId))); return message(form, 'Service archived.'); }