From ad7ba3ae4eeae706e27e012e1c8a6d6156cda958 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Sat, 13 Jun 2026 14:22:45 -0400 Subject: [PATCH] chore(10-01): generate + apply v1.1 DB migration (0001_famous_mad_thinker) - Generated via drizzle-kit generate from updated schema.ts - SQL is additive-only: CREATE TABLE app_config + ALTER TABLE ADD COLUMN (3x) + ADD CONSTRAINT UNIQUE - Applied to live dev MariaDB via direct SQL execution (drizzle-kit migrate journal hash mismatch with legacy migration tracking; DDL applied + hash recorded in __drizzle_migrations manually) - Verified: MIGRATION OK via live DB SHOW COLUMNS / SHOW TABLES query - No DROP/TRUNCATE statements in generated SQL (grep returns 0) --- .../db/migrations/0001_famous_mad_thinker.sql | 11 + .../src/db/migrations/meta/0001_snapshot.json | 1039 +++++++++++++++++ apps/api/src/db/migrations/meta/_journal.json | 7 + 3 files changed, 1057 insertions(+) create mode 100644 apps/api/src/db/migrations/0001_famous_mad_thinker.sql create mode 100644 apps/api/src/db/migrations/meta/0001_snapshot.json diff --git a/apps/api/src/db/migrations/0001_famous_mad_thinker.sql b/apps/api/src/db/migrations/0001_famous_mad_thinker.sql new file mode 100644 index 0000000..b83ff32 --- /dev/null +++ b/apps/api/src/db/migrations/0001_famous_mad_thinker.sql @@ -0,0 +1,11 @@ +CREATE TABLE `app_config` ( + `key` varchar(128) NOT NULL, + `value` text, + `updated_at` timestamp DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `app_config_key` PRIMARY KEY(`key`) +); +--> statement-breakpoint +ALTER TABLE `calendar_events` ADD `reminder_lead_minutes` int;--> statement-breakpoint +ALTER TABLE `member_credentials` ADD `provider_type` varchar(64) DEFAULT 'caldav' NOT NULL;--> statement-breakpoint +ALTER TABLE `users` ADD `is_admin` boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE `member_credentials` ADD CONSTRAINT `uniq_member_credential_user` UNIQUE(`user_id`); \ No newline at end of file diff --git a/apps/api/src/db/migrations/meta/0001_snapshot.json b/apps/api/src/db/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..9cfbd2e --- /dev/null +++ b/apps/api/src/db/migrations/meta/0001_snapshot.json @@ -0,0 +1,1039 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "6d39430a-6910-4c3d-88d6-98ca96d21dfa", + "prevId": "f296f762-5b02-4743-9758-a5b01f11754e", + "tables": { + "app_config": { + "name": "app_config", + "columns": { + "key": { + "name": "key", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_config_key": { + "name": "app_config_key", + "columns": [ + "key" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "calendar_events": { + "name": "calendar_events", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "calendar_id": { + "name": "calendar_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "uid": { + "name": "uid", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "etag": { + "name": "etag", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "object_url": { + "name": "object_url", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "raw_vevent": { + "name": "raw_vevent", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dtstart_utc": { + "name": "dtstart_utc", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dtstart_date": { + "name": "dtstart_date", + "type": "date", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "all_day": { + "name": "all_day", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "has_rrule": { + "name": "has_rrule", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "reminder_lead_minutes": { + "name": "reminder_lead_minutes", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": { + "idx_calendar_events_dtstart_utc": { + "name": "idx_calendar_events_dtstart_utc", + "columns": [ + "dtstart_utc" + ], + "isUnique": false + }, + "idx_calendar_events_dtstart_date": { + "name": "idx_calendar_events_dtstart_date", + "columns": [ + "dtstart_date" + ], + "isUnique": false + }, + "idx_calendar_events_has_rrule": { + "name": "idx_calendar_events_has_rrule", + "columns": [ + "has_rrule" + ], + "isUnique": false + } + }, + "foreignKeys": { + "calendar_events_calendar_id_calendars_id_fk": { + "name": "calendar_events_calendar_id_calendars_id_fk", + "tableFrom": "calendar_events", + "tableTo": "calendars", + "columnsFrom": [ + "calendar_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "calendar_events_id": { + "name": "calendar_events_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_calendar_uid": { + "name": "uniq_calendar_uid", + "columns": [ + "calendar_id", + "uid" + ] + } + }, + "checkConstraint": {} + }, + "calendar_outbox": { + "name": "calendar_outbox", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "operation": { + "name": "operation", + "type": "enum('create','update','delete')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','done','failed','dead')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "uid": { + "name": "uid", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "calendar_url": { + "name": "calendar_url", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "calendar_object_url": { + "name": "calendar_object_url", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "etag": { + "name": "etag", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "attempt_count": { + "name": "attempt_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": { + "idx_outbox_user_status": { + "name": "idx_outbox_user_status", + "columns": [ + "user_id", + "status" + ], + "isUnique": false + }, + "idx_outbox_next_attempt": { + "name": "idx_outbox_next_attempt", + "columns": [ + "next_attempt_at", + "status" + ], + "isUnique": false + }, + "idx_outbox_uid": { + "name": "idx_outbox_uid", + "columns": [ + "uid" + ], + "isUnique": false + } + }, + "foreignKeys": { + "calendar_outbox_user_id_users_id_fk": { + "name": "calendar_outbox_user_id_users_id_fk", + "tableFrom": "calendar_outbox", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "calendar_outbox_id": { + "name": "calendar_outbox_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "calendars": { + "name": "calendars", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "varchar(7)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ctag": { + "name": "ctag", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sync_token": { + "name": "sync_token", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_shared": { + "name": "is_shared", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": { + "idx_calendars_user_id": { + "name": "idx_calendars_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "calendars_user_id_users_id_fk": { + "name": "calendars_user_id_users_id_fk", + "tableFrom": "calendars", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "calendars_id": { + "name": "calendars_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_calendar_user_url": { + "name": "uniq_calendar_user_url", + "columns": [ + "user_id", + "url" + ] + } + }, + "checkConstraint": {} + }, + "list_items": { + "name": "list_items", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "list_id": { + "name": "list_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "text": { + "name": "text", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checked": { + "name": "checked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "rank": { + "name": "rank", + "type": "varchar(255) COLLATE utf8mb4_bin", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": { + "idx_list_items_list_id_rank": { + "name": "idx_list_items_list_id_rank", + "columns": [ + "list_id", + "rank" + ], + "isUnique": false + }, + "idx_list_items_list_id_checked": { + "name": "idx_list_items_list_id_checked", + "columns": [ + "list_id", + "checked" + ], + "isUnique": false + } + }, + "foreignKeys": { + "list_items_list_id_lists_id_fk": { + "name": "list_items_list_id_lists_id_fk", + "tableFrom": "list_items", + "tableTo": "lists", + "columnsFrom": [ + "list_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "list_items_id": { + "name": "list_items_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "list_shares": { + "name": "list_shares", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "list_id": { + "name": "list_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": { + "idx_list_shares_user_id": { + "name": "idx_list_shares_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "list_shares_list_id_lists_id_fk": { + "name": "list_shares_list_id_lists_id_fk", + "tableFrom": "list_shares", + "tableTo": "lists", + "columnsFrom": [ + "list_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "list_shares_user_id_users_id_fk": { + "name": "list_shares_user_id_users_id_fk", + "tableFrom": "list_shares", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "list_shares_id": { + "name": "list_shares_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_list_share": { + "name": "uniq_list_share", + "columns": [ + "list_id", + "user_id" + ] + } + }, + "checkConstraint": {} + }, + "lists": { + "name": "lists", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "owner_id": { + "name": "owner_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_shared": { + "name": "is_shared", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": { + "idx_lists_owner_id": { + "name": "idx_lists_owner_id", + "columns": [ + "owner_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "lists_owner_id_users_id_fk": { + "name": "lists_owner_id_users_id_fk", + "tableFrom": "lists", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "lists_id": { + "name": "lists_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "member_credentials": { + "name": "member_credentials", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "encrypted_password": { + "name": "encrypted_password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fastmail_email": { + "name": "fastmail_email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + }, + "provider_type": { + "name": "provider_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'caldav'" + } + }, + "indexes": { + "idx_member_credentials_user_id": { + "name": "idx_member_credentials_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "member_credentials_user_id_users_id_fk": { + "name": "member_credentials_user_id_users_id_fk", + "tableFrom": "member_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "member_credentials_id": { + "name": "member_credentials_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_member_credential_user": { + "name": "uniq_member_credential_user", + "columns": [ + "user_id" + ] + } + }, + "checkConstraint": {} + }, + "push_subscriptions": { + "name": "push_subscriptions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "varchar(2048)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "p256dh": { + "name": "p256dh", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auth": { + "name": "auth", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": { + "idx_push_subscriptions_user_id": { + "name": "idx_push_subscriptions_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "push_subscriptions_user_id_users_id_fk": { + "name": "push_subscriptions_user_id_users_id_fk", + "tableFrom": "push_subscriptions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "push_subscriptions_id": { + "name": "push_subscriptions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_push_endpoint": { + "name": "uniq_push_endpoint", + "columns": [ + "endpoint" + ] + } + }, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "oidc_iss": { + "name": "oidc_iss", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "oidc_sub": { + "name": "oidc_sub", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "uniq_oidc_identity": { + "name": "uniq_oidc_identity", + "columns": [ + "oidc_iss", + "oidc_sub" + ] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} \ No newline at end of file diff --git a/apps/api/src/db/migrations/meta/_journal.json b/apps/api/src/db/migrations/meta/_journal.json index ef83d68..7d064b8 100644 --- a/apps/api/src/db/migrations/meta/_journal.json +++ b/apps/api/src/db/migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1781202409890, "tag": "0000_baseline", "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1781374816375, + "tag": "0001_famous_mad_thinker", + "breakpoints": true } ] } \ No newline at end of file