diff --git a/Dockerfile b/Dockerfile index 38c10f7..4ff6620 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,4 +51,4 @@ EXPOSE 3000 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" -CMD ["node", "server.js"] +CMD ["sh", "-c", "npx prisma migrate deploy && node server.js"] diff --git a/ROADMAP.md b/ROADMAP.md index e45ad8f..3dbae6b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -127,7 +127,7 @@ The review tool lives at its own dedicated page (`/projects/[projectId]/delivera - `Revision.attachments` JSON stores `{ referenceImage, currentImage }` with metadata - Comparison viewer with 4 modes: side-by-side, wipe, overlay, toggle - SVG annotation layer with 7 tools (rect, ellipse, arrow, freehand, text, pin, screenshot paste) -- Annotation model in Prisma schema (requires `db push` to sync) +- Annotation model in Prisma schema (use `prisma migrate dev` to create migration) - Annotation API: GET/POST `/api/revisions/[id]/annotations`, PATCH/DELETE `/api/revisions/[id]/annotations/[id]` - Annotations linked to comments (transactional create), undo/redo stack - Screenshot paste: Cmd+V pastes clipboard image as draggable/resizable callout @@ -1310,7 +1310,7 @@ src/ - **Service layer** → Prisma queries + business rules (testable, reusable) - **URL-synced filters** via `nuqs` — views are shareable/bookmarkable - **Server Components** for initial fetch, **TanStack Query** for mutations/cache -- **`npx prisma db push`** for schema changes (no migrations dir — use db push) +- **`npx prisma migrate dev`** for schema changes (versioned migrations in `prisma/migrations/`) ### Local Dev ```bash diff --git a/SETUP.md b/SETUP.md index 2ecc881..43d0a73 100644 --- a/SETUP.md +++ b/SETUP.md @@ -134,14 +134,14 @@ NEXTAUTH_URL="http://localhost:3000" ## 5. Initialize the Database -Push the Prisma schema to the database and run the seed script: +Apply migrations and run the seed script: ```bash -npx prisma db push +npx prisma migrate dev npx prisma db seed ``` -`db push` creates all tables from `prisma/schema.prisma`. +`migrate dev` applies pending migrations and creates new ones from schema changes. `db seed` populates: - 10 pipeline stage templates with dependency rules @@ -177,7 +177,7 @@ be logged in automatically as the dev admin user. | Format | `npm run format` | Prettier format all files | | Format check | `npm run format:check` | Prettier check (no write) | | Generate client | `npm run db:generate` | Regenerate Prisma client | -| Push schema | `npm run db:push` | Sync schema to database (no migration files) | +| Migrate | `npm run db:migrate` | Apply/create migrations | | Seed | `npm run db:seed` | Run seed script | | Studio | `npm run db:studio` | Open Prisma Studio GUI | @@ -234,7 +234,7 @@ The workflow for moving between macOS and Windows: ```bash git pull npm install # in case dependencies changed - npx prisma db push # in case schema changed + npx prisma migrate dev # apply any new migrations npm run dev ``` @@ -266,8 +266,8 @@ taskkill /PID /F ### Schema out of sync after git pull ```bash -npx prisma db push # applies any schema changes -npx prisma generate # regenerates the client types +npx prisma migrate dev # applies pending migrations, creates new ones if schema changed +npx prisma generate # regenerates the client types ``` ### nvm: command not found (macOS) diff --git a/docs/brainstorms/2026-04-06-versioned-migration-baseline-requirements.md b/docs/brainstorms/2026-04-06-versioned-migration-baseline-requirements.md new file mode 100644 index 0000000..a34cccd --- /dev/null +++ b/docs/brainstorms/2026-04-06-versioned-migration-baseline-requirements.md @@ -0,0 +1,50 @@ +--- +date: 2026-04-06 +topic: versioned-migration-baseline +--- + +# Versioned Migration Baseline + +## Problem Frame + +The project uses `db push` for schema changes, which has no version history and no rollback path. The database was just reset to a clean state via the clean-slate toolkit. Two stale migration files exist in `prisma/migrations/` from early development (March 2026) but the schema has evolved far beyond them (40+ models now). Before real user data enters the database, the migration history must be established so future schema changes are versioned, repeatable, and auditable. + +## Requirements + +**Baseline Migration** +- R1. Delete the 2 stale migration files and create a single fresh baseline migration capturing the full current schema (40+ models). +- R2. The baseline migration must be marked as "already applied" against the current database (which already has the schema via `db push`) using `prisma migrate resolve`. + +**Enforce Migrations Going Forward** +- R3. All future schema changes must use `prisma migrate dev` (development) and `prisma migrate deploy` (production), not `db push`. +- R4. Update the Dockerfile to run `npx prisma migrate deploy` before `node server.js` so production deployments apply pending migrations automatically. + +**Developer Workflow** +- R5. Update `SETUP.md` or equivalent docs to reflect the new migration workflow (`prisma migrate dev` instead of `db push`). + +## Success Criteria + +- `prisma migrate status` shows no pending migrations and no drift against the current database. +- The Dockerfile runs migrations before starting the app. +- A new schema change created with `prisma migrate dev` produces a versioned migration file that can be applied to production with `prisma migrate deploy`. + +## Scope Boundaries + +- Not in scope: migrating data between schema versions (the database is clean — no data migration needed). +- Not in scope: CI checks to reject `db push` usage (nice-to-have for later). +- Not in scope: changing the Prisma adapter or connection setup. + +## Key Decisions + +- **Delete and re-baseline vs. squash:** Delete the 2 stale migrations and create a fresh baseline. The old migrations are artifacts of early prototyping and don't represent the current schema. A clean baseline is simpler than trying to reconcile drift. +- **Timing is ideal:** The database was just purged and re-seeded with the clean-slate toolkit. The schema matches `schema.prisma` exactly — no drift to resolve beyond marking the baseline as applied. + +## Outstanding Questions + +### Deferred to Planning +- [Affects R1][Technical] Determine the exact Prisma CLI commands for baselining (`prisma migrate diff`, `prisma migrate resolve`, or manual SQL baseline). +- [Affects R4][Technical] Determine whether the Dockerfile CMD should chain `prisma migrate deploy && node server.js` or use an entrypoint script. + +## Next Steps + +-> `/ce:plan` for structured implementation planning diff --git a/prisma/migrations/20260313034356_add_schedule_override_fields/migration.sql b/prisma/migrations/20260313034356_add_schedule_override_fields/migration.sql deleted file mode 100644 index 89ada4c..0000000 --- a/prisma/migrations/20260313034356_add_schedule_override_fields/migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- AlterTable -ALTER TABLE "deliverable_stages" ADD COLUMN "manualSchedule" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "scheduleConflict" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "scheduleDelta" INTEGER; diff --git a/prisma/migrations/20260312152601_init/migration.sql b/prisma/migrations/20260406194349_baseline/migration.sql similarity index 50% rename from prisma/migrations/20260312152601_init/migration.sql rename to prisma/migrations/20260406194349_baseline/migration.sql index 9c8c29d..ec233d1 100644 --- a/prisma/migrations/20260312152601_init/migration.sql +++ b/prisma/migrations/20260406194349_baseline/migration.sql @@ -1,5 +1,5 @@ --- Enable pgvector extension (must be before any vector column usage) -CREATE EXTENSION IF NOT EXISTS vector; +-- CreateSchema +CREATE SCHEMA IF NOT EXISTS "public"; -- CreateEnum CREATE TYPE "Role" AS ENUM ('ADMIN', 'PRODUCER', 'ARTIST'); @@ -31,6 +31,28 @@ CREATE TYPE "SkillLevel" AS ENUM ('JUNIOR', 'INTERMEDIATE', 'SENIOR', 'LEAD'); -- CreateEnum CREATE TYPE "ExecutionStatus" AS ENUM ('SUCCESS', 'PARTIAL_FAILURE', 'FAILURE'); +-- CreateEnum +CREATE TYPE "Permission" AS ENUM ('PROJECT_CREATE', 'PROJECT_UPDATE', 'PROJECT_DELETE', 'PROJECT_VIEW', 'DELIVERABLE_CREATE', 'DELIVERABLE_UPDATE', 'DELIVERABLE_DELETE', 'STAGE_UPDATE_STATUS', 'STAGE_ASSIGN', 'STAGE_SCHEDULE', 'REVISION_CREATE', 'REVISION_REVIEW', 'COMMENT_CREATE', 'COMMENT_DELETE_ANY', 'PIPELINE_MANAGE', 'USER_MANAGE', 'ROLE_MANAGE', 'ORG_SETTINGS', 'AUTOMATION_MANAGE', 'FIELD_CUSTOMIZE'); + +-- CreateEnum +CREATE TYPE "AnnotationType" AS ENUM ('RECTANGLE', 'ELLIPSE', 'ARROW', 'FREEHAND', 'TEXT', 'PIN', 'SCREENSHOT'); + +-- CreateEnum +CREATE TYPE "FeedbackStatus" AS ENUM ('OPEN', 'IN_PROGRESS', 'RESOLVED', 'VERIFIED', 'REOPENED'); + +-- CreateEnum +CREATE TYPE "ReviewSessionStatus" AS ENUM ('DRAFT', 'IN_PROGRESS', 'COMPLETED'); + +-- CreateTable +CREATE TABLE "org_role_permissions" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "role" "Role" NOT NULL, + "permission" "Permission" NOT NULL, + + CONSTRAINT "org_role_permissions_pkey" PRIMARY KEY ("id") +); + -- CreateTable CREATE TABLE "organizations" ( "id" TEXT NOT NULL, @@ -117,6 +139,46 @@ CREATE TABLE "pipeline_stage_dependencies" ( CONSTRAINT "pipeline_stage_dependencies_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "pipeline_templates" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "organizationId" TEXT NOT NULL, + "isArchived" BOOLEAN NOT NULL DEFAULT false, + "isDefault" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "pipeline_templates_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "pipeline_stage_definitions" ( + "id" TEXT NOT NULL, + "pipelineId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "order" INTEGER NOT NULL, + "isCriticalGate" BOOLEAN NOT NULL DEFAULT false, + "isOptional" BOOLEAN NOT NULL DEFAULT false, + "description" TEXT, + "estimatedDays" DOUBLE PRECISION, + "color" TEXT, + "customStatuses" JSONB, + + CONSTRAINT "pipeline_stage_definitions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "pipeline_stage_dependencies_v2" ( + "id" TEXT NOT NULL, + "stageId" TEXT NOT NULL, + "prerequisiteId" TEXT NOT NULL, + + CONSTRAINT "pipeline_stage_dependencies_v2_pkey" PRIMARY KEY ("id") +); + -- CreateTable CREATE TABLE "projects" ( "id" TEXT NOT NULL, @@ -140,7 +202,9 @@ CREATE TABLE "projects" ( "actualCost" DOUBLE PRECISION, "agency" TEXT, "embedding" vector(768), + "customFields" JSONB, "organizationId" TEXT NOT NULL, + "pipelineTemplateId" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -162,7 +226,9 @@ CREATE TABLE "deliverables" ( "actualDeliveryDate" TIMESTAMP(3), "wfInputDate" TIMESTAMP(3), "embedding" vector(768), + "customFields" JSONB, "projectId" TEXT NOT NULL, + "organizationId" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -179,8 +245,13 @@ CREATE TABLE "deliverable_stages" ( "dueDate" TIMESTAMP(3), "notes" TEXT, "subStatus" TEXT, + "manualSchedule" BOOLEAN NOT NULL DEFAULT false, + "scheduleConflict" BOOLEAN NOT NULL DEFAULT false, + "scheduleDelta" INTEGER, "deliverableId" TEXT NOT NULL, "templateId" TEXT NOT NULL, + "stageDefinitionId" TEXT, + "organizationId" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -312,6 +383,53 @@ CREATE TABLE "chat_messages" ( CONSTRAINT "chat_messages_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "custom_field_definitions" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "entityType" TEXT NOT NULL, + "fieldName" TEXT NOT NULL, + "fieldType" TEXT NOT NULL, + "fieldOptions" JSONB, + "isRequired" BOOLEAN NOT NULL DEFAULT false, + "order" INTEGER NOT NULL DEFAULT 0, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "custom_field_definitions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "notification_rules" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "isEnabled" BOOLEAN NOT NULL DEFAULT true, + "event" TEXT NOT NULL, + "conditions" JSONB, + "channels" JSONB NOT NULL, + "recipientRoles" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "notification_rules_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "invitations" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "role" "Role" NOT NULL DEFAULT 'ARTIST', + "organizationId" TEXT NOT NULL, + "invitedById" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "acceptedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "invitations_pkey" PRIMARY KEY ("id") +); + -- CreateTable CREATE TABLE "search_logs" ( "id" TEXT NOT NULL, @@ -324,6 +442,99 @@ CREATE TABLE "search_logs" ( CONSTRAINT "search_logs_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "annotations" ( + "id" TEXT NOT NULL, + "commentId" TEXT NOT NULL, + "revisionId" TEXT NOT NULL, + "type" "AnnotationType" NOT NULL, + "data" JSONB NOT NULL, + "imageX" DOUBLE PRECISION NOT NULL, + "imageY" DOUBLE PRECISION NOT NULL, + "timestampSeconds" DOUBLE PRECISION, + "frameThumbnailUrl" TEXT, + "createdById" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "annotations_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "feedback_items" ( + "id" TEXT NOT NULL, + "deliverableStageId" TEXT NOT NULL, + "revisionId" TEXT NOT NULL, + "annotationId" TEXT, + "commentId" TEXT, + "summary" TEXT NOT NULL, + "isActionItem" BOOLEAN NOT NULL DEFAULT true, + "status" "FeedbackStatus" NOT NULL DEFAULT 'OPEN', + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "assignedToId" TEXT, + "createdById" TEXT NOT NULL, + "resolvedById" TEXT, + "resolvedAt" TIMESTAMP(3), + "resolutionNote" TEXT, + "verifiedById" TEXT, + "verifiedAt" TIMESTAMP(3), + "carriedFromId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "feedback_items_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "review_sessions" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "status" "ReviewSessionStatus" NOT NULL DEFAULT 'DRAFT', + "createdById" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "review_sessions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "review_session_items" ( + "id" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "deliverableStageId" TEXT NOT NULL, + "revisionId" TEXT, + "sortOrder" INTEGER NOT NULL, + "decision" TEXT, + "decisionNote" TEXT, + "decidedById" TEXT, + "decidedAt" TIMESTAMP(3), + + CONSTRAINT "review_session_items_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "color_probes" ( + "id" TEXT NOT NULL, + "revisionId" TEXT NOT NULL, + "index" INTEGER NOT NULL, + "workingX" DOUBLE PRECISION NOT NULL, + "workingY" DOUBLE PRECISION NOT NULL, + "referenceX" DOUBLE PRECISION NOT NULL, + "referenceY" DOUBLE PRECISION NOT NULL, + "createdById" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "color_probes_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "org_role_permissions_organizationId_idx" ON "org_role_permissions"("organizationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "org_role_permissions_organizationId_role_permission_key" ON "org_role_permissions"("organizationId", "role", "permission"); + -- CreateIndex CREATE UNIQUE INDEX "organizations_domain_key" ON "organizations"("domain"); @@ -351,29 +562,56 @@ CREATE UNIQUE INDEX "pipeline_stage_templates_order_key" ON "pipeline_stage_temp -- CreateIndex CREATE UNIQUE INDEX "pipeline_stage_dependencies_stageId_prerequisiteId_key" ON "pipeline_stage_dependencies"("stageId", "prerequisiteId"); +-- CreateIndex +CREATE INDEX "pipeline_templates_organizationId_idx" ON "pipeline_templates"("organizationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "pipeline_templates_organizationId_name_key" ON "pipeline_templates"("organizationId", "name"); + +-- CreateIndex +CREATE UNIQUE INDEX "pipeline_stage_definitions_pipelineId_slug_key" ON "pipeline_stage_definitions"("pipelineId", "slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "pipeline_stage_definitions_pipelineId_order_key" ON "pipeline_stage_definitions"("pipelineId", "order"); + +-- CreateIndex +CREATE UNIQUE INDEX "pipeline_stage_dependencies_v2_stageId_prerequisiteId_key" ON "pipeline_stage_dependencies_v2"("stageId", "prerequisiteId"); + -- CreateIndex CREATE UNIQUE INDEX "projects_projectCode_key" ON "projects"("projectCode"); -- CreateIndex CREATE INDEX "projects_organizationId_idx" ON "projects"("organizationId"); +-- CreateIndex +CREATE INDEX "projects_pipelineTemplateId_idx" ON "projects"("pipelineTemplateId"); + -- CreateIndex CREATE INDEX "projects_status_idx" ON "projects"("status"); -- CreateIndex CREATE INDEX "deliverables_projectId_idx" ON "deliverables"("projectId"); +-- CreateIndex +CREATE INDEX "deliverables_organizationId_idx" ON "deliverables"("organizationId"); + -- CreateIndex CREATE INDEX "deliverables_status_idx" ON "deliverables"("status"); -- CreateIndex CREATE INDEX "deliverable_stages_deliverableId_idx" ON "deliverable_stages"("deliverableId"); +-- CreateIndex +CREATE INDEX "deliverable_stages_stageDefinitionId_idx" ON "deliverable_stages"("stageDefinitionId"); + +-- CreateIndex +CREATE INDEX "deliverable_stages_organizationId_idx" ON "deliverable_stages"("organizationId"); + -- CreateIndex CREATE INDEX "deliverable_stages_status_idx" ON "deliverable_stages"("status"); -- CreateIndex -CREATE UNIQUE INDEX "deliverable_stages_deliverableId_templateId_key" ON "deliverable_stages"("deliverableId", "templateId"); +CREATE UNIQUE INDEX "deliverable_stages_deliverableId_stageDefinitionId_key" ON "deliverable_stages"("deliverableId", "stageDefinitionId"); -- CreateIndex CREATE INDEX "stage_assignments_userId_idx" ON "stage_assignments"("userId"); @@ -414,9 +652,72 @@ CREATE INDEX "chat_messages_sessionId_idx" ON "chat_messages"("sessionId"); -- CreateIndex CREATE INDEX "chat_messages_userId_idx" ON "chat_messages"("userId"); +-- CreateIndex +CREATE INDEX "custom_field_definitions_organizationId_idx" ON "custom_field_definitions"("organizationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "custom_field_definitions_organizationId_entityType_fieldNam_key" ON "custom_field_definitions"("organizationId", "entityType", "fieldName"); + +-- CreateIndex +CREATE INDEX "notification_rules_organizationId_idx" ON "notification_rules"("organizationId"); + +-- CreateIndex +CREATE INDEX "notification_rules_event_idx" ON "notification_rules"("event"); + +-- CreateIndex +CREATE UNIQUE INDEX "invitations_token_key" ON "invitations"("token"); + +-- CreateIndex +CREATE INDEX "invitations_organizationId_idx" ON "invitations"("organizationId"); + +-- CreateIndex +CREATE INDEX "invitations_token_idx" ON "invitations"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "invitations_email_organizationId_key" ON "invitations"("email", "organizationId"); + -- CreateIndex CREATE INDEX "search_logs_userId_idx" ON "search_logs"("userId"); +-- CreateIndex +CREATE INDEX "annotations_commentId_idx" ON "annotations"("commentId"); + +-- CreateIndex +CREATE INDEX "annotations_revisionId_idx" ON "annotations"("revisionId"); + +-- CreateIndex +CREATE INDEX "annotations_revisionId_timestampSeconds_idx" ON "annotations"("revisionId", "timestampSeconds"); + +-- CreateIndex +CREATE INDEX "feedback_items_deliverableStageId_idx" ON "feedback_items"("deliverableStageId"); + +-- CreateIndex +CREATE INDEX "feedback_items_revisionId_idx" ON "feedback_items"("revisionId"); + +-- CreateIndex +CREATE INDEX "feedback_items_assignedToId_idx" ON "feedback_items"("assignedToId"); + +-- CreateIndex +CREATE INDEX "feedback_items_status_idx" ON "feedback_items"("status"); + +-- CreateIndex +CREATE INDEX "review_sessions_organizationId_idx" ON "review_sessions"("organizationId"); + +-- CreateIndex +CREATE INDEX "review_sessions_status_idx" ON "review_sessions"("status"); + +-- CreateIndex +CREATE INDEX "review_session_items_sessionId_idx" ON "review_session_items"("sessionId"); + +-- CreateIndex +CREATE INDEX "color_probes_revisionId_idx" ON "color_probes"("revisionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "color_probes_revisionId_index_key" ON "color_probes"("revisionId", "index"); + +-- AddForeignKey +ALTER TABLE "org_role_permissions" ADD CONSTRAINT "org_role_permissions_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "users" ADD CONSTRAINT "users_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE SET NULL ON UPDATE CASCADE; @@ -432,18 +733,42 @@ ALTER TABLE "pipeline_stage_dependencies" ADD CONSTRAINT "pipeline_stage_depende -- AddForeignKey ALTER TABLE "pipeline_stage_dependencies" ADD CONSTRAINT "pipeline_stage_dependencies_prerequisiteId_fkey" FOREIGN KEY ("prerequisiteId") REFERENCES "pipeline_stage_templates"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "pipeline_templates" ADD CONSTRAINT "pipeline_templates_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "pipeline_stage_definitions" ADD CONSTRAINT "pipeline_stage_definitions_pipelineId_fkey" FOREIGN KEY ("pipelineId") REFERENCES "pipeline_templates"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "pipeline_stage_dependencies_v2" ADD CONSTRAINT "pipeline_stage_dependencies_v2_stageId_fkey" FOREIGN KEY ("stageId") REFERENCES "pipeline_stage_definitions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "pipeline_stage_dependencies_v2" ADD CONSTRAINT "pipeline_stage_dependencies_v2_prerequisiteId_fkey" FOREIGN KEY ("prerequisiteId") REFERENCES "pipeline_stage_definitions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "projects" ADD CONSTRAINT "projects_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "projects" ADD CONSTRAINT "projects_pipelineTemplateId_fkey" FOREIGN KEY ("pipelineTemplateId") REFERENCES "pipeline_templates"("id") ON DELETE SET NULL ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "deliverables" ADD CONSTRAINT "deliverables_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "deliverables" ADD CONSTRAINT "deliverables_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE SET NULL ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "deliverable_stages" ADD CONSTRAINT "deliverable_stages_deliverableId_fkey" FOREIGN KEY ("deliverableId") REFERENCES "deliverables"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "deliverable_stages" ADD CONSTRAINT "deliverable_stages_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "pipeline_stage_templates"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "deliverable_stages" ADD CONSTRAINT "deliverable_stages_stageDefinitionId_fkey" FOREIGN KEY ("stageDefinitionId") REFERENCES "pipeline_stage_definitions"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "deliverable_stages" ADD CONSTRAINT "deliverable_stages_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE SET NULL ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "stage_assignments" ADD CONSTRAINT "stage_assignments_deliverableStageId_fkey" FOREIGN KEY ("deliverableStageId") REFERENCES "deliverable_stages"("id") ON DELETE CASCADE ON UPDATE CASCADE; @@ -489,5 +814,75 @@ ALTER TABLE "automation_executions" ADD CONSTRAINT "automation_executions_ruleId -- AddForeignKey ALTER TABLE "chat_messages" ADD CONSTRAINT "chat_messages_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "custom_field_definitions" ADD CONSTRAINT "custom_field_definitions_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "notification_rules" ADD CONSTRAINT "notification_rules_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "invitations" ADD CONSTRAINT "invitations_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "invitations" ADD CONSTRAINT "invitations_invitedById_fkey" FOREIGN KEY ("invitedById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "search_logs" ADD CONSTRAINT "search_logs_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "annotations" ADD CONSTRAINT "annotations_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "comments"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "annotations" ADD CONSTRAINT "annotations_revisionId_fkey" FOREIGN KEY ("revisionId") REFERENCES "revisions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "annotations" ADD CONSTRAINT "annotations_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_deliverableStageId_fkey" FOREIGN KEY ("deliverableStageId") REFERENCES "deliverable_stages"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_revisionId_fkey" FOREIGN KEY ("revisionId") REFERENCES "revisions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_annotationId_fkey" FOREIGN KEY ("annotationId") REFERENCES "annotations"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "comments"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_assignedToId_fkey" FOREIGN KEY ("assignedToId") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_resolvedById_fkey" FOREIGN KEY ("resolvedById") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_verifiedById_fkey" FOREIGN KEY ("verifiedById") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "feedback_items" ADD CONSTRAINT "feedback_items_carriedFromId_fkey" FOREIGN KEY ("carriedFromId") REFERENCES "feedback_items"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "review_sessions" ADD CONSTRAINT "review_sessions_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "review_session_items" ADD CONSTRAINT "review_session_items_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "review_sessions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "review_session_items" ADD CONSTRAINT "review_session_items_deliverableStageId_fkey" FOREIGN KEY ("deliverableStageId") REFERENCES "deliverable_stages"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "review_session_items" ADD CONSTRAINT "review_session_items_revisionId_fkey" FOREIGN KEY ("revisionId") REFERENCES "revisions"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "review_session_items" ADD CONSTRAINT "review_session_items_decidedById_fkey" FOREIGN KEY ("decidedById") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "color_probes" ADD CONSTRAINT "color_probes_revisionId_fkey" FOREIGN KEY ("revisionId") REFERENCES "revisions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "color_probes" ADD CONSTRAINT "color_probes_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +