From 2bb985000bce1889db9da44881ec30f16996cf33 Mon Sep 17 00:00:00 2001 From: Daniel Kirby Date: Wed, 24 Jun 2026 18:04:21 +0100 Subject: [PATCH] feat: add organization membership data model --- drizzle/0012_organization_memberships.sql | 28 + drizzle/0013_flippant_jamie_braddock.sql | 65 + drizzle/meta/0013_snapshot.json | 2052 +++++++++++++++++ drizzle/meta/_journal.json | 16 +- src/lib/schemas/organizations.schema.ts | 4 +- .../db/organization-memberships.schema.ts | 29 + src/lib/server/db/organizations.schema.ts | 4 +- src/lib/server/db/schema.ts | 1 + 8 files changed, 2194 insertions(+), 5 deletions(-) create mode 100644 drizzle/0012_organization_memberships.sql create mode 100644 drizzle/0013_flippant_jamie_braddock.sql create mode 100644 drizzle/meta/0013_snapshot.json create mode 100644 src/lib/server/db/organization-memberships.schema.ts diff --git a/drizzle/0012_organization_memberships.sql b/drizzle/0012_organization_memberships.sql new file mode 100644 index 0000000..627684e --- /dev/null +++ b/drizzle/0012_organization_memberships.sql @@ -0,0 +1,28 @@ +CREATE TABLE `organization_memberships` ( + `id` text PRIMARY KEY NOT NULL, + `organization_id` text NOT NULL, + `user_id` text NOT NULL, + `role` text DEFAULT 'user' NOT NULL, + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `archived_at` integer, + FOREIGN KEY (`organization_id`) REFERENCES `organizations`(`id`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE UNIQUE INDEX `organization_memberships_organization_user_unique` ON `organization_memberships` (`organization_id`,`user_id`);--> statement-breakpoint +CREATE INDEX `organization_memberships_organization_id_idx` ON `organization_memberships` (`organization_id`);--> statement-breakpoint +CREATE INDEX `organization_memberships_user_id_idx` ON `organization_memberships` (`user_id`);--> statement-breakpoint +INSERT INTO `organization_memberships` (`id`, `organization_id`, `user_id`, `role`) +SELECT lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-' || lower(hex(randomblob(2))) || '-' || lower(hex(randomblob(2))) || '-' || lower(hex(randomblob(6))), + organizations.`id`, + user.`id`, + CASE WHEN user.`role` = 'admin' THEN 'admin' ELSE 'user' END +FROM `organizations` +CROSS JOIN `user` +WHERE NOT EXISTS ( + SELECT 1 + FROM `organization_memberships` + WHERE `organization_memberships`.`organization_id` = organizations.`id` + AND `organization_memberships`.`user_id` = user.`id` +); diff --git a/drizzle/0013_flippant_jamie_braddock.sql b/drizzle/0013_flippant_jamie_braddock.sql new file mode 100644 index 0000000..3ae5089 --- /dev/null +++ b/drizzle/0013_flippant_jamie_braddock.sql @@ -0,0 +1,65 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_organizations` ( + `id` text PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `address_line_1` text DEFAULT '' NOT NULL, + `address_line_2` text, + `address_line_3` text, + `city` text, + `region` text, + `postcode` text, + `country` text DEFAULT 'United Kingdom' NOT NULL, + `bank_name` text, + `bank_account_name` text, + `bank_account_number` text, + `bank_sort_code` text, + `bank_iban` text, + `bank_swift` text, + `created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL, + `archived_at` integer +); +--> statement-breakpoint +INSERT INTO `__new_organizations` ( + "id", + "name", + "address_line_1", + "address_line_2", + "address_line_3", + "city", + "region", + "postcode", + "country", + "bank_name", + "bank_account_name", + "bank_account_number", + "bank_sort_code", + "bank_iban", + "bank_swift", + "created_at", + "updated_at", + "archived_at" +) +SELECT + "id", + "name", + COALESCE(NULLIF("address_line_1", ''), "workspace", ''), + "address_line_2", + NULL, + "city", + "region", + "postcode", + "country", + "bank_name", + "bank_account_name", + "bank_account_number", + "bank_sort_code", + "bank_iban", + "bank_swift", + "created_at", + "updated_at", + "archived_at" +FROM `organizations`;--> statement-breakpoint +DROP TABLE `organizations`;--> statement-breakpoint +ALTER TABLE `__new_organizations` RENAME TO `organizations`;--> statement-breakpoint +PRAGMA foreign_keys=ON; diff --git a/drizzle/meta/0013_snapshot.json b/drizzle/meta/0013_snapshot.json new file mode 100644 index 0000000..750c5cd --- /dev/null +++ b/drizzle/meta/0013_snapshot.json @@ -0,0 +1,2052 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "9b273e1a-b074-44d2-b90f-7aa8a6605a47", + "prevId": "2a8c8b90-bbf2-48a0-8185-630b9d3be582", + "tables": { + "task": { + "name": "task", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "industry": { + "name": "industry", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_organization_id_organizations_id_fk": { + "name": "clients_organization_id_organizations_id_fk", + "tableFrom": "clients", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organizations": { + "name": "organizations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "address_line_3": { + "name": "address_line_3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "city": { + "name": "city", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'United Kingdom'" + }, + "bank_name": { + "name": "bank_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bank_account_name": { + "name": "bank_account_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bank_account_number": { + "name": "bank_account_number", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bank_sort_code": { + "name": "bank_sort_code", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bank_iban": { + "name": "bank_iban", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bank_swift": { + "name": "bank_swift", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization_memberships": { + "name": "organization_memberships", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "organization_memberships_organization_user_unique": { + "name": "organization_memberships_organization_user_unique", + "columns": [ + "organization_id", + "user_id" + ], + "isUnique": true + }, + "organization_memberships_organization_id_idx": { + "name": "organization_memberships_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "organization_memberships_user_id_idx": { + "name": "organization_memberships_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "organization_memberships_organization_id_organizations_id_fk": { + "name": "organization_memberships_organization_id_organizations_id_fk", + "tableFrom": "organization_memberships", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_memberships_user_id_user_id_fk": { + "name": "organization_memberships_user_id_user_id_fk", + "tableFrom": "organization_memberships", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "addresses": { + "name": "addresses", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'primary'" + }, + "line_1": { + "name": "line_1", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "line_2": { + "name": "line_2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "line_3": { + "name": "line_3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "city": { + "name": "city", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'United Kingdom'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "addresses_organization_id_idx": { + "name": "addresses_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "addresses_client_id_idx": { + "name": "addresses_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "addresses_organization_id_organizations_id_fk": { + "name": "addresses_organization_id_organizations_id_fk", + "tableFrom": "addresses", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "addresses_client_id_clients_id_fk": { + "name": "addresses_client_id_clients_id_fk", + "tableFrom": "addresses", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "contacts": { + "name": "contacts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "receives_invoices": { + "name": "receives_invoices", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "receives_contracts": { + "name": "receives_contracts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "contacts_organization_id_idx": { + "name": "contacts_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "contacts_client_id_idx": { + "name": "contacts_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "contacts_organization_id_organizations_id_fk": { + "name": "contacts_organization_id_organizations_id_fk", + "tableFrom": "contacts", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "contacts_client_id_clients_id_fk": { + "name": "contacts_client_id_clients_id_fk", + "tableFrom": "contacts", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rooms": { + "name": "rooms", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'meeting_room'" + }, + "sq_ft": { + "name": "sq_ft", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_price_per_hour_gbp": { + "name": "internal_price_per_hour_gbp", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "external_price_per_hour_gbp": { + "name": "external_price_per_hour_gbp", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_price_per_day_gbp": { + "name": "internal_price_per_day_gbp", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "external_price_per_day_gbp": { + "name": "external_price_per_day_gbp", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_attendees": { + "name": "max_attendees", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "workstations": { + "name": "workstations", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price_per_month_gbp": { + "name": "price_per_month_gbp", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "rooms_organization_id_organizations_id_fk": { + "name": "rooms_organization_id_organizations_id_fk", + "tableFrom": "rooms", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "services": { + "name": "services", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'each'" + }, + "price_gbp": { + "name": "price_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "services_organization_id_organizations_id_fk": { + "name": "services_organization_id_organizations_id_fk", + "tableFrom": "services", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "bookings": { + "name": "bookings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_id": { + "name": "room_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_id": { + "name": "service_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "starts_at": { + "name": "starts_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ends_at": { + "name": "ends_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'booked'" + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "bookings_organization_id_idx": { + "name": "bookings_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "bookings_client_id_idx": { + "name": "bookings_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "bookings_room_id_idx": { + "name": "bookings_room_id_idx", + "columns": [ + "room_id" + ], + "isUnique": false + }, + "bookings_service_id_idx": { + "name": "bookings_service_id_idx", + "columns": [ + "service_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "bookings_organization_id_organizations_id_fk": { + "name": "bookings_organization_id_organizations_id_fk", + "tableFrom": "bookings", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "bookings_client_id_clients_id_fk": { + "name": "bookings_client_id_clients_id_fk", + "tableFrom": "bookings", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "bookings_room_id_rooms_id_fk": { + "name": "bookings_room_id_rooms_id_fk", + "tableFrom": "bookings", + "tableTo": "rooms", + "columnsFrom": [ + "room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "bookings_service_id_services_id_fk": { + "name": "bookings_service_id_services_id_fk", + "tableFrom": "bookings", + "tableTo": "services", + "columnsFrom": [ + "service_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invoice_lines": { + "name": "invoice_lines", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invoice_id": { + "name": "invoice_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "period_start": { + "name": "period_start", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "period_end": { + "name": "period_end", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "quantity": { + "name": "quantity", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "unit_price_gbp": { + "name": "unit_price_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "total_gbp": { + "name": "total_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "invoice_lines_organization_id_idx": { + "name": "invoice_lines_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invoice_lines_invoice_id_idx": { + "name": "invoice_lines_invoice_id_idx", + "columns": [ + "invoice_id" + ], + "isUnique": false + }, + "invoice_lines_client_id_idx": { + "name": "invoice_lines_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "invoice_lines_source_idx": { + "name": "invoice_lines_source_idx", + "columns": [ + "source_type", + "source_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invoice_lines_organization_id_organizations_id_fk": { + "name": "invoice_lines_organization_id_organizations_id_fk", + "tableFrom": "invoice_lines", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "invoice_lines_invoice_id_invoices_id_fk": { + "name": "invoice_lines_invoice_id_invoices_id_fk", + "tableFrom": "invoice_lines", + "tableTo": "invoices", + "columnsFrom": [ + "invoice_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invoice_lines_client_id_clients_id_fk": { + "name": "invoice_lines_client_id_clients_id_fk", + "tableFrom": "invoice_lines", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invoices": { + "name": "invoices", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invoice_number": { + "name": "invoice_number", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "issue_date": { + "name": "issue_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "due_date": { + "name": "due_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "subtotal_gbp": { + "name": "subtotal_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "tax_gbp": { + "name": "tax_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "total_gbp": { + "name": "total_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "invoices_invoice_number_unique": { + "name": "invoices_invoice_number_unique", + "columns": [ + "invoice_number" + ], + "isUnique": true + }, + "invoices_organization_id_idx": { + "name": "invoices_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invoices_client_id_idx": { + "name": "invoices_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invoices_organization_id_organizations_id_fk": { + "name": "invoices_organization_id_organizations_id_fk", + "tableFrom": "invoices", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "invoices_client_id_clients_id_fk": { + "name": "invoices_client_id_clients_id_fk", + "tableFrom": "invoices", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "contracts": { + "name": "contracts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_id": { + "name": "room_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "service_id": { + "name": "service_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "license_fee_gbp": { + "name": "license_fee_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "deposit_gbp": { + "name": "deposit_gbp", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "start_date": { + "name": "start_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "end_date": { + "name": "end_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "billed_to": { + "name": "billed_to", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "contracts_organization_id_idx": { + "name": "contracts_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "contracts_client_id_idx": { + "name": "contracts_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "contracts_room_id_idx": { + "name": "contracts_room_id_idx", + "columns": [ + "room_id" + ], + "isUnique": false + }, + "contracts_service_id_idx": { + "name": "contracts_service_id_idx", + "columns": [ + "service_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "contracts_organization_id_organizations_id_fk": { + "name": "contracts_organization_id_organizations_id_fk", + "tableFrom": "contracts", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "contracts_client_id_clients_id_fk": { + "name": "contracts_client_id_clients_id_fk", + "tableFrom": "contracts", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "contracts_room_id_rooms_id_fk": { + "name": "contracts_room_id_rooms_id_fk", + "tableFrom": "contracts", + "tableTo": "rooms", + "columnsFrom": [ + "room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "contracts_service_id_services_id_fk": { + "name": "contracts_service_id_services_id_fk", + "tableFrom": "contracts", + "tableTo": "services", + "columnsFrom": [ + "service_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index fee8759..13c8940 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -85,6 +85,20 @@ "when": 1782291600000, "tag": "0011_billing_flow", "breakpoints": true + }, + { + "idx": 12, + "version": "6", + "when": 1782295200000, + "tag": "0012_organization_memberships", + "breakpoints": true + }, + { + "idx": 13, + "version": "6", + "when": 1782313131621, + "tag": "0013_flippant_jamie_braddock", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/src/lib/schemas/organizations.schema.ts b/src/lib/schemas/organizations.schema.ts index eecbaef..45664b0 100644 --- a/src/lib/schemas/organizations.schema.ts +++ b/src/lib/schemas/organizations.schema.ts @@ -3,9 +3,9 @@ import { idSchema, optionalText, requiredText } from './shared.schema'; const organizationDetailsSchema = z.object({ name: requiredText('Organization name'), - workspace: requiredText('Workspace', 120).default('Blueprint Workspace'), - addressLine1: optionalText(160), + addressLine1: requiredText('Address line 1'), addressLine2: optionalText(160), + addressLine3: optionalText(160), city: optionalText(100), region: optionalText(100), postcode: optionalText(24), diff --git a/src/lib/server/db/organization-memberships.schema.ts b/src/lib/server/db/organization-memberships.schema.ts new file mode 100644 index 0000000..1466fdc --- /dev/null +++ b/src/lib/server/db/organization-memberships.schema.ts @@ -0,0 +1,29 @@ +import { index, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; +import { user } from './auth.schema'; +import { organizations } from './organizations.schema'; +import { timestamps } from './shared.schema'; + +export const organizationMemberships = sqliteTable( + 'organization_memberships', + { + id: text('id') + .primaryKey() + .$defaultFn(() => crypto.randomUUID()), + organizationId: text('organization_id') + .notNull() + .references(() => organizations.id, { onDelete: 'cascade' }), + userId: text('user_id') + .notNull() + .references(() => user.id, { onDelete: 'cascade' }), + role: text('role').notNull().default('user'), + ...timestamps + }, + (table) => [ + uniqueIndex('organization_memberships_organization_user_unique').on( + table.organizationId, + table.userId + ), + index('organization_memberships_organization_id_idx').on(table.organizationId), + index('organization_memberships_user_id_idx').on(table.userId) + ] +); diff --git a/src/lib/server/db/organizations.schema.ts b/src/lib/server/db/organizations.schema.ts index a448032..1b26c8e 100644 --- a/src/lib/server/db/organizations.schema.ts +++ b/src/lib/server/db/organizations.schema.ts @@ -6,9 +6,9 @@ export const organizations = sqliteTable('organizations', { .primaryKey() .$defaultFn(() => crypto.randomUUID()), name: text('name').notNull(), - workspace: text('workspace').notNull().default('Default Workspace'), - addressLine1: text('address_line_1'), + addressLine1: text('address_line_1').notNull().default(''), addressLine2: text('address_line_2'), + addressLine3: text('address_line_3'), city: text('city'), region: text('region'), postcode: text('postcode'), diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts index 603f99a..c0d8bc5 100644 --- a/src/lib/server/db/schema.ts +++ b/src/lib/server/db/schema.ts @@ -10,6 +10,7 @@ export const task = sqliteTable('task', { export * from './clients.schema'; export * from './organizations.schema'; +export * from './organization-memberships.schema'; export * from './addresses.schema'; export * from './contacts.schema'; export * from './rooms.schema';