From 3417ed6698b28b51d03bc699d4f97dc1e77a6cbd Mon Sep 17 00:00:00 2001 From: grabowski Date: Thu, 23 Apr 2026 15:32:20 +0700 Subject: [PATCH] feat(properties): expenses tab with electricity+water chart - expense_kind enum (utilities + maintenance/repair/cleaning/insurance/tax/rent/other) - property_expenses table with optional link to a property_accounts row (preserves history via ON DELETE SET NULL) - services/expenses.ts: CRUD + 12-month monthly series aggregation + year-to-date summary by kind - /properties/[id]/expenses tab: inline SVG line chart for electricity + water last 12 months (no chart library), summary card, add/edit/delete inline with account linking when kind matches --- drizzle/0014_property_expenses.sql | 25 + drizzle/0015_expenses_updated_at_trigger.sql | 3 + drizzle/meta/0014_snapshot.json | 4542 +++++++++++++++++ drizzle/meta/0015_snapshot.json | 4542 +++++++++++++++++ drizzle/meta/_journal.json | 14 + src/lib/components/ExpenseChart.svelte | 153 + src/lib/expenses.ts | 51 + src/lib/server/db/schema/_shared.ts | 16 + src/lib/server/db/schema/expenses.ts | 46 + src/lib/server/db/schema/index.ts | 1 + src/lib/server/services/expenses.ts | 283 + .../(app)/properties/[id]/+layout.svelte | 1 + .../properties/[id]/expenses/+page.server.ts | 158 + .../properties/[id]/expenses/+page.svelte | 267 + 14 files changed, 10102 insertions(+) create mode 100644 drizzle/0014_property_expenses.sql create mode 100644 drizzle/0015_expenses_updated_at_trigger.sql create mode 100644 drizzle/meta/0014_snapshot.json create mode 100644 drizzle/meta/0015_snapshot.json create mode 100644 src/lib/components/ExpenseChart.svelte create mode 100644 src/lib/expenses.ts create mode 100644 src/lib/server/db/schema/expenses.ts create mode 100644 src/lib/server/services/expenses.ts create mode 100644 src/routes/(app)/properties/[id]/expenses/+page.server.ts create mode 100644 src/routes/(app)/properties/[id]/expenses/+page.svelte diff --git a/drizzle/0014_property_expenses.sql b/drizzle/0014_property_expenses.sql new file mode 100644 index 0000000..5d94d1e --- /dev/null +++ b/drizzle/0014_property_expenses.sql @@ -0,0 +1,25 @@ +CREATE TYPE "public"."expense_kind" AS ENUM('water', 'electricity', 'gas', 'internet', 'phone', 'cable', 'waste', 'maintenance', 'repair', 'cleaning', 'insurance', 'tax', 'rent', 'other');--> statement-breakpoint +CREATE TABLE "property_expenses" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "property_id" uuid NOT NULL, + "account_id" uuid, + "kind" "expense_kind" NOT NULL, + "amount" numeric(18, 4) NOT NULL, + "currency" varchar(3) NOT NULL, + "period_start" timestamp with time zone, + "period_end" timestamp with time zone, + "incurred_at" timestamp with time zone NOT NULL, + "vendor" varchar(128), + "reference" varchar(128), + "notes" text, + "created_by" uuid, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "property_expenses" ADD CONSTRAINT "property_expenses_property_id_properties_id_fk" FOREIGN KEY ("property_id") REFERENCES "public"."properties"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "property_expenses" ADD CONSTRAINT "property_expenses_account_id_property_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."property_accounts"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "property_expenses" ADD CONSTRAINT "property_expenses_created_by_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "expenses_by_property_time" ON "property_expenses" USING btree ("property_id","incurred_at");--> statement-breakpoint +CREATE INDEX "expenses_by_property_kind" ON "property_expenses" USING btree ("property_id","kind","incurred_at");--> statement-breakpoint +CREATE INDEX "expenses_by_account" ON "property_expenses" USING btree ("account_id"); \ No newline at end of file diff --git a/drizzle/0015_expenses_updated_at_trigger.sql b/drizzle/0015_expenses_updated_at_trigger.sql new file mode 100644 index 0000000..d732282 --- /dev/null +++ b/drizzle/0015_expenses_updated_at_trigger.sql @@ -0,0 +1,3 @@ +-- Updated_at trigger for property_expenses. +CREATE TRIGGER property_expenses_set_updated_at BEFORE UPDATE ON "property_expenses" + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); diff --git a/drizzle/meta/0014_snapshot.json b/drizzle/meta/0014_snapshot.json new file mode 100644 index 0000000..b75b698 --- /dev/null +++ b/drizzle/meta/0014_snapshot.json @@ -0,0 +1,4542 @@ +{ + "id": "4d5b9058-c852-4391-b06c-c39f088f84ce", + "prevId": "aa553ee3-1697-4639-ae6a-25520e125ba3", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.property_accounts": { + "name": "property_accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "account_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "label": { + "name": "label", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "account_number": { + "name": "account_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "meter_number": { + "name": "meter_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "accounts_by_property": { + "name": "accounts_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_accounts_property_id_properties_id_fk": { + "name": "property_accounts_property_id_properties_id_fk", + "tableFrom": "property_accounts", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_field_defs": { + "name": "asset_field_defs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_type_id": { + "name": "asset_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "field_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enum_values": { + "name": "enum_values", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(32)", + "primaryKey": false, + "notNull": false + }, + "placeholder": { + "name": "placeholder", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "help_text": { + "name": "help_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deprecated_at": { + "name": "deprecated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_field_defs_type_key_uq": { + "name": "asset_field_defs_type_key_uq", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "asset_field_defs_by_type": { + "name": "asset_field_defs_by_type", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_field_defs_asset_type_id_asset_types_id_fk": { + "name": "asset_field_defs_asset_type_id_asset_types_id_fk", + "tableFrom": "asset_field_defs", + "tableTo": "asset_types", + "columnsFrom": [ + "asset_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_location_history": { + "name": "asset_location_history", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "from_kind": { + "name": "from_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "from_project_id": { + "name": "from_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "from_property_id": { + "name": "from_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "to_kind": { + "name": "to_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "to_project_id": { + "name": "to_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "to_property_id": { + "name": "to_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "moved_by": { + "name": "moved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "moved_at": { + "name": "moved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "alh_by_asset": { + "name": "alh_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "moved_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_location_history_asset_id_assets_id_fk": { + "name": "asset_location_history_asset_id_assets_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "asset_location_history_from_project_id_projects_id_fk": { + "name": "asset_location_history_from_project_id_projects_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "projects", + "columnsFrom": [ + "from_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_from_property_id_properties_id_fk": { + "name": "asset_location_history_from_property_id_properties_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "properties", + "columnsFrom": [ + "from_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_to_project_id_projects_id_fk": { + "name": "asset_location_history_to_project_id_projects_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "projects", + "columnsFrom": [ + "to_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_to_property_id_properties_id_fk": { + "name": "asset_location_history_to_property_id_properties_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "properties", + "columnsFrom": [ + "to_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_moved_by_users_id_fk": { + "name": "asset_location_history_moved_by_users_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "users", + "columnsFrom": [ + "moved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_logs": { + "name": "asset_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_logs_by_asset": { + "name": "asset_logs_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_logs_asset_id_assets_id_fk": { + "name": "asset_logs_asset_id_assets_id_fk", + "tableFrom": "asset_logs", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "asset_logs_author_id_users_id_fk": { + "name": "asset_logs_author_id_users_id_fk", + "tableFrom": "asset_logs", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_types": { + "name": "asset_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_version": { + "name": "schema_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_types_company_slug_uq": { + "name": "asset_types_company_slug_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "asset_types_by_parent": { + "name": "asset_types_by_parent", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_types_company_id_companies_id_fk": { + "name": "asset_types_company_id_companies_id_fk", + "tableFrom": "asset_types", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.assets": { + "name": "assets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "asset_type_id": { + "name": "asset_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "serial_number": { + "name": "serial_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "manufacturer": { + "name": "manufacturer", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "purchased_at": { + "name": "purchased_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "current_container_kind": { + "name": "current_container_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "current_project_id": { + "name": "current_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "current_property_id": { + "name": "current_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "current_room_id": { + "name": "current_room_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "custom_fields": { + "name": "custom_fields", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "search_tsv": { + "name": "search_tsv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "assets_by_company": { + "name": "assets_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_type": { + "name": "assets_by_type", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_project": { + "name": "assets_by_project", + "columns": [ + { + "expression": "current_project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_property": { + "name": "assets_by_property", + "columns": [ + { + "expression": "current_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_room": { + "name": "assets_by_room", + "columns": [ + { + "expression": "current_room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_company_tag_uq": { + "name": "assets_company_tag_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_company_serial_uq": { + "name": "assets_company_serial_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "serial_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "assets_company_id_companies_id_fk": { + "name": "assets_company_id_companies_id_fk", + "tableFrom": "assets", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "assets_asset_type_id_asset_types_id_fk": { + "name": "assets_asset_type_id_asset_types_id_fk", + "tableFrom": "assets", + "tableTo": "asset_types", + "columnsFrom": [ + "asset_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_project_id_projects_id_fk": { + "name": "assets_current_project_id_projects_id_fk", + "tableFrom": "assets", + "tableTo": "projects", + "columnsFrom": [ + "current_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_property_id_properties_id_fk": { + "name": "assets_current_property_id_properties_id_fk", + "tableFrom": "assets", + "tableTo": "properties", + "columnsFrom": [ + "current_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_room_id_property_rooms_id_fk": { + "name": "assets_current_room_id_property_rooms_id_fk", + "tableFrom": "assets", + "tableTo": "property_rooms", + "columnsFrom": [ + "current_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "assets_created_by_users_id_fk": { + "name": "assets_created_by_users_id_fk", + "tableFrom": "assets", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_instances": { + "name": "checklist_instances", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "scope_type": { + "name": "scope_type", + "type": "checklist_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ci_by_scope": { + "name": "ci_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ci_by_company": { + "name": "ci_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_instances_company_id_companies_id_fk": { + "name": "checklist_instances_company_id_companies_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_instances_template_id_checklist_templates_id_fk": { + "name": "checklist_instances_template_id_checklist_templates_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "checklist_templates", + "columnsFrom": [ + "template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "checklist_instances_created_by_users_id_fk": { + "name": "checklist_instances_created_by_users_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_items": { + "name": "checklist_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "instance_id": { + "name": "instance_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "done": { + "name": "done", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "done_at": { + "name": "done_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "done_by": { + "name": "done_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "cit_by_instance": { + "name": "cit_by_instance", + "columns": [ + { + "expression": "instance_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_items_instance_id_checklist_instances_id_fk": { + "name": "checklist_items_instance_id_checklist_instances_id_fk", + "tableFrom": "checklist_items", + "tableTo": "checklist_instances", + "columnsFrom": [ + "instance_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_items_done_by_users_id_fk": { + "name": "checklist_items_done_by_users_id_fk", + "tableFrom": "checklist_items", + "tableTo": "users", + "columnsFrom": [ + "done_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_template_items": { + "name": "checklist_template_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "template_id": { + "name": "template_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "cti_by_template": { + "name": "cti_by_template", + "columns": [ + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_template_items_template_id_checklist_templates_id_fk": { + "name": "checklist_template_items_template_id_checklist_templates_id_fk", + "tableFrom": "checklist_template_items", + "tableTo": "checklist_templates", + "columnsFrom": [ + "template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_templates": { + "name": "checklist_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ct_by_company": { + "name": "ct_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_templates_company_id_companies_id_fk": { + "name": "checklist_templates_company_id_companies_id_fk", + "tableFrom": "checklist_templates", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_templates_created_by_users_id_fk": { + "name": "checklist_templates_created_by_users_id_fk", + "tableFrom": "checklist_templates", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.decision_events": { + "name": "decision_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "decision_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body_md": { + "name": "body_md", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "alternatives_considered": { + "name": "alternatives_considered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_impact": { + "name": "cost_impact", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "varchar(3)", + "primaryKey": false, + "notNull": false + }, + "approved_by": { + "name": "approved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "decided_at": { + "name": "decided_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "decided_by": { + "name": "decided_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "de_by_scope": { + "name": "de_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "decided_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "de_by_company": { + "name": "de_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "de_tags_gin": { + "name": "de_tags_gin", + "columns": [ + { + "expression": "tags", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "decision_events_company_id_companies_id_fk": { + "name": "decision_events_company_id_companies_id_fk", + "tableFrom": "decision_events", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "decision_events_approved_by_users_id_fk": { + "name": "decision_events_approved_by_users_id_fk", + "tableFrom": "decision_events", + "tableTo": "users", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "decision_events_decided_by_users_id_fk": { + "name": "decision_events_decided_by_users_id_fk", + "tableFrom": "decision_events", + "tableTo": "users", + "columnsFrom": [ + "decided_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.documents": { + "name": "documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "doc_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "sha256": { + "name": "sha256", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docs_by_scope": { + "name": "docs_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_by_company": { + "name": "docs_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_by_hash": { + "name": "docs_by_hash", + "columns": [ + { + "expression": "sha256", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_storage_key_uq": { + "name": "docs_storage_key_uq", + "columns": [ + { + "expression": "storage_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "documents_company_id_companies_id_fk": { + "name": "documents_company_id_companies_id_fk", + "tableFrom": "documents", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "documents_uploaded_by_users_id_fk": { + "name": "documents_uploaded_by_users_id_fk", + "tableFrom": "documents", + "tableTo": "users", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_expenses": { + "name": "property_expenses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "expense_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "varchar(3)", + "primaryKey": false, + "notNull": true + }, + "period_start": { + "name": "period_start", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "incurred_at": { + "name": "incurred_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "vendor": { + "name": "vendor", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "reference": { + "name": "reference", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "expenses_by_property_time": { + "name": "expenses_by_property_time", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "incurred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "expenses_by_property_kind": { + "name": "expenses_by_property_kind", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "incurred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "expenses_by_account": { + "name": "expenses_by_account", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_expenses_property_id_properties_id_fk": { + "name": "property_expenses_property_id_properties_id_fk", + "tableFrom": "property_expenses", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_expenses_account_id_property_accounts_id_fk": { + "name": "property_expenses_account_id_property_accounts_id_fk", + "tableFrom": "property_expenses", + "tableTo": "property_accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "property_expenses_created_by_users_id_fk": { + "name": "property_expenses_created_by_users_id_fk", + "tableFrom": "property_expenses", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.companies": { + "name": "companies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "settings_json": { + "name": "settings_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "companies_slug_unique": { + "name": "companies_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.company_users": { + "name": "company_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "company_users_uq": { + "name": "company_users_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "company_users_by_user": { + "name": "company_users_by_user", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "company_users_company_id_companies_id_fk": { + "name": "company_users_company_id_companies_id_fk", + "tableFrom": "company_users", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "company_users_user_id_users_id_fk": { + "name": "company_users_user_id_users_id_fk", + "tableFrom": "company_users", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(128)", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "active_company_id": { + "name": "active_company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sessions_by_user": { + "name": "sessions_by_user", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_by_expiry": { + "name": "sessions_by_expiry", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sessions_active_company_id_companies_id_fk": { + "name": "sessions_active_company_id_companies_id_fk", + "tableFrom": "sessions", + "tableTo": "companies", + "columnsFrom": [ + "active_company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true + }, + "email_normalized": { + "name": "email_normalized", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oidc_subject": { + "name": "oidc_subject", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "oidc_issuer": { + "name": "oidc_issuer", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_login_at": { + "name": "last_login_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "email_notifications": { + "name": "email_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "matrix_notifications": { + "name": "matrix_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "matrix_user_id": { + "name": "matrix_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "users_email_norm_uq": { + "name": "users_email_norm_uq", + "columns": [ + { + "expression": "email_normalized", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_oidc_uq": { + "name": "users_oidc_uq", + "columns": [ + { + "expression": "oidc_issuer", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "oidc_subject", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.properties": { + "name": "properties", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "address_line1": { + "name": "address_line1", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "address_line2": { + "name": "address_line2", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "city": { + "name": "city", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "region": { + "name": "region", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "varchar(32)", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "varchar(2)", + "primaryKey": false, + "notNull": false + }, + "lat": { + "name": "lat", + "type": "numeric(9, 6)", + "primaryKey": false, + "notNull": false + }, + "lng": { + "name": "lng", + "type": "numeric(9, 6)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "properties_by_company": { + "name": "properties_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "properties_company_id_companies_id_fk": { + "name": "properties_company_id_companies_id_fk", + "tableFrom": "properties", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "properties_created_by_users_id_fk": { + "name": "properties_created_by_users_id_fk", + "tableFrom": "properties", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_floors": { + "name": "property_floors", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "floors_by_property": { + "name": "floors_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "floors_property_label_uq": { + "name": "floors_property_label_uq", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "label", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_floors_property_id_properties_id_fk": { + "name": "property_floors_property_id_properties_id_fk", + "tableFrom": "property_floors", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_rooms": { + "name": "property_rooms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "floor_id": { + "name": "floor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "rooms_by_property": { + "name": "rooms_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rooms_by_floor": { + "name": "rooms_by_floor", + "columns": [ + { + "expression": "floor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rooms_floor_name_uq": { + "name": "rooms_floor_name_uq", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "floor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_rooms_property_id_properties_id_fk": { + "name": "property_rooms_property_id_properties_id_fk", + "tableFrom": "property_rooms", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_rooms_floor_id_property_floors_id_fk": { + "name": "property_rooms_floor_id_property_floors_id_fk", + "tableFrom": "property_rooms", + "tableTo": "property_floors", + "columnsFrom": [ + "floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.maintenance_events": { + "name": "maintenance_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "performed_at": { + "name": "performed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "performed_by": { + "name": "performed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "usage_reading": { + "name": "usage_reading", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "checklist_instance_id": { + "name": "checklist_instance_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "me_by_asset_time": { + "name": "me_by_asset_time", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "performed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "me_by_schedule": { + "name": "me_by_schedule", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "maintenance_events_asset_id_assets_id_fk": { + "name": "maintenance_events_asset_id_assets_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "maintenance_events_schedule_id_maintenance_schedules_id_fk": { + "name": "maintenance_events_schedule_id_maintenance_schedules_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "maintenance_schedules", + "columnsFrom": [ + "schedule_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_events_performed_by_users_id_fk": { + "name": "maintenance_events_performed_by_users_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "users", + "columnsFrom": [ + "performed_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_events_checklist_instance_id_checklist_instances_id_fk": { + "name": "maintenance_events_checklist_instance_id_checklist_instances_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "checklist_instances", + "columnsFrom": [ + "checklist_instance_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.maintenance_schedules": { + "name": "maintenance_schedules", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "schedule_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "interval_value": { + "name": "interval_value", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "interval_unit": { + "name": "interval_unit", + "type": "interval_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "last_serviced_at": { + "name": "last_serviced_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_due_at": { + "name": "next_due_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_due_usage": { + "name": "next_due_usage", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "checklist_template_id": { + "name": "checklist_template_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ms_by_asset": { + "name": "ms_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ms_by_next_due": { + "name": "ms_by_next_due", + "columns": [ + { + "expression": "next_due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "maintenance_schedules_asset_id_assets_id_fk": { + "name": "maintenance_schedules_asset_id_assets_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "maintenance_schedules_checklist_template_id_checklist_templates_id_fk": { + "name": "maintenance_schedules_checklist_template_id_checklist_templates_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "checklist_templates", + "columnsFrom": [ + "checklist_template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_schedules_created_by_users_id_fk": { + "name": "maintenance_schedules_created_by_users_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_readings": { + "name": "usage_readings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "reading": { + "name": "reading", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "interval_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "recorded_at": { + "name": "recorded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "recorded_by": { + "name": "recorded_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ur_by_asset_time": { + "name": "ur_by_asset_time", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recorded_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_readings_asset_id_assets_id_fk": { + "name": "usage_readings_asset_id_assets_id_fk", + "tableFrom": "usage_readings", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_readings_recorded_by_users_id_fk": { + "name": "usage_readings_recorded_by_users_id_fk", + "tableFrom": "usage_readings", + "tableTo": "users", + "columnsFrom": [ + "recorded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "start_date": { + "name": "start_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "projects_by_company": { + "name": "projects_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "projects_company_code_uq": { + "name": "projects_company_code_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "projects_company_id_companies_id_fk": { + "name": "projects_company_id_companies_id_fk", + "tableFrom": "projects", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "projects_created_by_users_id_fk": { + "name": "projects_created_by_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subtasks": { + "name": "subtasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "done": { + "name": "done", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "subtasks_by_task": { + "name": "subtasks_by_task", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "subtasks_task_id_tasks_id_fk": { + "name": "subtasks_task_id_tasks_id_fk", + "tableFrom": "subtasks", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "work_package_id": { + "name": "work_package_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'todo'" + }, + "assignee_id": { + "name": "assignee_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "due_at": { + "name": "due_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "tasks_by_wp": { + "name": "tasks_by_wp", + "columns": [ + { + "expression": "work_package_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_by_assignee": { + "name": "tasks_by_assignee", + "columns": [ + { + "expression": "assignee_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_status_due": { + "name": "tasks_status_due", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tasks_work_package_id_work_packages_id_fk": { + "name": "tasks_work_package_id_work_packages_id_fk", + "tableFrom": "tasks", + "tableTo": "work_packages", + "columnsFrom": [ + "work_package_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "tasks_assignee_id_users_id_fk": { + "name": "tasks_assignee_id_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": [ + "assignee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "tasks_created_by_users_id_fk": { + "name": "tasks_created_by_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_packages": { + "name": "work_packages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "work_packages_by_project": { + "name": "work_packages_by_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "work_packages_project_id_projects_id_fk": { + "name": "work_packages_project_id_projects_id_fk", + "tableFrom": "work_packages", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wiki_pages": { + "name": "wiki_pages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "wiki_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "current_revision_id": { + "name": "current_revision_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "wiki_by_scope": { + "name": "wiki_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "wiki_pages_company_id_companies_id_fk": { + "name": "wiki_pages_company_id_companies_id_fk", + "tableFrom": "wiki_pages", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "wiki_pages_created_by_users_id_fk": { + "name": "wiki_pages_created_by_users_id_fk", + "tableFrom": "wiki_pages", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wiki_revisions": { + "name": "wiki_revisions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body_md": { + "name": "body_md", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_tsv": { + "name": "body_tsv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "edited_by": { + "name": "edited_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "comment": { + "name": "comment", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "wiki_rev_page_rev_uq": { + "name": "wiki_rev_page_rev_uq", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "revision", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "wiki_rev_by_page": { + "name": "wiki_rev_by_page", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "revision", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "wiki_revisions_page_id_wiki_pages_id_fk": { + "name": "wiki_revisions_page_id_wiki_pages_id_fk", + "tableFrom": "wiki_revisions", + "tableTo": "wiki_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "wiki_revisions_edited_by_users_id_fk": { + "name": "wiki_revisions_edited_by_users_id_fk", + "tableFrom": "wiki_revisions", + "tableTo": "users", + "columnsFrom": [ + "edited_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "notification_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false + }, + "read_at": { + "name": "read_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "notifications_by_user_unread": { + "name": "notifications_by_user_unread", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "read_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notifications_by_user_company": { + "name": "notifications_by_user_company", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_company_id_companies_id_fk": { + "name": "notifications_company_id_companies_id_fk", + "tableFrom": "notifications", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.account_kind": { + "name": "account_kind", + "schema": "public", + "values": [ + "water", + "electricity", + "gas", + "internet", + "phone", + "cable", + "waste", + "other" + ] + }, + "public.audit_action": { + "name": "audit_action", + "schema": "public", + "values": [ + "create", + "update", + "delete", + "move", + "assign", + "complete", + "login", + "logout" + ] + }, + "public.checklist_scope": { + "name": "checklist_scope", + "schema": "public", + "values": [ + "task", + "subtask", + "maintenance_event", + "ad_hoc" + ] + }, + "public.container_kind": { + "name": "container_kind", + "schema": "public", + "values": [ + "project", + "property" + ] + }, + "public.decision_scope": { + "name": "decision_scope", + "schema": "public", + "values": [ + "project", + "property", + "asset", + "work_package" + ] + }, + "public.doc_scope": { + "name": "doc_scope", + "schema": "public", + "values": [ + "project", + "property", + "asset", + "work_package", + "decision_event" + ] + }, + "public.expense_kind": { + "name": "expense_kind", + "schema": "public", + "values": [ + "water", + "electricity", + "gas", + "internet", + "phone", + "cable", + "waste", + "maintenance", + "repair", + "cleaning", + "insurance", + "tax", + "rent", + "other" + ] + }, + "public.field_type": { + "name": "field_type", + "schema": "public", + "values": [ + "text", + "textarea", + "int", + "float", + "bool", + "date", + "ip", + "cidr", + "mac", + "enum", + "multi_enum", + "url", + "email", + "asset_ref" + ] + }, + "public.interval_unit": { + "name": "interval_unit", + "schema": "public", + "values": [ + "days", + "months", + "years", + "hours", + "cycles", + "km" + ] + }, + "public.notification_kind": { + "name": "notification_kind", + "schema": "public", + "values": [ + "task_assigned", + "asset_log_added", + "asset_moved", + "decision_created", + "maintenance_event_recorded", + "generic" + ] + }, + "public.role": { + "name": "role", + "schema": "public", + "values": [ + "admin", + "manager", + "user", + "viewer" + ] + }, + "public.schedule_kind": { + "name": "schedule_kind", + "schema": "public", + "values": [ + "time", + "usage" + ] + }, + "public.task_status": { + "name": "task_status", + "schema": "public", + "values": [ + "todo", + "doing", + "done", + "blocked" + ] + }, + "public.wiki_scope": { + "name": "wiki_scope", + "schema": "public", + "values": [ + "global", + "project", + "property" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0015_snapshot.json b/drizzle/meta/0015_snapshot.json new file mode 100644 index 0000000..18da381 --- /dev/null +++ b/drizzle/meta/0015_snapshot.json @@ -0,0 +1,4542 @@ +{ + "id": "bd351213-4b03-413d-a70c-be340f618beb", + "prevId": "4d5b9058-c852-4391-b06c-c39f088f84ce", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.property_accounts": { + "name": "property_accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "account_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "label": { + "name": "label", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "account_number": { + "name": "account_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "meter_number": { + "name": "meter_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "accounts_by_property": { + "name": "accounts_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_accounts_property_id_properties_id_fk": { + "name": "property_accounts_property_id_properties_id_fk", + "tableFrom": "property_accounts", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_field_defs": { + "name": "asset_field_defs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_type_id": { + "name": "asset_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "field_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enum_values": { + "name": "enum_values", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(32)", + "primaryKey": false, + "notNull": false + }, + "placeholder": { + "name": "placeholder", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "help_text": { + "name": "help_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deprecated_at": { + "name": "deprecated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_field_defs_type_key_uq": { + "name": "asset_field_defs_type_key_uq", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "asset_field_defs_by_type": { + "name": "asset_field_defs_by_type", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_field_defs_asset_type_id_asset_types_id_fk": { + "name": "asset_field_defs_asset_type_id_asset_types_id_fk", + "tableFrom": "asset_field_defs", + "tableTo": "asset_types", + "columnsFrom": [ + "asset_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_location_history": { + "name": "asset_location_history", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "from_kind": { + "name": "from_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "from_project_id": { + "name": "from_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "from_property_id": { + "name": "from_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "to_kind": { + "name": "to_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "to_project_id": { + "name": "to_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "to_property_id": { + "name": "to_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "moved_by": { + "name": "moved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "moved_at": { + "name": "moved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "alh_by_asset": { + "name": "alh_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "moved_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_location_history_asset_id_assets_id_fk": { + "name": "asset_location_history_asset_id_assets_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "asset_location_history_from_project_id_projects_id_fk": { + "name": "asset_location_history_from_project_id_projects_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "projects", + "columnsFrom": [ + "from_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_from_property_id_properties_id_fk": { + "name": "asset_location_history_from_property_id_properties_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "properties", + "columnsFrom": [ + "from_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_to_project_id_projects_id_fk": { + "name": "asset_location_history_to_project_id_projects_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "projects", + "columnsFrom": [ + "to_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_to_property_id_properties_id_fk": { + "name": "asset_location_history_to_property_id_properties_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "properties", + "columnsFrom": [ + "to_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "asset_location_history_moved_by_users_id_fk": { + "name": "asset_location_history_moved_by_users_id_fk", + "tableFrom": "asset_location_history", + "tableTo": "users", + "columnsFrom": [ + "moved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_logs": { + "name": "asset_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "author_id": { + "name": "author_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_logs_by_asset": { + "name": "asset_logs_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_logs_asset_id_assets_id_fk": { + "name": "asset_logs_asset_id_assets_id_fk", + "tableFrom": "asset_logs", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "asset_logs_author_id_users_id_fk": { + "name": "asset_logs_author_id_users_id_fk", + "tableFrom": "asset_logs", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.asset_types": { + "name": "asset_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_version": { + "name": "schema_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "asset_types_company_slug_uq": { + "name": "asset_types_company_slug_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "asset_types_by_parent": { + "name": "asset_types_by_parent", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "asset_types_company_id_companies_id_fk": { + "name": "asset_types_company_id_companies_id_fk", + "tableFrom": "asset_types", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.assets": { + "name": "assets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "asset_type_id": { + "name": "asset_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "serial_number": { + "name": "serial_number", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "manufacturer": { + "name": "manufacturer", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "purchased_at": { + "name": "purchased_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "current_container_kind": { + "name": "current_container_kind", + "type": "container_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "current_project_id": { + "name": "current_project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "current_property_id": { + "name": "current_property_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "current_room_id": { + "name": "current_room_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "custom_fields": { + "name": "custom_fields", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "search_tsv": { + "name": "search_tsv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "assets_by_company": { + "name": "assets_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_type": { + "name": "assets_by_type", + "columns": [ + { + "expression": "asset_type_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_project": { + "name": "assets_by_project", + "columns": [ + { + "expression": "current_project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_property": { + "name": "assets_by_property", + "columns": [ + { + "expression": "current_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_by_room": { + "name": "assets_by_room", + "columns": [ + { + "expression": "current_room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_company_tag_uq": { + "name": "assets_company_tag_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "assets_company_serial_uq": { + "name": "assets_company_serial_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "serial_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "assets_company_id_companies_id_fk": { + "name": "assets_company_id_companies_id_fk", + "tableFrom": "assets", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "assets_asset_type_id_asset_types_id_fk": { + "name": "assets_asset_type_id_asset_types_id_fk", + "tableFrom": "assets", + "tableTo": "asset_types", + "columnsFrom": [ + "asset_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_project_id_projects_id_fk": { + "name": "assets_current_project_id_projects_id_fk", + "tableFrom": "assets", + "tableTo": "projects", + "columnsFrom": [ + "current_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_property_id_properties_id_fk": { + "name": "assets_current_property_id_properties_id_fk", + "tableFrom": "assets", + "tableTo": "properties", + "columnsFrom": [ + "current_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "assets_current_room_id_property_rooms_id_fk": { + "name": "assets_current_room_id_property_rooms_id_fk", + "tableFrom": "assets", + "tableTo": "property_rooms", + "columnsFrom": [ + "current_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "assets_created_by_users_id_fk": { + "name": "assets_created_by_users_id_fk", + "tableFrom": "assets", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_instances": { + "name": "checklist_instances", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "scope_type": { + "name": "scope_type", + "type": "checklist_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ci_by_scope": { + "name": "ci_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ci_by_company": { + "name": "ci_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_instances_company_id_companies_id_fk": { + "name": "checklist_instances_company_id_companies_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_instances_template_id_checklist_templates_id_fk": { + "name": "checklist_instances_template_id_checklist_templates_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "checklist_templates", + "columnsFrom": [ + "template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "checklist_instances_created_by_users_id_fk": { + "name": "checklist_instances_created_by_users_id_fk", + "tableFrom": "checklist_instances", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_items": { + "name": "checklist_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "instance_id": { + "name": "instance_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "done": { + "name": "done", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "done_at": { + "name": "done_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "done_by": { + "name": "done_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "cit_by_instance": { + "name": "cit_by_instance", + "columns": [ + { + "expression": "instance_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_items_instance_id_checklist_instances_id_fk": { + "name": "checklist_items_instance_id_checklist_instances_id_fk", + "tableFrom": "checklist_items", + "tableTo": "checklist_instances", + "columnsFrom": [ + "instance_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_items_done_by_users_id_fk": { + "name": "checklist_items_done_by_users_id_fk", + "tableFrom": "checklist_items", + "tableTo": "users", + "columnsFrom": [ + "done_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_template_items": { + "name": "checklist_template_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "template_id": { + "name": "template_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "cti_by_template": { + "name": "cti_by_template", + "columns": [ + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_template_items_template_id_checklist_templates_id_fk": { + "name": "checklist_template_items_template_id_checklist_templates_id_fk", + "tableFrom": "checklist_template_items", + "tableTo": "checklist_templates", + "columnsFrom": [ + "template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.checklist_templates": { + "name": "checklist_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ct_by_company": { + "name": "ct_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "checklist_templates_company_id_companies_id_fk": { + "name": "checklist_templates_company_id_companies_id_fk", + "tableFrom": "checklist_templates", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "checklist_templates_created_by_users_id_fk": { + "name": "checklist_templates_created_by_users_id_fk", + "tableFrom": "checklist_templates", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.decision_events": { + "name": "decision_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "decision_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body_md": { + "name": "body_md", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "alternatives_considered": { + "name": "alternatives_considered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_impact": { + "name": "cost_impact", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "varchar(3)", + "primaryKey": false, + "notNull": false + }, + "approved_by": { + "name": "approved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "decided_at": { + "name": "decided_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "decided_by": { + "name": "decided_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "de_by_scope": { + "name": "de_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "decided_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "de_by_company": { + "name": "de_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "de_tags_gin": { + "name": "de_tags_gin", + "columns": [ + { + "expression": "tags", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "decision_events_company_id_companies_id_fk": { + "name": "decision_events_company_id_companies_id_fk", + "tableFrom": "decision_events", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "decision_events_approved_by_users_id_fk": { + "name": "decision_events_approved_by_users_id_fk", + "tableFrom": "decision_events", + "tableTo": "users", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "decision_events_decided_by_users_id_fk": { + "name": "decision_events_decided_by_users_id_fk", + "tableFrom": "decision_events", + "tableTo": "users", + "columnsFrom": [ + "decided_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.documents": { + "name": "documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "doc_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "sha256": { + "name": "sha256", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docs_by_scope": { + "name": "docs_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_by_company": { + "name": "docs_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_by_hash": { + "name": "docs_by_hash", + "columns": [ + { + "expression": "sha256", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_storage_key_uq": { + "name": "docs_storage_key_uq", + "columns": [ + { + "expression": "storage_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "documents_company_id_companies_id_fk": { + "name": "documents_company_id_companies_id_fk", + "tableFrom": "documents", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "documents_uploaded_by_users_id_fk": { + "name": "documents_uploaded_by_users_id_fk", + "tableFrom": "documents", + "tableTo": "users", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_expenses": { + "name": "property_expenses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "expense_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "varchar(3)", + "primaryKey": false, + "notNull": true + }, + "period_start": { + "name": "period_start", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "incurred_at": { + "name": "incurred_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "vendor": { + "name": "vendor", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "reference": { + "name": "reference", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "expenses_by_property_time": { + "name": "expenses_by_property_time", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "incurred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "expenses_by_property_kind": { + "name": "expenses_by_property_kind", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "incurred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "expenses_by_account": { + "name": "expenses_by_account", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_expenses_property_id_properties_id_fk": { + "name": "property_expenses_property_id_properties_id_fk", + "tableFrom": "property_expenses", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_expenses_account_id_property_accounts_id_fk": { + "name": "property_expenses_account_id_property_accounts_id_fk", + "tableFrom": "property_expenses", + "tableTo": "property_accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "property_expenses_created_by_users_id_fk": { + "name": "property_expenses_created_by_users_id_fk", + "tableFrom": "property_expenses", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.companies": { + "name": "companies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "settings_json": { + "name": "settings_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "companies_slug_unique": { + "name": "companies_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.company_users": { + "name": "company_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "company_users_uq": { + "name": "company_users_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "company_users_by_user": { + "name": "company_users_by_user", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "company_users_company_id_companies_id_fk": { + "name": "company_users_company_id_companies_id_fk", + "tableFrom": "company_users", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "company_users_user_id_users_id_fk": { + "name": "company_users_user_id_users_id_fk", + "tableFrom": "company_users", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(128)", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "active_company_id": { + "name": "active_company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sessions_by_user": { + "name": "sessions_by_user", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_by_expiry": { + "name": "sessions_by_expiry", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sessions_active_company_id_companies_id_fk": { + "name": "sessions_active_company_id_companies_id_fk", + "tableFrom": "sessions", + "tableTo": "companies", + "columnsFrom": [ + "active_company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true + }, + "email_normalized": { + "name": "email_normalized", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oidc_subject": { + "name": "oidc_subject", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "oidc_issuer": { + "name": "oidc_issuer", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_login_at": { + "name": "last_login_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "email_notifications": { + "name": "email_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "matrix_notifications": { + "name": "matrix_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "matrix_user_id": { + "name": "matrix_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "users_email_norm_uq": { + "name": "users_email_norm_uq", + "columns": [ + { + "expression": "email_normalized", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_oidc_uq": { + "name": "users_oidc_uq", + "columns": [ + { + "expression": "oidc_issuer", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "oidc_subject", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.properties": { + "name": "properties", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "address_line1": { + "name": "address_line1", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "address_line2": { + "name": "address_line2", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "city": { + "name": "city", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "region": { + "name": "region", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "varchar(32)", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "varchar(2)", + "primaryKey": false, + "notNull": false + }, + "lat": { + "name": "lat", + "type": "numeric(9, 6)", + "primaryKey": false, + "notNull": false + }, + "lng": { + "name": "lng", + "type": "numeric(9, 6)", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "properties_by_company": { + "name": "properties_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "properties_company_id_companies_id_fk": { + "name": "properties_company_id_companies_id_fk", + "tableFrom": "properties", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "properties_created_by_users_id_fk": { + "name": "properties_created_by_users_id_fk", + "tableFrom": "properties", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_floors": { + "name": "property_floors", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "floors_by_property": { + "name": "floors_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "floors_property_label_uq": { + "name": "floors_property_label_uq", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "label", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_floors_property_id_properties_id_fk": { + "name": "property_floors_property_id_properties_id_fk", + "tableFrom": "property_floors", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_rooms": { + "name": "property_rooms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "floor_id": { + "name": "floor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "rooms_by_property": { + "name": "rooms_by_property", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rooms_by_floor": { + "name": "rooms_by_floor", + "columns": [ + { + "expression": "floor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rooms_floor_name_uq": { + "name": "rooms_floor_name_uq", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "floor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_rooms_property_id_properties_id_fk": { + "name": "property_rooms_property_id_properties_id_fk", + "tableFrom": "property_rooms", + "tableTo": "properties", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_rooms_floor_id_property_floors_id_fk": { + "name": "property_rooms_floor_id_property_floors_id_fk", + "tableFrom": "property_rooms", + "tableTo": "property_floors", + "columnsFrom": [ + "floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.maintenance_events": { + "name": "maintenance_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "performed_at": { + "name": "performed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "performed_by": { + "name": "performed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "usage_reading": { + "name": "usage_reading", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "checklist_instance_id": { + "name": "checklist_instance_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "me_by_asset_time": { + "name": "me_by_asset_time", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "performed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "me_by_schedule": { + "name": "me_by_schedule", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "maintenance_events_asset_id_assets_id_fk": { + "name": "maintenance_events_asset_id_assets_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "maintenance_events_schedule_id_maintenance_schedules_id_fk": { + "name": "maintenance_events_schedule_id_maintenance_schedules_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "maintenance_schedules", + "columnsFrom": [ + "schedule_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_events_performed_by_users_id_fk": { + "name": "maintenance_events_performed_by_users_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "users", + "columnsFrom": [ + "performed_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_events_checklist_instance_id_checklist_instances_id_fk": { + "name": "maintenance_events_checklist_instance_id_checklist_instances_id_fk", + "tableFrom": "maintenance_events", + "tableTo": "checklist_instances", + "columnsFrom": [ + "checklist_instance_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.maintenance_schedules": { + "name": "maintenance_schedules", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "schedule_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "interval_value": { + "name": "interval_value", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "interval_unit": { + "name": "interval_unit", + "type": "interval_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "last_serviced_at": { + "name": "last_serviced_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_due_at": { + "name": "next_due_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_due_usage": { + "name": "next_due_usage", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": false + }, + "checklist_template_id": { + "name": "checklist_template_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ms_by_asset": { + "name": "ms_by_asset", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ms_by_next_due": { + "name": "ms_by_next_due", + "columns": [ + { + "expression": "next_due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "maintenance_schedules_asset_id_assets_id_fk": { + "name": "maintenance_schedules_asset_id_assets_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "maintenance_schedules_checklist_template_id_checklist_templates_id_fk": { + "name": "maintenance_schedules_checklist_template_id_checklist_templates_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "checklist_templates", + "columnsFrom": [ + "checklist_template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "maintenance_schedules_created_by_users_id_fk": { + "name": "maintenance_schedules_created_by_users_id_fk", + "tableFrom": "maintenance_schedules", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_readings": { + "name": "usage_readings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "asset_id": { + "name": "asset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "reading": { + "name": "reading", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "interval_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "recorded_at": { + "name": "recorded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "recorded_by": { + "name": "recorded_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ur_by_asset_time": { + "name": "ur_by_asset_time", + "columns": [ + { + "expression": "asset_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recorded_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_readings_asset_id_assets_id_fk": { + "name": "usage_readings_asset_id_assets_id_fk", + "tableFrom": "usage_readings", + "tableTo": "assets", + "columnsFrom": [ + "asset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_readings_recorded_by_users_id_fk": { + "name": "usage_readings_recorded_by_users_id_fk", + "tableFrom": "usage_readings", + "tableTo": "users", + "columnsFrom": [ + "recorded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "start_date": { + "name": "start_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "projects_by_company": { + "name": "projects_by_company", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "projects_company_code_uq": { + "name": "projects_company_code_uq", + "columns": [ + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "projects_company_id_companies_id_fk": { + "name": "projects_company_id_companies_id_fk", + "tableFrom": "projects", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "projects_created_by_users_id_fk": { + "name": "projects_created_by_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subtasks": { + "name": "subtasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "done": { + "name": "done", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "subtasks_by_task": { + "name": "subtasks_by_task", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "subtasks_task_id_tasks_id_fk": { + "name": "subtasks_task_id_tasks_id_fk", + "tableFrom": "subtasks", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "work_package_id": { + "name": "work_package_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'todo'" + }, + "assignee_id": { + "name": "assignee_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "due_at": { + "name": "due_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "tasks_by_wp": { + "name": "tasks_by_wp", + "columns": [ + { + "expression": "work_package_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_by_assignee": { + "name": "tasks_by_assignee", + "columns": [ + { + "expression": "assignee_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_status_due": { + "name": "tasks_status_due", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tasks_work_package_id_work_packages_id_fk": { + "name": "tasks_work_package_id_work_packages_id_fk", + "tableFrom": "tasks", + "tableTo": "work_packages", + "columnsFrom": [ + "work_package_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "tasks_assignee_id_users_id_fk": { + "name": "tasks_assignee_id_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": [ + "assignee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "tasks_created_by_users_id_fk": { + "name": "tasks_created_by_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_packages": { + "name": "work_packages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "work_packages_by_project": { + "name": "work_packages_by_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "work_packages_project_id_projects_id_fk": { + "name": "work_packages_project_id_projects_id_fk", + "tableFrom": "work_packages", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wiki_pages": { + "name": "wiki_pages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "wiki_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "scope_id": { + "name": "scope_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "current_revision_id": { + "name": "current_revision_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "wiki_by_scope": { + "name": "wiki_by_scope", + "columns": [ + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "wiki_pages_company_id_companies_id_fk": { + "name": "wiki_pages_company_id_companies_id_fk", + "tableFrom": "wiki_pages", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "wiki_pages_created_by_users_id_fk": { + "name": "wiki_pages_created_by_users_id_fk", + "tableFrom": "wiki_pages", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wiki_revisions": { + "name": "wiki_revisions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body_md": { + "name": "body_md", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_tsv": { + "name": "body_tsv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "edited_by": { + "name": "edited_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "comment": { + "name": "comment", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "wiki_rev_page_rev_uq": { + "name": "wiki_rev_page_rev_uq", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "revision", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "wiki_rev_by_page": { + "name": "wiki_rev_by_page", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "revision", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "wiki_revisions_page_id_wiki_pages_id_fk": { + "name": "wiki_revisions_page_id_wiki_pages_id_fk", + "tableFrom": "wiki_revisions", + "tableTo": "wiki_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "wiki_revisions_edited_by_users_id_fk": { + "name": "wiki_revisions_edited_by_users_id_fk", + "tableFrom": "wiki_revisions", + "tableTo": "users", + "columnsFrom": [ + "edited_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "notification_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false + }, + "read_at": { + "name": "read_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "notifications_by_user_unread": { + "name": "notifications_by_user_unread", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "read_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notifications_by_user_company": { + "name": "notifications_by_user_company", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "company_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_company_id_companies_id_fk": { + "name": "notifications_company_id_companies_id_fk", + "tableFrom": "notifications", + "tableTo": "companies", + "columnsFrom": [ + "company_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.account_kind": { + "name": "account_kind", + "schema": "public", + "values": [ + "water", + "electricity", + "gas", + "internet", + "phone", + "cable", + "waste", + "other" + ] + }, + "public.audit_action": { + "name": "audit_action", + "schema": "public", + "values": [ + "create", + "update", + "delete", + "move", + "assign", + "complete", + "login", + "logout" + ] + }, + "public.checklist_scope": { + "name": "checklist_scope", + "schema": "public", + "values": [ + "task", + "subtask", + "maintenance_event", + "ad_hoc" + ] + }, + "public.container_kind": { + "name": "container_kind", + "schema": "public", + "values": [ + "project", + "property" + ] + }, + "public.decision_scope": { + "name": "decision_scope", + "schema": "public", + "values": [ + "project", + "property", + "asset", + "work_package" + ] + }, + "public.doc_scope": { + "name": "doc_scope", + "schema": "public", + "values": [ + "project", + "property", + "asset", + "work_package", + "decision_event" + ] + }, + "public.expense_kind": { + "name": "expense_kind", + "schema": "public", + "values": [ + "water", + "electricity", + "gas", + "internet", + "phone", + "cable", + "waste", + "maintenance", + "repair", + "cleaning", + "insurance", + "tax", + "rent", + "other" + ] + }, + "public.field_type": { + "name": "field_type", + "schema": "public", + "values": [ + "text", + "textarea", + "int", + "float", + "bool", + "date", + "ip", + "cidr", + "mac", + "enum", + "multi_enum", + "url", + "email", + "asset_ref" + ] + }, + "public.interval_unit": { + "name": "interval_unit", + "schema": "public", + "values": [ + "days", + "months", + "years", + "hours", + "cycles", + "km" + ] + }, + "public.notification_kind": { + "name": "notification_kind", + "schema": "public", + "values": [ + "task_assigned", + "asset_log_added", + "asset_moved", + "decision_created", + "maintenance_event_recorded", + "generic" + ] + }, + "public.role": { + "name": "role", + "schema": "public", + "values": [ + "admin", + "manager", + "user", + "viewer" + ] + }, + "public.schedule_kind": { + "name": "schedule_kind", + "schema": "public", + "values": [ + "time", + "usage" + ] + }, + "public.task_status": { + "name": "task_status", + "schema": "public", + "values": [ + "todo", + "doing", + "done", + "blocked" + ] + }, + "public.wiki_scope": { + "name": "wiki_scope", + "schema": "public", + "values": [ + "global", + "project", + "property" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 4038d0d..e990fe7 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -99,6 +99,20 @@ "when": 1776930973516, "tag": "0013_notifications", "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1776932841675, + "tag": "0014_property_expenses", + "breakpoints": true + }, + { + "idx": 15, + "version": "7", + "when": 1776932900000, + "tag": "0015_expenses_updated_at_trigger", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/lib/components/ExpenseChart.svelte b/src/lib/components/ExpenseChart.svelte new file mode 100644 index 0000000..95d20ae --- /dev/null +++ b/src/lib/components/ExpenseChart.svelte @@ -0,0 +1,153 @@ + + +
+ {#if !hasAnyData} +
+ No {kinds.map((k) => EXPENSE_KIND_LABEL[k].toLowerCase()).join(' or ')} expenses in the last {n} months yet. +
+ {:else} + + + {#each yTicks as t} + + {fmtTick(t)} + {/each} + + + {#each series as p, i} + {#if i % xLabelStride === 0 || i === series.length - 1} + {monthLabel(p.month)} + {/if} + {/each} + + + {#each kinds as kind} + + {#each series as p, i} + + {EXPENSE_KIND_LABEL[kind]} — {monthLabel(p.month)} {p.month.slice(0, 4)}: {(p.totals[kind] ?? 0).toLocaleString()} {currency ?? ''} + + {/each} + {/each} + + +
+ {#each kinds as kind} + + + {EXPENSE_KIND_LABEL[kind]} + + {/each} + {#if currency} + Currency: {currency} + {/if} +
+ {/if} +
diff --git a/src/lib/expenses.ts b/src/lib/expenses.ts new file mode 100644 index 0000000..d78ffba --- /dev/null +++ b/src/lib/expenses.ts @@ -0,0 +1,51 @@ +// Client-safe expense constants. Mirrors expense_kind in schema/_shared.ts. + +export type ExpenseKind = + | 'water' + | 'electricity' + | 'gas' + | 'internet' + | 'phone' + | 'cable' + | 'waste' + | 'maintenance' + | 'repair' + | 'cleaning' + | 'insurance' + | 'tax' + | 'rent' + | 'other'; + +export const EXPENSE_KINDS: readonly ExpenseKind[] = [ + 'electricity', + 'water', + 'gas', + 'internet', + 'phone', + 'cable', + 'waste', + 'maintenance', + 'repair', + 'cleaning', + 'insurance', + 'tax', + 'rent', + 'other' +] as const; + +export const EXPENSE_KIND_LABEL: Record = { + water: 'Water', + electricity: 'Electricity', + gas: 'Gas', + internet: 'Internet', + phone: 'Phone', + cable: 'Cable TV', + waste: 'Waste', + maintenance: 'Maintenance', + repair: 'Repair', + cleaning: 'Cleaning', + insurance: 'Insurance', + tax: 'Tax', + rent: 'Rent', + other: 'Other' +}; diff --git a/src/lib/server/db/schema/_shared.ts b/src/lib/server/db/schema/_shared.ts index b4f6513..061f1d0 100644 --- a/src/lib/server/db/schema/_shared.ts +++ b/src/lib/server/db/schema/_shared.ts @@ -77,6 +77,22 @@ export const notificationKindEnum = pgEnum('notification_kind', [ 'maintenance_event_recorded', 'generic' ]); +export const expenseKindEnum = pgEnum('expense_kind', [ + 'water', + 'electricity', + 'gas', + 'internet', + 'phone', + 'cable', + 'waste', + 'maintenance', + 'repair', + 'cleaning', + 'insurance', + 'tax', + 'rent', + 'other' +]); export const pk = () => uuid('id').primaryKey().default(sql`gen_random_uuid()`); export const fk = (name: string) => uuid(name); diff --git a/src/lib/server/db/schema/expenses.ts b/src/lib/server/db/schema/expenses.ts new file mode 100644 index 0000000..b6ef4dc --- /dev/null +++ b/src/lib/server/db/schema/expenses.ts @@ -0,0 +1,46 @@ +import { pgTable, varchar, text, numeric, timestamp, index } from 'drizzle-orm/pg-core'; +import { properties } from './properties'; +import { propertyAccounts } from './accounts'; +import { users } from './tenancy'; +import { expenseKindEnum, pk, fk, createdAt, updatedAt } from './_shared'; + +// Recurring costs attached to a property: electricity bills, water bills, +// maintenance, repair jobs, insurance payments, etc. Optionally linked to a +// property_account so a utility bill ties to the actual meter on file. +export const propertyExpenses = pgTable( + 'property_expenses', + { + id: pk(), + propertyId: fk('property_id') + .notNull() + .references(() => properties.id, { onDelete: 'cascade' }), + // Optional link to the account (meter / ISP subscription) this expense + // was charged against. Account deletion doesn't wipe expense history. + accountId: fk('account_id').references(() => propertyAccounts.id, { + onDelete: 'set null' + }), + kind: expenseKindEnum('kind').notNull(), + amount: numeric('amount', { precision: 18, scale: 4 }).notNull(), + // ISO 4217 code. Defaults to company currency if blank at input time. + currency: varchar('currency', { length: 3 }).notNull(), + // Billing period (optional — some expenses are one-off, not periodic). + periodStart: timestamp('period_start', { withTimezone: true, mode: 'date' }), + periodEnd: timestamp('period_end', { withTimezone: true, mode: 'date' }), + // When the expense was incurred/dated (required for reporting). + incurredAt: timestamp('incurred_at', { withTimezone: true }).notNull(), + vendor: varchar('vendor', { length: 128 }), + reference: varchar('reference', { length: 128 }), // invoice #, job id, etc. + notes: text('notes'), + createdBy: fk('created_by').references(() => users.id, { onDelete: 'set null' }), + createdAt: createdAt(), + updatedAt: updatedAt() + }, + (t) => ({ + byPropertyTime: index('expenses_by_property_time').on(t.propertyId, t.incurredAt), + byPropertyKind: index('expenses_by_property_kind').on(t.propertyId, t.kind, t.incurredAt), + byAccount: index('expenses_by_account').on(t.accountId) + }) +); + +export type PropertyExpense = typeof propertyExpenses.$inferSelect; +export type NewPropertyExpense = typeof propertyExpenses.$inferInsert; diff --git a/src/lib/server/db/schema/index.ts b/src/lib/server/db/schema/index.ts index 3da7b41..470fe1f 100644 --- a/src/lib/server/db/schema/index.ts +++ b/src/lib/server/db/schema/index.ts @@ -3,6 +3,7 @@ export * from './tenancy'; export * from './properties'; export * from './rooms'; export * from './accounts'; +export * from './expenses'; export * from './assets'; export * from './documents'; export * from './checklists'; diff --git a/src/lib/server/services/expenses.ts b/src/lib/server/services/expenses.ts new file mode 100644 index 0000000..a4e124c --- /dev/null +++ b/src/lib/server/services/expenses.ts @@ -0,0 +1,283 @@ +import { and, asc, desc, eq, gte, inArray, isNull, lt, sql } from 'drizzle-orm'; +import { db } from '$lib/server/db/client'; +import { properties } from '$lib/server/db/schema/properties'; +import { propertyAccounts } from '$lib/server/db/schema/accounts'; +import { + propertyExpenses, + type NewPropertyExpense, + type PropertyExpense +} from '$lib/server/db/schema/expenses'; +import type { ExpenseKind } from '$lib/expenses'; + +export type { ExpenseKind }; + +async function assertProperty(companyId: string, propertyId: string): Promise { + const [p] = await db + .select({ id: properties.id }) + .from(properties) + .where( + and( + eq(properties.id, propertyId), + eq(properties.companyId, companyId), + isNull(properties.deletedAt) + ) + ) + .limit(1); + if (!p) throw new Error('property not found'); +} + +async function assertAccountInProperty( + companyId: string, + propertyId: string, + accountId: string +): Promise { + const [row] = await db + .select({ id: propertyAccounts.id }) + .from(propertyAccounts) + .innerJoin(properties, eq(properties.id, propertyAccounts.propertyId)) + .where( + and( + eq(propertyAccounts.id, accountId), + eq(propertyAccounts.propertyId, propertyId), + eq(properties.companyId, companyId) + ) + ) + .limit(1); + if (!row) throw new Error('account does not belong to this property'); +} + +export interface ExpenseCreateInput { + companyId: string; + propertyId: string; + createdBy: string; + kind: ExpenseKind; + amount: number; + currency: string; + incurredAt: Date; + periodStart?: Date | null; + periodEnd?: Date | null; + vendor?: string | null; + reference?: string | null; + notes?: string | null; + accountId?: string | null; +} + +export async function createExpense(input: ExpenseCreateInput): Promise<{ id: string }> { + await assertProperty(input.companyId, input.propertyId); + if (input.accountId) { + await assertAccountInProperty(input.companyId, input.propertyId, input.accountId); + } + if (!Number.isFinite(input.amount)) throw new Error('amount must be a number'); + const cur = input.currency.trim().toUpperCase(); + if (cur.length !== 3) throw new Error('currency must be a 3-letter ISO code'); + + const values: NewPropertyExpense = { + propertyId: input.propertyId, + accountId: input.accountId ?? null, + kind: input.kind, + amount: String(input.amount), + currency: cur, + incurredAt: input.incurredAt, + periodStart: input.periodStart ?? null, + periodEnd: input.periodEnd ?? null, + vendor: input.vendor?.trim() || null, + reference: input.reference?.trim() || null, + notes: input.notes?.trim() || null, + createdBy: input.createdBy + }; + const [row] = await db + .insert(propertyExpenses) + .values(values) + .returning({ id: propertyExpenses.id }); + return row; +} + +export interface ExpenseUpdateInput { + kind?: ExpenseKind; + amount?: number; + currency?: string; + incurredAt?: Date; + periodStart?: Date | null; + periodEnd?: Date | null; + vendor?: string | null; + reference?: string | null; + notes?: string | null; + accountId?: string | null; +} + +export async function updateExpense( + companyId: string, + expenseId: string, + patch: ExpenseUpdateInput +): Promise { + const [row] = await db + .select({ + id: propertyExpenses.id, + propertyId: propertyExpenses.propertyId + }) + .from(propertyExpenses) + .innerJoin(properties, eq(properties.id, propertyExpenses.propertyId)) + .where(and(eq(propertyExpenses.id, expenseId), eq(properties.companyId, companyId))) + .limit(1); + if (!row) throw new Error('expense not found'); + + if (patch.accountId !== undefined && patch.accountId !== null) { + await assertAccountInProperty(companyId, row.propertyId, patch.accountId); + } + + const update: Record = {}; + if (patch.kind !== undefined) update.kind = patch.kind; + if (patch.amount !== undefined) { + if (!Number.isFinite(patch.amount)) throw new Error('amount must be a number'); + update.amount = String(patch.amount); + } + if (patch.currency !== undefined) { + const cur = patch.currency.trim().toUpperCase(); + if (cur.length !== 3) throw new Error('currency must be a 3-letter ISO code'); + update.currency = cur; + } + if (patch.incurredAt !== undefined) update.incurredAt = patch.incurredAt; + if (patch.periodStart !== undefined) update.periodStart = patch.periodStart; + if (patch.periodEnd !== undefined) update.periodEnd = patch.periodEnd; + if (patch.vendor !== undefined) update.vendor = patch.vendor?.trim() || null; + if (patch.reference !== undefined) update.reference = patch.reference?.trim() || null; + if (patch.notes !== undefined) update.notes = patch.notes?.trim() || null; + if (patch.accountId !== undefined) update.accountId = patch.accountId; + + if (Object.keys(update).length === 0) return; + await db.update(propertyExpenses).set(update).where(eq(propertyExpenses.id, expenseId)); +} + +export async function deleteExpense(companyId: string, expenseId: string): Promise { + const [row] = await db + .select({ id: propertyExpenses.id }) + .from(propertyExpenses) + .innerJoin(properties, eq(properties.id, propertyExpenses.propertyId)) + .where(and(eq(propertyExpenses.id, expenseId), eq(properties.companyId, companyId))) + .limit(1); + if (!row) return; + await db.delete(propertyExpenses).where(eq(propertyExpenses.id, expenseId)); +} + +export async function listExpensesForProperty( + companyId: string, + propertyId: string, + opts: { kinds?: ExpenseKind[]; limit?: number } = {} +): Promise { + await assertProperty(companyId, propertyId); + const where = [eq(propertyExpenses.propertyId, propertyId)]; + if (opts.kinds && opts.kinds.length > 0) { + where.push(inArray(propertyExpenses.kind, opts.kinds)); + } + return db + .select() + .from(propertyExpenses) + .where(and(...where)) + .orderBy(desc(propertyExpenses.incurredAt)) + .limit(opts.limit ?? 500); +} + +export interface MonthlySeriesPoint { + // ISO month label e.g. 2026-04 + month: string; + // kind → summed amount in that month (only kinds with data present). + totals: Partial>; +} + +/** + * Sum expenses by (month, kind) for the last N months. Used by the chart on + * the property expenses tab. Currency is not converted — assumes the property + * is billed in a single currency; if mixed, the chart is still useful as a + * unit-less trend line. + */ +export async function monthlySeriesForProperty( + companyId: string, + propertyId: string, + kinds: ExpenseKind[], + months = 12 +): Promise { + await assertProperty(companyId, propertyId); + if (kinds.length === 0 || months < 1) return []; + + const now = new Date(); + const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (months - 1), 1)); + + const rows = await db + .select({ + month: sql`to_char(date_trunc('month', ${propertyExpenses.incurredAt}), 'YYYY-MM')`, + kind: propertyExpenses.kind, + total: sql`sum(${propertyExpenses.amount})` + }) + .from(propertyExpenses) + .where( + and( + eq(propertyExpenses.propertyId, propertyId), + inArray(propertyExpenses.kind, kinds), + gte(propertyExpenses.incurredAt, start), + lt(propertyExpenses.incurredAt, new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1))) + ) + ) + .groupBy( + sql`date_trunc('month', ${propertyExpenses.incurredAt})`, + propertyExpenses.kind + ); + + // Build a zero-filled series across all months. + const byMonth = new Map>>(); + for (let i = 0; i < months; i++) { + const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (months - 1 - i), 1)); + const label = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`; + byMonth.set(label, {}); + } + for (const r of rows) { + const bucket = byMonth.get(r.month); + if (!bucket) continue; + const n = Number(r.total); + if (Number.isFinite(n)) bucket[r.kind as ExpenseKind] = n; + } + return Array.from(byMonth.entries()).map(([month, totals]) => ({ month, totals })); +} + +/** Totals by kind for the last N days, plus a grand total. */ +export async function summaryForProperty( + companyId: string, + propertyId: string, + days = 365 +): Promise<{ + byKind: Partial>; + grandTotal: number; + currency: string | null; +}> { + await assertProperty(companyId, propertyId); + const since = new Date(Date.now() - days * 86_400_000); + const rows = await db + .select({ + kind: propertyExpenses.kind, + total: sql`sum(${propertyExpenses.amount})`, + currency: propertyExpenses.currency + }) + .from(propertyExpenses) + .where( + and( + eq(propertyExpenses.propertyId, propertyId), + gte(propertyExpenses.incurredAt, since) + ) + ) + .groupBy(propertyExpenses.kind, propertyExpenses.currency); + + const byKind: Partial> = {}; + let grand = 0; + const currencies = new Set(); + for (const r of rows) { + const n = Number(r.total); + if (!Number.isFinite(n)) continue; + byKind[r.kind as ExpenseKind] = (byKind[r.kind as ExpenseKind] ?? 0) + n; + grand += n; + currencies.add(r.currency); + } + const currency = currencies.size === 1 ? Array.from(currencies)[0] : null; + return { byKind, grandTotal: grand, currency }; +} + +// Unused import placeholder — asc kept in case we add a low-level listing helper later. +void asc; diff --git a/src/routes/(app)/properties/[id]/+layout.svelte b/src/routes/(app)/properties/[id]/+layout.svelte index 1b36700..19b0780 100644 --- a/src/routes/(app)/properties/[id]/+layout.svelte +++ b/src/routes/(app)/properties/[id]/+layout.svelte @@ -10,6 +10,7 @@ { href: `/properties/${data.property.id}/rooms`, label: 'Rooms' }, { href: `/properties/${data.property.id}/assets`, label: 'Assets' }, { href: `/properties/${data.property.id}/accounts`, label: 'Accounts' }, + { href: `/properties/${data.property.id}/expenses`, label: 'Expenses' }, { href: `/properties/${data.property.id}/documents`, label: 'Documents' } ]); diff --git a/src/routes/(app)/properties/[id]/expenses/+page.server.ts b/src/routes/(app)/properties/[id]/expenses/+page.server.ts new file mode 100644 index 0000000..e1c3a7a --- /dev/null +++ b/src/routes/(app)/properties/[id]/expenses/+page.server.ts @@ -0,0 +1,158 @@ +import { fail } from '@sveltejs/kit'; +import { and, eq } from 'drizzle-orm'; +import { z } from 'zod'; +import { requireCompany } from '$lib/server/auth/guards'; +import { db } from '$lib/server/db/client'; +import { propertyAccounts } from '$lib/server/db/schema/accounts'; +import { companies } from '$lib/server/db/schema/tenancy'; +import { + createExpense, + deleteExpense, + listExpensesForProperty, + monthlySeriesForProperty, + summaryForProperty, + updateExpense, + type ExpenseKind +} from '$lib/server/services/expenses'; +import type { Actions, PageServerLoad } from './$types'; + +const KINDS = [ + 'water', + 'electricity', + 'gas', + 'internet', + 'phone', + 'cable', + 'waste', + 'maintenance', + 'repair', + 'cleaning', + 'insurance', + 'tax', + 'rent', + 'other' +] as const; + +const Schema = z.object({ + kind: z.enum(KINDS), + amount: z.coerce.number().positive('Amount must be positive'), + currency: z.string().trim().length(3), + incurred_at: z.string().min(1, 'Date required'), + period_start: z.string().optional().or(z.literal('')), + period_end: z.string().optional().or(z.literal('')), + vendor: z.string().trim().max(128).optional().or(z.literal('')), + reference: z.string().trim().max(128).optional().or(z.literal('')), + notes: z.string().trim().max(2000).optional().or(z.literal('')), + account_id: z.string().uuid().optional().or(z.literal('')) +}); + +interface CompanySettings { + default_currency?: string; +} +function parseSettings(raw: string | null | undefined): CompanySettings { + if (!raw) return {}; + try { + return JSON.parse(raw) as CompanySettings; + } catch { + return {}; + } +} + +export const load: PageServerLoad = async ({ locals, params }) => { + const { company } = requireCompany(locals); + const [expenses, accounts, series, summary, [companyRow]] = await Promise.all([ + listExpensesForProperty(company.id, params.id), + db + .select({ + id: propertyAccounts.id, + kind: propertyAccounts.kind, + provider: propertyAccounts.provider, + label: propertyAccounts.label, + meterNumber: propertyAccounts.meterNumber + }) + .from(propertyAccounts) + .where(eq(propertyAccounts.propertyId, params.id)), + monthlySeriesForProperty(company.id, params.id, ['electricity', 'water'], 12), + summaryForProperty(company.id, params.id, 365), + db.select({ settings: companies.settings }).from(companies).where(eq(companies.id, company.id)).limit(1) + ]); + const defaultCurrency = parseSettings(companyRow?.settings ?? null).default_currency ?? 'USD'; + return { + expenses, + accounts, + chartSeries: series, + summary, + defaultCurrency + }; +}; + +export const actions: Actions = { + create: async ({ request, locals, params }) => { + const { company, user } = requireCompany(locals); + const form = await request.formData(); + const raw = Object.fromEntries(form.entries()) as Record; + const parsed = Schema.safeParse(raw); + if (!parsed.success) { + return fail(400, { error: parsed.error.errors[0]?.message ?? 'Invalid input', values: raw }); + } + const v = parsed.data; + try { + await createExpense({ + companyId: company.id, + propertyId: params.id, + createdBy: user.id, + kind: v.kind as ExpenseKind, + amount: v.amount, + currency: v.currency, + incurredAt: new Date(v.incurred_at), + periodStart: v.period_start ? new Date(v.period_start) : null, + periodEnd: v.period_end ? new Date(v.period_end) : null, + vendor: v.vendor || null, + reference: v.reference || null, + notes: v.notes || null, + accountId: v.account_id || null + }); + } catch (e) { + return fail(400, { error: (e as Error).message, values: raw }); + } + return { ok: true }; + }, + update: async ({ request, locals }) => { + const { company } = requireCompany(locals); + const form = await request.formData(); + const id = String(form.get('id') ?? ''); + if (!id) return fail(400, { error: 'Missing id' }); + const raw = Object.fromEntries(form.entries()) as Record; + const parsed = Schema.safeParse(raw); + if (!parsed.success) return fail(400, { error: parsed.error.errors[0]?.message ?? 'Invalid input' }); + const v = parsed.data; + try { + await updateExpense(company.id, id, { + kind: v.kind as ExpenseKind, + amount: v.amount, + currency: v.currency, + incurredAt: new Date(v.incurred_at), + periodStart: v.period_start ? new Date(v.period_start) : null, + periodEnd: v.period_end ? new Date(v.period_end) : null, + vendor: v.vendor || null, + reference: v.reference || null, + notes: v.notes || null, + accountId: v.account_id || null + }); + } catch (e) { + return fail(400, { error: (e as Error).message }); + } + return { ok: true }; + }, + delete: async ({ request, locals }) => { + const { company } = requireCompany(locals); + const form = await request.formData(); + const id = String(form.get('id') ?? ''); + if (!id) return fail(400, { error: 'Missing id' }); + await deleteExpense(company.id, id); + return { ok: true }; + } +}; + +// silence unused import for Drizzle helpers we might lean on later +void and; diff --git a/src/routes/(app)/properties/[id]/expenses/+page.svelte b/src/routes/(app)/properties/[id]/expenses/+page.svelte new file mode 100644 index 0000000..64ee4d5 --- /dev/null +++ b/src/routes/(app)/properties/[id]/expenses/+page.svelte @@ -0,0 +1,267 @@ + + +
+ +
+
+

+ Electricity & water · last 12 months +

+ + {chartCurrency} + +
+ +
+ + +
+
+
Last 12 months
+
+ {fmtMoney(data.summary.grandTotal, data.summary.currency ?? data.defaultCurrency)} +
+ {#if totalByKind.length > 0} +
+ {#each totalByKind.slice(0, 6) as [kind, total]} + {EXPENSE_KIND_LABEL[kind]}: {fmtMoney(total, data.summary.currency ?? data.defaultCurrency)} + {/each} +
+ {/if} +
+ +
+ + {#if form?.error} +
{form.error}
+ {/if} + + {#if showForm} +
async ({ update, result }) => { + await update(); + if (result.type === 'success') showForm = false; + }} + class="grid gap-3 rounded-lg border border-gray-200 bg-white p-4 sm:grid-cols-3 dark:border-gray-700 dark:bg-gray-800"> + + + + + + + + + + +
+ +
+
+ {/if} + + + {#if data.expenses.length === 0 && !showForm} +
+ No expenses recorded for this property yet. +
+ {:else if data.expenses.length > 0} +
+ + + + + + + + + + + + + + {#each data.expenses as e} + {#if editingId === e.id} + + + + {:else} + + + + + + + + + + {/if} + {/each} + +
DateKindAmountVendorReferenceNotes
+
async ({ update, result }) => { + await update(); + if (result.type === 'success') editingId = null; + }} + class="grid gap-2 sm:grid-cols-4"> + + + + + + + + + + + +
+ + +
+
+
{new Date(e.incurredAt).toLocaleDateString()}{EXPENSE_KIND_LABEL[e.kind as ExpenseKind]}{fmtMoney(e.amount, e.currency)}{e.vendor ?? '—'}{e.reference ?? '—'}{e.notes ?? '—'} +
+ +
+ + +
+
+
+
+ {/if} +