Task 2.3: Replace single-column unique constraints with composite (user_id, name) unique indexes
- charts.name → uniqueIndex('charts_user_id_name_unique').on(user_id, name)
- annotation_types.name → uniqueIndex('annotation_types_user_id_name_unique').on(user_id, name)
- span_label_types.name → uniqueIndex('span_label_types_user_id_name_unique').on(user_id, name)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0cd74ebedd
commit
b633a3f52a
2 changed files with 13 additions and 7 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
- [x] 2.1 `[sonnet]` Add `users` table to Drizzle schema (`src/lib/db/schema.ts`) with UUID PK, email, password_hash, name, image, provider, provider_account_id, email_verified, created_at, updated_at
|
||||
- [x] 2.2 `[sonnet]` Add `user_id` (uuid, FK to users.id) column to `charts`, `annotations`, `annotation_types`, `span_annotations`, `span_label_types` in schema
|
||||
- [ ] 2.3 `[sonnet]` Replace unique constraints: `charts.name` → `(user_id, name)`, `annotation_types.name` → `(user_id, name)`, `span_label_types.name` → `(user_id, name)`
|
||||
- [x] 2.3 `[sonnet]` Replace unique constraints: `charts.name` → `(user_id, name)`, `annotation_types.name` → `(user_id, name)`, `span_label_types.name` → `(user_id, name)`
|
||||
- [ ] 2.4 `[haiku]` Generate Drizzle migration with `drizzle-kit generate`
|
||||
- [ ] 2.5 `[opus]` Create data migration script (`scripts/migrate-users.ts`): create default admin user, backfill `user_id` on all existing rows, alter columns to NOT NULL
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@ export const users = pgTable('users', {
|
|||
export const charts = pgTable('charts', {
|
||||
id: serial('id').primaryKey(),
|
||||
user_id: uuid('user_id').references(() => users.id), // nullable for now; will be NOT NULL after data migration (task 2.5)
|
||||
name: text('name').notNull().unique(),
|
||||
name: text('name').notNull(),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
});
|
||||
}, (table) => [
|
||||
uniqueIndex('charts_user_id_name_unique').on(table.user_id, table.name),
|
||||
]);
|
||||
|
||||
export const candles = pgTable('candles', {
|
||||
id: serial('id').primaryKey(),
|
||||
|
|
@ -35,14 +37,16 @@ export const candles = pgTable('candles', {
|
|||
export const annotationTypes = pgTable('annotation_types', {
|
||||
id: serial('id').primaryKey(),
|
||||
user_id: uuid('user_id').references(() => users.id), // nullable for now; will be NOT NULL after data migration (task 2.5)
|
||||
name: text('name').notNull().unique(), // internal name (e.g., 'break_up')
|
||||
name: text('name').notNull(), // internal name (e.g., 'break_up')
|
||||
display_name: text('display_name').notNull(), // display name (e.g., 'Break Up')
|
||||
color: text('color').notNull(), // hex color code
|
||||
category: text('category').notNull(), // 'marker' or 'line'
|
||||
icon: text('icon'), // icon name or symbol
|
||||
is_active: boolean('is_active').notNull().default(true), // true = active, false = inactive
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
});
|
||||
}, (table) => [
|
||||
uniqueIndex('annotation_types_user_id_name_unique').on(table.user_id, table.name),
|
||||
]);
|
||||
|
||||
export const annotations = pgTable('annotations', {
|
||||
id: serial('id').primaryKey(),
|
||||
|
|
@ -58,14 +62,16 @@ export const annotations = pgTable('annotations', {
|
|||
export const spanLabelTypes = pgTable('span_label_types', {
|
||||
id: serial('id').primaryKey(),
|
||||
user_id: uuid('user_id').references(() => users.id), // nullable for now; will be NOT NULL after data migration (task 2.5)
|
||||
name: text('name').notNull().unique(), // internal name (e.g., 'bull_flag')
|
||||
name: text('name').notNull(), // internal name (e.g., 'bull_flag')
|
||||
display_name: text('display_name').notNull(), // UI label (e.g., 'Bull Flag')
|
||||
color: text('color').notNull(), // hex color for rectangle fill
|
||||
hotkey: text('hotkey'), // keyboard shortcut (e.g., '1')
|
||||
is_active: boolean('is_active').notNull().default(true), // true = active, false = inactive
|
||||
sort_order: integer('sort_order').notNull().default(0), // display order
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
});
|
||||
}, (table) => [
|
||||
uniqueIndex('span_label_types_user_id_name_unique').on(table.user_id, table.name),
|
||||
]);
|
||||
|
||||
export const spanAnnotations = pgTable('span_annotations', {
|
||||
id: serial('id').primaryKey(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue