From 6ec9ab6c2a6fc7f76b5ae7260e5ae0f2fc1dd48e Mon Sep 17 00:00:00 2001 From: Lleyton Gray Date: Tue, 18 Aug 2026 16:42:15 -0700 Subject: [PATCH 1/2] feat: add analytics schema (redacted PII) for BI tools --- apps/dashboard/drizzle.config.ts | 6 +- apps/dashboard/drizzle/0029_blue_wolfpack.sql | 18 + .../dashboard/drizzle/meta/0029_snapshot.json | 3666 +++++++++++++++++ apps/dashboard/drizzle/meta/_journal.json | 7 + .../src/lib/server/db/analytics.schema.ts | 318 ++ 5 files changed, 4014 insertions(+), 1 deletion(-) create mode 100644 apps/dashboard/drizzle/0029_blue_wolfpack.sql create mode 100644 apps/dashboard/drizzle/meta/0029_snapshot.json create mode 100644 apps/dashboard/src/lib/server/db/analytics.schema.ts diff --git a/apps/dashboard/drizzle.config.ts b/apps/dashboard/drizzle.config.ts index 6a7e8e3..839fc8d 100644 --- a/apps/dashboard/drizzle.config.ts +++ b/apps/dashboard/drizzle.config.ts @@ -13,7 +13,11 @@ function getDbCredentials(connectionString: string) { } export default defineConfig({ - schema: './src/lib/server/db/schema.ts', + schema: [ + './src/lib/server/db/schema.ts', + './src/lib/server/db/auth.schema.ts', + './src/lib/server/db/analytics.schema.ts' + ], dialect: 'postgresql', ...(url ? { dbCredentials: getDbCredentials(url) } : {}), verbose: true, diff --git a/apps/dashboard/drizzle/0029_blue_wolfpack.sql b/apps/dashboard/drizzle/0029_blue_wolfpack.sql new file mode 100644 index 0000000..f9644d4 --- /dev/null +++ b/apps/dashboard/drizzle/0029_blue_wolfpack.sql @@ -0,0 +1,18 @@ +CREATE SCHEMA "analytics"; +--> statement-breakpoint +CREATE VIEW "analytics"."api_tokens" AS (select "id", "user_id", "created_at" from "api_tokens");--> statement-breakpoint +CREATE VIEW "analytics"."base_images" AS (select "id", "file_path", "name", "version", "description", "short_name", "icon", "color", "is_official", "logo_svg", "accent_color", "image_type", "secure_boot", "isa", "sort_order" from "base_images");--> statement-breakpoint +CREATE VIEW "analytics"."billing_meters" AS (select "id", "project_id", "resource_type", "resource_id", "feature_id", "units", "last_metered_at", "active", "created_at", "ended_at" from "billing_meters");--> statement-breakpoint +CREATE VIEW "analytics"."billing_usage_events" AS (select "id", "project_id", "resource_type", "resource_id", "feature_id", "quantity", "period_start", "period_end", "idempotency_key", "sync_status", "sync_error", "synced_at", "created_at" from "billing_usage_events");--> statement-breakpoint +CREATE VIEW "analytics"."ipam_allocations" AS (select "id", "ipam_prefix_id", "associated_vm_id", "family", "address", "prefix", "prefix_length", "created_at" from "ipam_allocations");--> statement-breakpoint +CREATE VIEW "analytics"."ipam_prefixes" AS (select "id", "name", "cidr", "family", "disabled", "ipv6_use_transit_address", "whitelist_start", "whitelist_end", "gateway_address", "created_at" from "ipam_prefixes");--> statement-breakpoint +CREATE VIEW "analytics"."ipam_ptr_records" AS (select "id", "ipam_allocation_id", "address", "value", "created_at" from "ipam_ptr_records");--> statement-breakpoint +CREATE VIEW "analytics"."ipam_settings" AS (select "id", "default_ptr_format_ipv4", "default_ptr_format_ipv6" from "ipam_settings");--> statement-breakpoint +CREATE VIEW "analytics"."member" AS (select "id", "organization_id", "user_id", "role", "created_at" from "member");--> statement-breakpoint +CREATE VIEW "analytics"."organization" AS (select "id", "name", "slug", "created_at", "billing_exempt", "disabled", "deleted_at" from "organization");--> statement-breakpoint +CREATE VIEW "analytics"."project_billing_customers" AS (select "project_id", "sync_status", "sync_error", "last_synced_at", "past_due_since", "suspended_at", "created_at", "updated_at" from "project_billing_customers");--> statement-breakpoint +CREATE VIEW "analytics"."ssh_keys" AS (select "id", "user_id", "fingerprint" from "ssh_keys");--> statement-breakpoint +CREATE VIEW "analytics"."user" AS (select "id", "email_verified", "created_at", "updated_at", "role", "banned", "ban_expires", "two_factor_enabled", "is_admin", "billing_exempt" from "user");--> statement-breakpoint +CREATE VIEW "analytics"."vm_types" AS (select "id", "name", "isa", "cores", "ram_capacity", "storage_amount", "rate", "cap", "sort_order" from "vm_types");--> statement-breakpoint +CREATE VIEW "analytics"."vms" AS (select "id", "proxmox_id", "proxmox_node", "last_known_ipv4", "last_known_ipv6", "last_known_status", "last_known_uptime", "last_known_at", "active", "deleted_at", "owner_project_id", "vm_type_id", "creation_date", "created_at", "backend", "status", "status_error" from "vms");--> statement-breakpoint +CREATE VIEW "analytics"."volumes" AS (select "id", "size", "owner_project_id", "associated_vm_id", "created_at" from "volumes"); \ No newline at end of file diff --git a/apps/dashboard/drizzle/meta/0029_snapshot.json b/apps/dashboard/drizzle/meta/0029_snapshot.json new file mode 100644 index 0000000..508fddf --- /dev/null +++ b/apps/dashboard/drizzle/meta/0029_snapshot.json @@ -0,0 +1,3666 @@ +{ + "id": "c6afabf0-439d-40df-b743-ed76ee468dc5", + "prevId": "fa8d27a2-da3c-42f8-87e7-8436f32155d6", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.api_tokens": { + "name": "api_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "api_tokens_user_id_index": { + "name": "api_tokens_user_id_index", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.base_images": { + "name": "base_images", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "short_name": { + "name": "short_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'bg-gray-600'" + }, + "is_official": { + "name": "is_official", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "logo_svg": { + "name": "logo_svg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accent_color": { + "name": "accent_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#6b7280'" + }, + "image_type": { + "name": "image_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'qcow2'" + }, + "secure_boot": { + "name": "secure_boot", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "isa": { + "name": "isa", + "type": "vm_isa", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.billing_meters": { + "name": "billing_meters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "billing_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "feature_id": { + "name": "feature_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "units": { + "name": "units", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_metered_at": { + "name": "last_metered_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "billing_meters_resource_index": { + "name": "billing_meters_resource_index", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "billing_meters_active_last_metered_at_index": { + "name": "billing_meters_active_last_metered_at_index", + "columns": [ + { + "expression": "active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_metered_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "billing_meters_project_active_index": { + "name": "billing_meters_project_active_index", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.billing_usage_events": { + "name": "billing_usage_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "billing_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "feature_id": { + "name": "feature_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "period_start": { + "name": "period_start", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "period_end": { + "name": "period_end", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_status": { + "name": "sync_status", + "type": "billing_sync_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "synced_at": { + "name": "synced_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "billing_usage_events_idempotency_key_index": { + "name": "billing_usage_events_idempotency_key_index", + "columns": [ + { + "expression": "idempotency_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "billing_usage_events_project_created_at_index": { + "name": "billing_usage_events_project_created_at_index", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "billing_usage_events_sync_status_created_at_index": { + "name": "billing_usage_events_sync_status_created_at_index", + "columns": [ + { + "expression": "sync_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "billing_usage_events_resource_index": { + "name": "billing_usage_events_resource_index", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ip_assignments": { + "name": "ip_assignments", + "schema": "", + "columns": { + "ip": { + "name": "ip", + "type": "inet", + "primaryKey": false, + "notNull": true + }, + "ip_block_id": { + "name": "ip_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "associated_vm_id": { + "name": "associated_vm_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ip_assignments_ip_block_id_index": { + "name": "ip_assignments_ip_block_id_index", + "columns": [ + { + "expression": "ip_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ip_assignments_associated_vm_id_index": { + "name": "ip_assignments_associated_vm_id_index", + "columns": [ + { + "expression": "associated_vm_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ip_assignments_ip_block_id_ip_blocks_id_fk": { + "name": "ip_assignments_ip_block_id_ip_blocks_id_fk", + "tableFrom": "ip_assignments", + "tableTo": "ip_blocks", + "columnsFrom": [ + "ip_block_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "ip_assignments_associated_vm_id_vms_id_fk": { + "name": "ip_assignments_associated_vm_id_vms_id_fk", + "tableFrom": "ip_assignments", + "tableTo": "vms", + "columnsFrom": [ + "associated_vm_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ip_blocks": { + "name": "ip_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ip_block": { + "name": "ip_block", + "type": "cidr", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ipam_allocations": { + "name": "ipam_allocations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ipam_prefix_id": { + "name": "ipam_prefix_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "associated_vm_id": { + "name": "associated_vm_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "family": { + "name": "family", + "type": "ip_family", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "cidr", + "primaryKey": false, + "notNull": false + }, + "prefix_length": { + "name": "prefix_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "mac_address": { + "name": "mac_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "indexes": { + "ipam_allocations_ipam_prefix_id_index": { + "name": "ipam_allocations_ipam_prefix_id_index", + "columns": [ + { + "expression": "ipam_prefix_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_allocations_associated_vm_id_index": { + "name": "ipam_allocations_associated_vm_id_index", + "columns": [ + { + "expression": "associated_vm_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_allocations_vm_family_index": { + "name": "ipam_allocations_vm_family_index", + "columns": [ + { + "expression": "associated_vm_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "family", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_allocations_address_index": { + "name": "ipam_allocations_address_index", + "columns": [ + { + "expression": "address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_allocations_prefix_index": { + "name": "ipam_allocations_prefix_index", + "columns": [ + { + "expression": "prefix", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ipam_allocations_ipam_prefix_id_ipam_prefixes_id_fk": { + "name": "ipam_allocations_ipam_prefix_id_ipam_prefixes_id_fk", + "tableFrom": "ipam_allocations", + "tableTo": "ipam_prefixes", + "columnsFrom": [ + "ipam_prefix_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "ipam_allocations_associated_vm_id_vms_id_fk": { + "name": "ipam_allocations_associated_vm_id_vms_id_fk", + "tableFrom": "ipam_allocations", + "tableTo": "vms", + "columnsFrom": [ + "associated_vm_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ipam_prefixes": { + "name": "ipam_prefixes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cidr": { + "name": "cidr", + "type": "cidr", + "primaryKey": false, + "notNull": true + }, + "family": { + "name": "family", + "type": "ip_family", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ipv6_use_transit_address": { + "name": "ipv6_use_transit_address", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "whitelist_start": { + "name": "whitelist_start", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "whitelist_end": { + "name": "whitelist_end", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "gateway_address": { + "name": "gateway_address", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "bunny_dns_zone": { + "name": "bunny_dns_zone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "indexes": { + "ipam_prefixes_cidr_index": { + "name": "ipam_prefixes_cidr_index", + "columns": [ + { + "expression": "cidr", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_prefixes_family_disabled_index": { + "name": "ipam_prefixes_family_disabled_index", + "columns": [ + { + "expression": "family", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "disabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ipam_ptr_records": { + "name": "ipam_ptr_records", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ipam_allocation_id": { + "name": "ipam_allocation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "inet", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bunny_record_id": { + "name": "bunny_record_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "indexes": { + "ipam_ptr_records_ipam_allocation_id_index": { + "name": "ipam_ptr_records_ipam_allocation_id_index", + "columns": [ + { + "expression": "ipam_allocation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ipam_ptr_records_address_index": { + "name": "ipam_ptr_records_address_index", + "columns": [ + { + "expression": "address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ipam_ptr_records_ipam_allocation_id_ipam_allocations_id_fk": { + "name": "ipam_ptr_records_ipam_allocation_id_ipam_allocations_id_fk", + "tableFrom": "ipam_ptr_records", + "tableTo": "ipam_allocations", + "columnsFrom": [ + "ipam_allocation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ipam_settings": { + "name": "ipam_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "default_ptr_format_ipv4": { + "name": "default_ptr_format_ipv4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_ptr_format_ipv6": { + "name": "default_ptr_format_ipv6", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payment_periods": { + "name": "payment_periods", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "vm_id": { + "name": "vm_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "end_date": { + "name": "end_date", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rate": { + "name": "rate", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "cap": { + "name": "cap", + "type": "numeric", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "payment_periods_vm_id_index": { + "name": "payment_periods_vm_id_index", + "columns": [ + { + "expression": "vm_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payment_periods_user_id_index": { + "name": "payment_periods_user_id_index", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "payment_periods_vm_id_vms_id_fk": { + "name": "payment_periods_vm_id_vms_id_fk", + "tableFrom": "payment_periods", + "tableTo": "vms", + "columnsFrom": [ + "vm_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_billing_customers": { + "name": "project_billing_customers", + "schema": "", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "autumn_customer_id": { + "name": "autumn_customer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sync_status": { + "name": "sync_status", + "type": "billing_sync_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "past_due_since": { + "name": "past_due_since", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "project_billing_customers_autumn_customer_id_index": { + "name": "project_billing_customers_autumn_customer_id_index", + "columns": [ + { + "expression": "autumn_customer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ssh_keys": { + "name": "ssh_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ssh_keys_user_id_index": { + "name": "ssh_keys_user_id_index", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vm_types": { + "name": "vm_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isa": { + "name": "isa", + "type": "vm_isa", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "cores": { + "name": "cores", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "ram_capacity": { + "name": "ram_capacity", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storage_amount": { + "name": "storage_amount", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rate": { + "name": "rate", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "cap": { + "name": "cap", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "autumn_feature_id": { + "name": "autumn_feature_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vms": { + "name": "vms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "proxmox_id": { + "name": "proxmox_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "proxmox_node": { + "name": "proxmox_node", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_known_ipv4": { + "name": "last_known_ipv4", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "last_known_ipv6": { + "name": "last_known_ipv6", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "last_known_status": { + "name": "last_known_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_known_uptime": { + "name": "last_known_uptime", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_known_at": { + "name": "last_known_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "owner_project_id": { + "name": "owner_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vm_type_id": { + "name": "vm_type_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "creation_date": { + "name": "creation_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + }, + "backend": { + "name": "backend", + "type": "vm_backend", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "vm_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'provisioning'" + }, + "status_error": { + "name": "status_error", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "vms_owner_project_id_index": { + "name": "vms_owner_project_id_index", + "columns": [ + { + "expression": "owner_project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "vms_owner_project_active_index": { + "name": "vms_owner_project_active_index", + "columns": [ + { + "expression": "owner_project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "vms_proxmox_id_index": { + "name": "vms_proxmox_id_index", + "columns": [ + { + "expression": "proxmox_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "vms_owner_project_id_organization_id_fk": { + "name": "vms_owner_project_id_organization_id_fk", + "tableFrom": "vms", + "tableTo": "organization", + "columnsFrom": [ + "owner_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "vms_vm_type_id_vm_types_id_fk": { + "name": "vms_vm_type_id_vm_types_id_fk", + "tableFrom": "vms", + "tableTo": "vm_types", + "columnsFrom": [ + "vm_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.volumes": { + "name": "volumes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "owner_project_id": { + "name": "owner_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "associated_vm_id": { + "name": "associated_vm_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "indexes": { + "volumes_owner_project_id_index": { + "name": "volumes_owner_project_id_index", + "columns": [ + { + "expression": "owner_project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "volumes_associated_vm_id_index": { + "name": "volumes_associated_vm_id_index", + "columns": [ + { + "expression": "associated_vm_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "volumes_owner_project_id_organization_id_fk": { + "name": "volumes_owner_project_id_organization_id_fk", + "tableFrom": "volumes", + "tableTo": "organization", + "columnsFrom": [ + "owner_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "volumes_associated_vm_id_vms_id_fk": { + "name": "volumes_associated_vm_id_vms_id_fk", + "tableFrom": "volumes", + "tableTo": "vms", + "columnsFrom": [ + "associated_vm_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_exempt": { + "name": "billing_exempt", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "organization_slug_uidx": { + "name": "organization_slug_uidx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.passkey": { + "name": "passkey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "device_type": { + "name": "device_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backed_up": { + "name": "backed_up", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "aaguid": { + "name": "aaguid", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "passkey_userId_idx": { + "name": "passkey_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "passkey_credentialID_idx": { + "name": "passkey_credentialID_idx", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "passkey_user_id_user_id_fk": { + "name": "passkey_user_id_user_id_fk", + "tableFrom": "passkey", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.two_factor": { + "name": "two_factor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backup_codes": { + "name": "backup_codes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "failed_verification_count": { + "name": "failed_verification_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "locked_until": { + "name": "locked_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "twoFactor_secret_idx": { + "name": "twoFactor_secret_idx", + "columns": [ + { + "expression": "secret", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "twoFactor_userId_idx": { + "name": "twoFactor_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "two_factor_user_id_user_id_fk": { + "name": "two_factor_user_id_user_id_fk", + "tableFrom": "two_factor", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_exempt": { + "name": "billing_exempt", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.billing_resource_type": { + "name": "billing_resource_type", + "schema": "public", + "values": [ + "vm", + "volume" + ] + }, + "public.billing_sync_status": { + "name": "billing_sync_status", + "schema": "public", + "values": [ + "pending", + "synced", + "failed", + "abandoned" + ] + }, + "public.ip_family": { + "name": "ip_family", + "schema": "public", + "values": [ + "ipv4", + "ipv6" + ] + }, + "public.vm_backend": { + "name": "vm_backend", + "schema": "public", + "values": [ + "proxmox" + ] + }, + "public.vm_isa": { + "name": "vm_isa", + "schema": "public", + "values": [ + "x86", + "arm", + "risc-v" + ] + }, + "public.vm_status": { + "name": "vm_status", + "schema": "public", + "values": [ + "provisioning", + "ready", + "error", + "deleting" + ] + } + }, + "schemas": { + "analytics": "analytics" + }, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": { + "analytics.api_tokens": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"id\", \"user_id\", \"created_at\" from \"api_tokens\"", + "name": "api_tokens", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.base_images": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "short_name": { + "name": "short_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'bg-gray-600'" + }, + "is_official": { + "name": "is_official", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "logo_svg": { + "name": "logo_svg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accent_color": { + "name": "accent_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#6b7280'" + }, + "image_type": { + "name": "image_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'qcow2'" + }, + "secure_boot": { + "name": "secure_boot", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "isa": { + "name": "isa", + "type": "vm_isa", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "definition": "select \"id\", \"file_path\", \"name\", \"version\", \"description\", \"short_name\", \"icon\", \"color\", \"is_official\", \"logo_svg\", \"accent_color\", \"image_type\", \"secure_boot\", \"isa\", \"sort_order\" from \"base_images\"", + "name": "base_images", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.billing_meters": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "billing_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "feature_id": { + "name": "feature_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "units": { + "name": "units", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_metered_at": { + "name": "last_metered_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "definition": "select \"id\", \"project_id\", \"resource_type\", \"resource_id\", \"feature_id\", \"units\", \"last_metered_at\", \"active\", \"created_at\", \"ended_at\" from \"billing_meters\"", + "name": "billing_meters", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.billing_usage_events": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "billing_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "feature_id": { + "name": "feature_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "period_start": { + "name": "period_start", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "period_end": { + "name": "period_end", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sync_status": { + "name": "sync_status", + "type": "billing_sync_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "synced_at": { + "name": "synced_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"id\", \"project_id\", \"resource_type\", \"resource_id\", \"feature_id\", \"quantity\", \"period_start\", \"period_end\", \"idempotency_key\", \"sync_status\", \"sync_error\", \"synced_at\", \"created_at\" from \"billing_usage_events\"", + "name": "billing_usage_events", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.ipam_allocations": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ipam_prefix_id": { + "name": "ipam_prefix_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "associated_vm_id": { + "name": "associated_vm_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "family": { + "name": "family", + "type": "ip_family", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "cidr", + "primaryKey": false, + "notNull": false + }, + "prefix_length": { + "name": "prefix_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "definition": "select \"id\", \"ipam_prefix_id\", \"associated_vm_id\", \"family\", \"address\", \"prefix\", \"prefix_length\", \"created_at\" from \"ipam_allocations\"", + "name": "ipam_allocations", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.ipam_prefixes": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cidr": { + "name": "cidr", + "type": "cidr", + "primaryKey": false, + "notNull": true + }, + "family": { + "name": "family", + "type": "ip_family", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ipv6_use_transit_address": { + "name": "ipv6_use_transit_address", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "whitelist_start": { + "name": "whitelist_start", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "whitelist_end": { + "name": "whitelist_end", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "gateway_address": { + "name": "gateway_address", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "definition": "select \"id\", \"name\", \"cidr\", \"family\", \"disabled\", \"ipv6_use_transit_address\", \"whitelist_start\", \"whitelist_end\", \"gateway_address\", \"created_at\" from \"ipam_prefixes\"", + "name": "ipam_prefixes", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.ipam_ptr_records": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ipam_allocation_id": { + "name": "ipam_allocation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "inet", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "definition": "select \"id\", \"ipam_allocation_id\", \"address\", \"value\", \"created_at\" from \"ipam_ptr_records\"", + "name": "ipam_ptr_records", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.ipam_settings": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "default_ptr_format_ipv4": { + "name": "default_ptr_format_ipv4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_ptr_format_ipv6": { + "name": "default_ptr_format_ipv6", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "definition": "select \"id\", \"default_ptr_format_ipv4\", \"default_ptr_format_ipv6\" from \"ipam_settings\"", + "name": "ipam_settings", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.member": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"id\", \"organization_id\", \"user_id\", \"role\", \"created_at\" from \"member\"", + "name": "member", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.organization": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "billing_exempt": { + "name": "billing_exempt", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "definition": "select \"id\", \"name\", \"slug\", \"created_at\", \"billing_exempt\", \"disabled\", \"deleted_at\" from \"organization\"", + "name": "organization", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.project_billing_customers": { + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "sync_status": { + "name": "sync_status", + "type": "billing_sync_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "past_due_since": { + "name": "past_due_since", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"project_id\", \"sync_status\", \"sync_error\", \"last_synced_at\", \"past_due_since\", \"suspended_at\", \"created_at\", \"updated_at\" from \"project_billing_customers\"", + "name": "project_billing_customers", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.ssh_keys": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"id\", \"user_id\", \"fingerprint\" from \"ssh_keys\"", + "name": "ssh_keys", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.user": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_exempt": { + "name": "billing_exempt", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "definition": "select \"id\", \"email_verified\", \"created_at\", \"updated_at\", \"role\", \"banned\", \"ban_expires\", \"two_factor_enabled\", \"is_admin\", \"billing_exempt\" from \"user\"", + "name": "user", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.vm_types": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isa": { + "name": "isa", + "type": "vm_isa", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "cores": { + "name": "cores", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "ram_capacity": { + "name": "ram_capacity", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storage_amount": { + "name": "storage_amount", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rate": { + "name": "rate", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "cap": { + "name": "cap", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "definition": "select \"id\", \"name\", \"isa\", \"cores\", \"ram_capacity\", \"storage_amount\", \"rate\", \"cap\", \"sort_order\" from \"vm_types\"", + "name": "vm_types", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.vms": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "proxmox_id": { + "name": "proxmox_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "proxmox_node": { + "name": "proxmox_node", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_known_ipv4": { + "name": "last_known_ipv4", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "last_known_ipv6": { + "name": "last_known_ipv6", + "type": "inet", + "primaryKey": false, + "notNull": false + }, + "last_known_status": { + "name": "last_known_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_known_uptime": { + "name": "last_known_uptime", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_known_at": { + "name": "last_known_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "owner_project_id": { + "name": "owner_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vm_type_id": { + "name": "vm_type_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "creation_date": { + "name": "creation_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + }, + "backend": { + "name": "backend", + "type": "vm_backend", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "vm_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'provisioning'" + }, + "status_error": { + "name": "status_error", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "definition": "select \"id\", \"proxmox_id\", \"proxmox_node\", \"last_known_ipv4\", \"last_known_ipv6\", \"last_known_status\", \"last_known_uptime\", \"last_known_at\", \"active\", \"deleted_at\", \"owner_project_id\", \"vm_type_id\", \"creation_date\", \"created_at\", \"backend\", \"status\", \"status_error\" from \"vms\"", + "name": "vms", + "schema": "analytics", + "isExisting": false, + "materialized": false + }, + "analytics.volumes": { + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "owner_project_id": { + "name": "owner_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "associated_vm_id": { + "name": "associated_vm_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "(extract(epoch from now()) * 1000)::bigint" + } + }, + "definition": "select \"id\", \"size\", \"owner_project_id\", \"associated_vm_id\", \"created_at\" from \"volumes\"", + "name": "volumes", + "schema": "analytics", + "isExisting": false, + "materialized": false + } + }, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dashboard/drizzle/meta/_journal.json b/apps/dashboard/drizzle/meta/_journal.json index 32f2866..6389483 100644 --- a/apps/dashboard/drizzle/meta/_journal.json +++ b/apps/dashboard/drizzle/meta/_journal.json @@ -204,6 +204,13 @@ "when": 1785817075068, "tag": "0028_flashy_sleeper", "breakpoints": true + }, + { + "idx": 29, + "version": "7", + "when": 1787096478484, + "tag": "0029_blue_wolfpack", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dashboard/src/lib/server/db/analytics.schema.ts b/apps/dashboard/src/lib/server/db/analytics.schema.ts new file mode 100644 index 0000000..8925385 --- /dev/null +++ b/apps/dashboard/src/lib/server/db/analytics.schema.ts @@ -0,0 +1,318 @@ +/** + * A read-only mirror of the public schema for analytics/BI tools such as Metabase. + * Basically you can think of this as the same as public, but with fields redacted for privacy and security reasons. + * When setting this up, please make sure to set up a role which ONLY has read-only access to this schema. + * + * Here's an example: + * -- Add LOGIN and a password when you set this up for real, otherwise nothing can connect. + * CREATE ROLE analytics_role; + * -- In newer versions of postgres, the following revoke shouldn't be necessary, but it doesn't hurt. + * REVOKE ALL ON SCHEMA public FROM analytics_role; + * -- Grants only read-only access to analytics_role. + * GRANT USAGE ON SCHEMA analytics TO analytics_role; + * GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO analytics_role; + * -- If we create new tables in this schema in the future, we want the role to be able to access them. + * -- Run this one as the role that runs migrations: it attaches to whoever executes it, so running + * -- it as an admin instead means later views silently never become readable. + * -- You can think of this as modifying the default permission set your migration role uses when creating tables in the schema. + * ALTER DEFAULT PRIVILEGES IN SCHEMA analytics GRANT SELECT ON TABLES TO analytics_role; + */ + +import { pgSchema } from 'drizzle-orm/pg-core'; +import { + apiTokens, + baseImages, + billingMeters, + billingUsageEvents, + ipamAllocations, + ipamPrefixes, + ipamPtrRecords, + ipamSettings, + member, + organization, + projectBillingCustomers, + sshKeys, + user, + vmTypes, + vms, + volumes +} from './schema'; + +export const analyticsSchema = pgSchema('analytics'); + +// Organization + +export const analyticsOrganization = analyticsSchema.view('organization').as((qb) => + qb + .select({ + id: organization.id, + name: organization.name, + slug: organization.slug, + createdAt: organization.createdAt, + billingExempt: organization.billingExempt, + disabled: organization.disabled, + deletedAt: organization.deletedAt + }) + .from(organization) +); + +// Member + +export const analyticsMember = analyticsSchema.view('member').as((qb) => + qb + .select({ + id: member.id, + organizationId: member.organizationId, + userId: member.userId, + role: member.role, + createdAt: member.createdAt + }) + .from(member) +); + +// User + +export const analyticsUser = analyticsSchema.view('user').as((qb) => + qb + .select({ + id: user.id, + emailVerified: user.emailVerified, + createdAt: user.createdAt, + updatedAt: user.updatedAt, + role: user.role, + banned: user.banned, + banExpires: user.banExpires, + twoFactorEnabled: user.twoFactorEnabled, + isAdmin: user.isAdmin, + billingExempt: user.billingExempt + }) + .from(user) +); + +// VM Types + +export const analyticsVmTypes = analyticsSchema.view('vm_types').as((qb) => + qb + .select({ + id: vmTypes.id, + name: vmTypes.name, + isa: vmTypes.isa, + cores: vmTypes.cores, + ramCapacity: vmTypes.ramCapacity, + storageAmount: vmTypes.storageAmount, + rate: vmTypes.rate, + cap: vmTypes.cap, + sortOrder: vmTypes.sortOrder + }) + .from(vmTypes) +); + +// VMs + +export const analyticsVms = analyticsSchema.view('vms').as((qb) => + qb + .select({ + id: vms.id, + proxmoxId: vms.proxmoxId, + proxmoxNode: vms.proxmoxNode, + lastKnownIpv4: vms.lastKnownIpv4, + lastKnownIpv6: vms.lastKnownIpv6, + lastKnownStatus: vms.lastKnownStatus, + lastKnownUptime: vms.lastKnownUptime, + lastKnownAt: vms.lastKnownAt, + active: vms.active, + deletedAt: vms.deletedAt, + ownerProjectId: vms.ownerProjectId, + vmTypeId: vms.vmTypeId, + creationDate: vms.creationDate, + createdAt: vms.createdAt, + backend: vms.backend, + status: vms.status, + statusError: vms.statusError + }) + .from(vms) +); + +// Volumes + +export const analyticsVolumes = analyticsSchema.view('volumes').as((qb) => + qb + .select({ + id: volumes.id, + size: volumes.size, + ownerProjectId: volumes.ownerProjectId, + associatedVmId: volumes.associatedVmId, + createdAt: volumes.createdAt + }) + .from(volumes) +); + +// Project Billing Customers + +export const analyticsProjectBillingCustomers = analyticsSchema + .view('project_billing_customers') + .as((qb) => + qb + .select({ + projectId: projectBillingCustomers.projectId, + syncStatus: projectBillingCustomers.syncStatus, + syncError: projectBillingCustomers.syncError, + lastSyncedAt: projectBillingCustomers.lastSyncedAt, + pastDueSince: projectBillingCustomers.pastDueSince, + suspendedAt: projectBillingCustomers.suspendedAt, + createdAt: projectBillingCustomers.createdAt, + updatedAt: projectBillingCustomers.updatedAt + }) + .from(projectBillingCustomers) + ); + +// Billing Meters + +export const analyticsBillingMeters = analyticsSchema.view('billing_meters').as((qb) => + qb + .select({ + id: billingMeters.id, + projectId: billingMeters.projectId, + resourceType: billingMeters.resourceType, + resourceId: billingMeters.resourceId, + featureId: billingMeters.featureId, + units: billingMeters.units, + lastMeteredAt: billingMeters.lastMeteredAt, + active: billingMeters.active, + createdAt: billingMeters.createdAt, + endedAt: billingMeters.endedAt + }) + .from(billingMeters) +); + +// Billing Usage Events + +export const analyticsBillingUsageEvents = analyticsSchema.view('billing_usage_events').as((qb) => + qb + .select({ + id: billingUsageEvents.id, + projectId: billingUsageEvents.projectId, + resourceType: billingUsageEvents.resourceType, + resourceId: billingUsageEvents.resourceId, + featureId: billingUsageEvents.featureId, + quantity: billingUsageEvents.quantity, + periodStart: billingUsageEvents.periodStart, + periodEnd: billingUsageEvents.periodEnd, + idempotencyKey: billingUsageEvents.idempotencyKey, + syncStatus: billingUsageEvents.syncStatus, + syncError: billingUsageEvents.syncError, + syncedAt: billingUsageEvents.syncedAt, + createdAt: billingUsageEvents.createdAt + }) + .from(billingUsageEvents) +); + +// IPAM Prefixes + +export const analyticsIpamPrefixes = analyticsSchema.view('ipam_prefixes').as((qb) => + qb + .select({ + id: ipamPrefixes.id, + name: ipamPrefixes.name, + cidr: ipamPrefixes.cidr, + family: ipamPrefixes.family, + disabled: ipamPrefixes.disabled, + ipv6UseTransitAddress: ipamPrefixes.ipv6UseTransitAddress, + whitelistStart: ipamPrefixes.whitelistStart, + whitelistEnd: ipamPrefixes.whitelistEnd, + gatewayAddress: ipamPrefixes.gatewayAddress, + createdAt: ipamPrefixes.createdAt + }) + .from(ipamPrefixes) +); + +// IPAM Allocations + +export const analyticsIpamAllocations = analyticsSchema.view('ipam_allocations').as((qb) => + qb + .select({ + id: ipamAllocations.id, + ipamPrefixId: ipamAllocations.ipamPrefixId, + associatedVmId: ipamAllocations.associatedVmId, + family: ipamAllocations.family, + address: ipamAllocations.address, + prefix: ipamAllocations.prefix, + prefixLength: ipamAllocations.prefixLength, + createdAt: ipamAllocations.createdAt + }) + .from(ipamAllocations) +); + +// IPAM Settings + +export const analyticsIpamSettings = analyticsSchema.view('ipam_settings').as((qb) => + qb + .select({ + id: ipamSettings.id, + defaultPtrFormatIpv4: ipamSettings.defaultPtrFormatIpv4, + defaultPtrFormatIpv6: ipamSettings.defaultPtrFormatIpv6 + }) + .from(ipamSettings) +); + +// IPAM PTR Records + +export const analyticsIpamPtrRecords = analyticsSchema.view('ipam_ptr_records').as((qb) => + qb + .select({ + id: ipamPtrRecords.id, + ipamAllocationId: ipamPtrRecords.ipamAllocationId, + address: ipamPtrRecords.address, + value: ipamPtrRecords.value, + createdAt: ipamPtrRecords.createdAt + }) + .from(ipamPtrRecords) +); + +// SSH Keys + +export const analyticsSshKeys = analyticsSchema.view('ssh_keys').as((qb) => + qb + .select({ + id: sshKeys.id, + userId: sshKeys.userId, + fingerprint: sshKeys.fingerprint + }) + .from(sshKeys) +); + +// API Tokens + +export const analyticsApiTokens = analyticsSchema.view('api_tokens').as((qb) => + qb + .select({ + id: apiTokens.id, + userId: apiTokens.userId, + createdAt: apiTokens.createdAt + }) + .from(apiTokens) +); + +// Base Images + +export const analyticsBaseImages = analyticsSchema.view('base_images').as((qb) => + qb + .select({ + id: baseImages.id, + filePath: baseImages.filePath, + name: baseImages.name, + version: baseImages.version, + description: baseImages.description, + shortName: baseImages.shortName, + icon: baseImages.icon, + color: baseImages.color, + isOfficial: baseImages.isOfficial, + logoSvg: baseImages.logoSvg, + accentColor: baseImages.accentColor, + imageType: baseImages.imageType, + secureBoot: baseImages.secureBoot, + isa: baseImages.isa, + sortOrder: baseImages.sortOrder + }) + .from(baseImages) +); From 0f6e7e0b69bef564953464b26b29fc290048607c Mon Sep 17 00:00:00 2001 From: Lleyton Gray Date: Tue, 18 Aug 2026 16:56:11 -0700 Subject: [PATCH 2/2] fix: remove analytics schema comment on request of @addidotlol --- .../src/lib/server/db/analytics.schema.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/apps/dashboard/src/lib/server/db/analytics.schema.ts b/apps/dashboard/src/lib/server/db/analytics.schema.ts index 8925385..fd8382f 100644 --- a/apps/dashboard/src/lib/server/db/analytics.schema.ts +++ b/apps/dashboard/src/lib/server/db/analytics.schema.ts @@ -1,23 +1,3 @@ -/** - * A read-only mirror of the public schema for analytics/BI tools such as Metabase. - * Basically you can think of this as the same as public, but with fields redacted for privacy and security reasons. - * When setting this up, please make sure to set up a role which ONLY has read-only access to this schema. - * - * Here's an example: - * -- Add LOGIN and a password when you set this up for real, otherwise nothing can connect. - * CREATE ROLE analytics_role; - * -- In newer versions of postgres, the following revoke shouldn't be necessary, but it doesn't hurt. - * REVOKE ALL ON SCHEMA public FROM analytics_role; - * -- Grants only read-only access to analytics_role. - * GRANT USAGE ON SCHEMA analytics TO analytics_role; - * GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO analytics_role; - * -- If we create new tables in this schema in the future, we want the role to be able to access them. - * -- Run this one as the role that runs migrations: it attaches to whoever executes it, so running - * -- it as an admin instead means later views silently never become readable. - * -- You can think of this as modifying the default permission set your migration role uses when creating tables in the schema. - * ALTER DEFAULT PRIVILEGES IN SCHEMA analytics GRANT SELECT ON TABLES TO analytics_role; - */ - import { pgSchema } from 'drizzle-orm/pg-core'; import { apiTokens,