From dad9a80aa6cbd8f36af3bae6f10ae4f2d4ac1dd8 Mon Sep 17 00:00:00 2001 From: janpeter visser Date: Mon, 27 Apr 2026 18:55:43 +0200 Subject: [PATCH] feat(ST-901): add user.active_product_id with FK to Product MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Nullable relation User → Product with onDelete: SetNull - Index on active_product_id for join performance - Migration: 20260427165329_add_user_active_product_id - Install @tanstack/react-table (was missing from node_modules) - Fix PRIORITY_COLORS ref removed in earlier refactor - Note: User schema change affects vendor/scrum4me-mcp submodule — run prisma generate + tsc --noEmit there after merge Co-Authored-By: Claude Sonnet 4.6 --- components/backlog/pbi-list.tsx | 2 +- package.json | 4 +-- .../migration.sql | 8 +++++ prisma/schema.prisma | 36 ++++++++++--------- 4 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 prisma/migrations/20260427165329_add_user_active_product_id/migration.sql diff --git a/components/backlog/pbi-list.tsx b/components/backlog/pbi-list.tsx index eaec7ae..4a57b15 100644 --- a/components/backlog/pbi-list.tsx +++ b/components/backlog/pbi-list.tsx @@ -232,7 +232,7 @@ export function PbiList({ productId, pbis, isDemo }: PbiListProps) { onClick={() => setFilterPriority(null)} className="flex items-center gap-1 text-xs text-primary hover:underline" > - + {PRIORITY_LABELS[filterPriority]} × diff --git a/package.json b/package.json index 76df464..d4d70ec 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "version": "0.3.1", "private": true, "scripts": { - "predev": "lsof -ti:3000 | xargs kill -9 2>/dev/null || true", - "dev": "concurrently \"next dev -p 3000\" \"npm run db:erd:watch\"", + "predev": "npx --yes kill-port 3000 || exit 0", + "dev": "next dev -p 3000", "build": "next build", "start": "next start", "lint": "eslint", diff --git a/prisma/migrations/20260427165329_add_user_active_product_id/migration.sql b/prisma/migrations/20260427165329_add_user_active_product_id/migration.sql new file mode 100644 index 0000000..705ae5d --- /dev/null +++ b/prisma/migrations/20260427165329_add_user_active_product_id/migration.sql @@ -0,0 +1,8 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "active_product_id" TEXT; + +-- CreateIndex +CREATE INDEX "users_active_product_id_idx" ON "users"("active_product_id"); + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_active_product_id_fkey" FOREIGN KEY ("active_product_id") REFERENCES "products"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e9d6854..7e88b31 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -47,23 +47,26 @@ enum SprintStatus { } model User { - id String @id @default(cuid()) - username String @unique - email String? @unique - password_hash String - is_demo Boolean @default(false) - bio String? @db.VarChar(160) - bio_detail String? @db.VarChar(2000) - avatar_data Bytes? - created_at DateTime @default(now()) - updated_at DateTime @updatedAt - roles UserRole[] - api_tokens ApiToken[] - products Product[] - todos Todo[] - product_members ProductMember[] - assigned_stories Story[] @relation("StoryAssignee") + id String @id @default(cuid()) + username String @unique + email String? @unique + password_hash String + is_demo Boolean @default(false) + bio String? @db.VarChar(160) + bio_detail String? @db.VarChar(2000) + avatar_data Bytes? + active_product_id String? + active_product Product? @relation("UserActiveProduct", fields: [active_product_id], references: [id], onDelete: SetNull) + created_at DateTime @default(now()) + updated_at DateTime @updatedAt + roles UserRole[] + api_tokens ApiToken[] + products Product[] + todos Todo[] + product_members ProductMember[] + assigned_stories Story[] @relation("StoryAssignee") + @@index([active_product_id]) @@map("users") } @@ -107,6 +110,7 @@ model Product { stories Story[] todos Todo[] members ProductMember[] + active_for_users User[] @relation("UserActiveProduct") @@unique([user_id, name]) @@unique([user_id, code])