From 20a845991b5bab46d832837da35b79633c956852 Mon Sep 17 00:00:00 2001 From: Lane Campbell Date: Wed, 8 Apr 2026 09:52:45 -0700 Subject: [PATCH] fix: add missing data column to user_profiles migration The user edit page (/admin/users/:id/edit) crashes with a 500 error because the user_profiles table is missing the `data` column. PR #747 added code querying this column but placed the migration in the wrong directory (src/db/migrations/ instead of migrations/), so it was never bundled or executed. - Add data column to migration 032 CREATE TABLE (fresh installs) - Add migration 035 ALTER TABLE for existing databases - Add data column to app-level migration 018 - Remove misplaced 0011_user_profiles_data.sql - Regenerate migrations bundle Co-Authored-By: Claude Opus 4.6 --- my-sonicjs-app/migrations/018_user_profiles.sql | 1 + packages/core/migrations/032_user_profiles.sql | 1 + .../035_user_profiles_data_column.sql | 17 +++++++++++++++++ packages/core/src/db/migrations-bundle.ts | 11 +++++++++-- .../db/migrations/0011_user_profiles_data.sql | 5 ----- 5 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 packages/core/migrations/035_user_profiles_data_column.sql delete mode 100644 packages/core/src/db/migrations/0011_user_profiles_data.sql diff --git a/my-sonicjs-app/migrations/018_user_profiles.sql b/my-sonicjs-app/migrations/018_user_profiles.sql index 55c241733..78256800d 100644 --- a/my-sonicjs-app/migrations/018_user_profiles.sql +++ b/my-sonicjs-app/migrations/018_user_profiles.sql @@ -14,6 +14,7 @@ CREATE TABLE IF NOT EXISTS user_profiles ( website TEXT, location TEXT, date_of_birth INTEGER, + data TEXT DEFAULT '{}', created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000), updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000) diff --git a/packages/core/migrations/032_user_profiles.sql b/packages/core/migrations/032_user_profiles.sql index 2e8a05075..25040101b 100644 --- a/packages/core/migrations/032_user_profiles.sql +++ b/packages/core/migrations/032_user_profiles.sql @@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS user_profiles ( website TEXT, location TEXT, date_of_birth INTEGER, + data TEXT DEFAULT '{}', created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000), updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000) diff --git a/packages/core/migrations/035_user_profiles_data_column.sql b/packages/core/migrations/035_user_profiles_data_column.sql new file mode 100644 index 000000000..866a3763a --- /dev/null +++ b/packages/core/migrations/035_user_profiles_data_column.sql @@ -0,0 +1,17 @@ +-- Migration 035: Add data column to user_profiles +-- Stores custom profile fields as JSON (used by user-profiles plugin) +-- +-- The data column was missing from migration 032 when the user-profiles plugin +-- was added in PR #747. The ALTER TABLE migration was placed in the wrong +-- directory (src/db/migrations/) so it was never bundled or executed. +-- This caused the user edit page to crash with a 500 error because the route +-- queries SELECT ... data FROM user_profiles. +-- +-- Migration 032 has been updated to include the column for fresh installs. +-- This migration handles existing databases that already ran 032 without it. + +-- SQLite does not support IF NOT EXISTS for ALTER TABLE ADD COLUMN, +-- but re-adding an existing column is a no-op error that we catch at the +-- application level. The migration runner skips already-applied migrations +-- by ID, so this only runs on databases missing the column. +ALTER TABLE user_profiles ADD COLUMN data TEXT DEFAULT '{}'; diff --git a/packages/core/src/db/migrations-bundle.ts b/packages/core/src/db/migrations-bundle.ts index 726609b4d..a0d8eb1f7 100644 --- a/packages/core/src/db/migrations-bundle.ts +++ b/packages/core/src/db/migrations-bundle.ts @@ -1,7 +1,7 @@ /** * AUTO-GENERATED FILE - DO NOT EDIT * Generated by: scripts/generate-migrations.ts - * Generated at: 2026-04-08T04:42:01.383Z + * Generated at: 2026-04-08T16:51:05.650Z * * This file contains all migration SQL bundled for use in Cloudflare Workers * where filesystem access is not available at runtime. @@ -231,7 +231,7 @@ export const bundledMigrations: BundledMigration[] = [ name: 'User Profiles', filename: '032_user_profiles.sql', description: 'Migration 032: User Profiles', - sql: "-- User Profiles Table (Core Migration)\n-- Stores extended user profile data separate from auth concerns\n-- Required by admin-users.ts for user edit page profile management\n--\n-- Originally introduced as app-level migration (my-sonicjs-app/migrations/018_user_profiles.sql)\n-- in upstream PR #508. Core routes (admin-users.ts) were updated to query this table in PR #512,\n-- but no corresponding core migration was added. This migration corrects that gap.\n--\n-- IF NOT EXISTS guards ensure idempotency for databases that already have the table\n-- from the app-level migration.\n\nCREATE TABLE IF NOT EXISTS user_profiles (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,\n\n display_name TEXT,\n bio TEXT,\n company TEXT,\n job_title TEXT,\n website TEXT,\n location TEXT,\n date_of_birth INTEGER,\n\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\n-- Index for fast user lookups\nCREATE INDEX IF NOT EXISTS idx_user_profiles_user_id ON user_profiles(user_id);\n\n-- Trigger to auto-update updated_at timestamp\nCREATE TRIGGER IF NOT EXISTS user_profiles_updated_at\n AFTER UPDATE ON user_profiles\nBEGIN\n UPDATE user_profiles SET updated_at = strftime('%s', 'now') * 1000 WHERE id = NEW.id;\nEND;\n" + sql: "-- User Profiles Table (Core Migration)\n-- Stores extended user profile data separate from auth concerns\n-- Required by admin-users.ts for user edit page profile management\n--\n-- Originally introduced as app-level migration (my-sonicjs-app/migrations/018_user_profiles.sql)\n-- in upstream PR #508. Core routes (admin-users.ts) were updated to query this table in PR #512,\n-- but no corresponding core migration was added. This migration corrects that gap.\n--\n-- IF NOT EXISTS guards ensure idempotency for databases that already have the table\n-- from the app-level migration.\n\nCREATE TABLE IF NOT EXISTS user_profiles (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,\n\n display_name TEXT,\n bio TEXT,\n company TEXT,\n job_title TEXT,\n website TEXT,\n location TEXT,\n date_of_birth INTEGER,\n data TEXT DEFAULT '{}',\n\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\n-- Index for fast user lookups\nCREATE INDEX IF NOT EXISTS idx_user_profiles_user_id ON user_profiles(user_id);\n\n-- Trigger to auto-update updated_at timestamp\nCREATE TRIGGER IF NOT EXISTS user_profiles_updated_at\n AFTER UPDATE ON user_profiles\nBEGIN\n UPDATE user_profiles SET updated_at = strftime('%s', 'now') * 1000 WHERE id = NEW.id;\nEND;\n" }, { id: '033', @@ -246,6 +246,13 @@ export const bundledMigrations: BundledMigration[] = [ filename: '034_security_audit_plugin.sql', description: 'Migration 034: Security Audit Plugin', sql: "-- Security Audit Plugin\n-- Tracks login attempts, registrations, and security events for monitoring and brute-force detection\n\nCREATE TABLE IF NOT EXISTS security_events (\n id TEXT PRIMARY KEY,\n event_type TEXT NOT NULL,\n severity TEXT NOT NULL DEFAULT 'info',\n user_id TEXT,\n email TEXT,\n ip_address TEXT,\n user_agent TEXT,\n country_code TEXT,\n request_path TEXT,\n request_method TEXT,\n details TEXT,\n fingerprint TEXT,\n blocked INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_security_events_type ON security_events(event_type);\nCREATE INDEX IF NOT EXISTS idx_security_events_user ON security_events(user_id);\nCREATE INDEX IF NOT EXISTS idx_security_events_email ON security_events(email);\nCREATE INDEX IF NOT EXISTS idx_security_events_ip ON security_events(ip_address);\nCREATE INDEX IF NOT EXISTS idx_security_events_severity ON security_events(severity);\nCREATE INDEX IF NOT EXISTS idx_security_events_created ON security_events(created_at);\nCREATE INDEX IF NOT EXISTS idx_security_events_fingerprint ON security_events(fingerprint);\n" + }, + { + id: '035', + name: 'User Profiles Data Column', + filename: '035_user_profiles_data_column.sql', + description: 'Migration 035: User Profiles Data Column', + sql: "-- Migration 035: Add data column to user_profiles\n-- Stores custom profile fields as JSON (used by user-profiles plugin)\n--\n-- The data column was missing from migration 032 when the user-profiles plugin\n-- was added in PR #747. The ALTER TABLE migration was placed in the wrong\n-- directory (src/db/migrations/) so it was never bundled or executed.\n-- This caused the user edit page to crash with a 500 error because the route\n-- queries SELECT ... data FROM user_profiles.\n--\n-- Migration 032 has been updated to include the column for fresh installs.\n-- This migration handles existing databases that already ran 032 without it.\n\n-- SQLite does not support IF NOT EXISTS for ALTER TABLE ADD COLUMN,\n-- but re-adding an existing column is a no-op error that we catch at the\n-- application level. The migration runner skips already-applied migrations\n-- by ID, so this only runs on databases missing the column.\nALTER TABLE user_profiles ADD COLUMN data TEXT DEFAULT '{}';\n" } ] diff --git a/packages/core/src/db/migrations/0011_user_profiles_data.sql b/packages/core/src/db/migrations/0011_user_profiles_data.sql deleted file mode 100644 index 1ed0bea33..000000000 --- a/packages/core/src/db/migrations/0011_user_profiles_data.sql +++ /dev/null @@ -1,5 +0,0 @@ --- Migration 0011: Add custom data column to user_profiles --- Stores plugin-defined custom profile fields as JSON --- Used by the user-profiles plugin for developer-defined fields - -ALTER TABLE user_profiles ADD COLUMN data TEXT DEFAULT '{}';