randomayzer/docs/MIGRATION_OWNERSHIP_INVARIANT.md

2.1 KiB

Database Migration Strategy: Mandatory Organizer Ownership Invariant

This document details the database schema migration strategy for enforcing mandatory, non-null organizerId on the Giveaway table in production.


1. Context & Invariant

In Randomayzer, every giveaway is owned by an authenticated Organizer (represented by the User model via VK ID OAuth 2.1). To prevent broken access control and ambiguous authorization states:

  • Giveaway.organizerId is strictly NOT NULL.
  • Foreign key relation is defined with onDelete: Restrict, strictly preventing the deletion of an organizer account while owned giveaways exist.

2. Prisma Schema Definition

model User {
  id          String          @id @default(cuid())
  vkUserId    String          @unique
  giveaways   Giveaway[]
  ...
}

model Giveaway {
  id                  String               @id @default(cuid())
  organizerId         String
  organizer           User                 @relation(fields: [organizerId], references: [id], onDelete: Restrict)
  ...
  @@index([organizerId])
}

3. Migration Plan for Existing Records

A. Development & Staging Environments

Existing anonymous test records created prior to Phase 2.2 can be purged:

DELETE FROM "ParticipantSnapshot" WHERE "giveawayId" IN (SELECT "id" FROM "Giveaway" WHERE "organizerId" IS NULL);
DELETE FROM "Participant" WHERE "giveawayId" IN (SELECT "id" FROM "Giveaway" WHERE "organizerId" IS NULL);
DELETE FROM "Giveaway" WHERE "organizerId" IS NULL;

B. Production Migration Protocol

  1. Never assign legacy records to arbitrary users: If unassigned giveaways exist in a production database, do not automatically bind them to random organizers.
  2. Quarantine or Admin Assignment: Migrate legacy orphan giveaways to a designated system quarantine table or assign to an explicitly verified administrative organizer.
  3. Execute SQL Migration:
-- Step 1: Verify 0 null records remain
SELECT COUNT(*) FROM "Giveaway" WHERE "organizerId" IS NULL;

-- Step 2: Enforce NOT NULL and Restrict constraint
ALTER TABLE "Giveaway" ALTER COLUMN "organizerId" SET NOT NULL;