bibimbap/docs/jam-ddl.sql

185 lines
8.8 KiB
SQL

-- W2-1 게임잼 엔티티/라이프사이클. 멱등. db/apply-local-ddl.sh 로 실행 DB 비파괴 적용.
-- games 변경 없음(연결은 jam_entries 가 보유). 추가만, 파괴 없음.
-- ===========================================================================
-- 1) jams (게임잼 회차. 회차 독립 = 다중 인스턴스)
-- ===========================================================================
CREATE SEQUENCE IF NOT EXISTS "jams_id_seq";
CREATE TABLE IF NOT EXISTS "jams" (
"id" bigint DEFAULT nextval('jams_id_seq'::regclass) NOT NULL,
"slug" character varying(80) NOT NULL,
"title" character varying(200) NOT NULL,
"description" text,
"status" character varying(20) DEFAULT 'RECRUIT' NOT NULL,
"recruit_start_at" timestamp with time zone,
"dev_start_at" timestamp with time zone,
"eval_start_at" timestamp with time zone,
"eval_end_at" timestamp with time zone,
"discord_url" character varying(500),
"prize_info" text,
"sponsor_info" text,
"is_visible" boolean DEFAULT true NOT NULL,
"created_by" bigint,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
"is_delete" boolean DEFAULT false NOT NULL,
PRIMARY KEY ("id")
);
ALTER SEQUENCE "jams_id_seq" OWNED BY "jams"."id";
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jams_status_check') THEN
ALTER TABLE "jams"
ADD CONSTRAINT "jams_status_check"
CHECK ("status" IN ('RECRUIT', 'DEV', 'EVAL', 'CLOSED'));
END IF;
END
$$;
CREATE UNIQUE INDEX IF NOT EXISTS "ux_jams_slug_active"
ON "jams" ("slug") WHERE "is_delete" IS NOT TRUE;
CREATE INDEX IF NOT EXISTS "idx_jams_visible_keyset"
ON "jams" ("is_visible", "is_delete", "created_at" DESC, "id" DESC);
-- ===========================================================================
-- 2) jam_teams
-- ===========================================================================
CREATE SEQUENCE IF NOT EXISTS "jam_teams_id_seq";
CREATE TABLE IF NOT EXISTS "jam_teams" (
"id" bigint DEFAULT nextval('jam_teams_id_seq'::regclass) NOT NULL,
"jam_id" bigint NOT NULL,
"name" character varying(120) NOT NULL,
"owner_user_id" bigint NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"is_delete" boolean DEFAULT false NOT NULL,
PRIMARY KEY ("id")
);
ALTER SEQUENCE "jam_teams_id_seq" OWNED BY "jam_teams"."id";
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_teams_jam_id_fkey') THEN
ALTER TABLE "jam_teams" ADD CONSTRAINT "jam_teams_jam_id_fkey"
FOREIGN KEY ("jam_id") REFERENCES "jams" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_teams_owner_fkey') THEN
ALTER TABLE "jam_teams" ADD CONSTRAINT "jam_teams_owner_fkey"
FOREIGN KEY ("owner_user_id") REFERENCES "users" ("id");
END IF;
END
$$;
CREATE INDEX IF NOT EXISTS "idx_jam_teams_jam" ON "jam_teams" ("jam_id");
-- ===========================================================================
-- 3) jam_team_members
-- ===========================================================================
CREATE SEQUENCE IF NOT EXISTS "jam_team_members_id_seq";
CREATE TABLE IF NOT EXISTS "jam_team_members" (
"id" bigint DEFAULT nextval('jam_team_members_id_seq'::regclass) NOT NULL,
"jam_team_id" bigint NOT NULL,
"user_id" bigint NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
PRIMARY KEY ("id")
);
ALTER SEQUENCE "jam_team_members_id_seq" OWNED BY "jam_team_members"."id";
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_team_members_team_fkey') THEN
ALTER TABLE "jam_team_members" ADD CONSTRAINT "jam_team_members_team_fkey"
FOREIGN KEY ("jam_team_id") REFERENCES "jam_teams" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_team_members_user_fkey') THEN
ALTER TABLE "jam_team_members" ADD CONSTRAINT "jam_team_members_user_fkey"
FOREIGN KEY ("user_id") REFERENCES "users" ("id");
END IF;
END
$$;
CREATE UNIQUE INDEX IF NOT EXISTS "ux_jam_team_members_team_user"
ON "jam_team_members" ("jam_team_id", "user_id");
-- ===========================================================================
-- 4) jam_entries (출품작 = 잼-게임 연결 조인. 평가 단위 = (jam_id, game_id) 활성 자연키)
-- ===========================================================================
CREATE SEQUENCE IF NOT EXISTS "jam_entries_id_seq";
CREATE TABLE IF NOT EXISTS "jam_entries" (
"id" bigint DEFAULT nextval('jam_entries_id_seq'::regclass) NOT NULL,
"jam_id" bigint NOT NULL,
"game_id" bigint NOT NULL,
"entrant_type" character varying(10) NOT NULL,
"entrant_user_id" bigint,
"jam_team_id" bigint,
"submitted_at" timestamp with time zone DEFAULT now() NOT NULL,
"is_delete" boolean DEFAULT false NOT NULL,
PRIMARY KEY ("id")
);
ALTER SEQUENCE "jam_entries_id_seq" OWNED BY "jam_entries"."id";
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_jam_fkey') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_jam_fkey"
FOREIGN KEY ("jam_id") REFERENCES "jams" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_game_fkey') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_game_fkey"
FOREIGN KEY ("game_id") REFERENCES "games" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_team_fkey') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_team_fkey"
FOREIGN KEY ("jam_team_id") REFERENCES "jam_teams" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_user_fkey') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_user_fkey"
FOREIGN KEY ("entrant_user_id") REFERENCES "users" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_entrant_type_check') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_entrant_type_check"
CHECK ("entrant_type" IN ('USER', 'TEAM'));
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_entries_entrant_xor_check') THEN
ALTER TABLE "jam_entries" ADD CONSTRAINT "jam_entries_entrant_xor_check"
CHECK (
("entrant_type" = 'USER' AND "entrant_user_id" IS NOT NULL AND "jam_team_id" IS NULL)
OR
("entrant_type" = 'TEAM' AND "jam_team_id" IS NOT NULL AND "entrant_user_id" IS NULL)
);
END IF;
END
$$;
CREATE UNIQUE INDEX IF NOT EXISTS "ux_jam_entries_jam_game_active"
ON "jam_entries" ("jam_id", "game_id") WHERE "is_delete" IS NOT TRUE;
CREATE INDEX IF NOT EXISTS "idx_jam_entries_jam" ON "jam_entries" ("jam_id");
CREATE INDEX IF NOT EXISTS "idx_jam_entries_game" ON "jam_entries" ("game_id");
-- ===========================================================================
-- 5) jam_status_log
-- ===========================================================================
CREATE SEQUENCE IF NOT EXISTS "jam_status_log_id_seq";
CREATE TABLE IF NOT EXISTS "jam_status_log" (
"id" bigint DEFAULT nextval('jam_status_log_id_seq'::regclass) NOT NULL,
"jam_id" bigint NOT NULL,
"from_status" character varying(20),
"to_status" character varying(20) NOT NULL,
"actor_id" bigint,
"transition_type" character varying(10) DEFAULT 'MANUAL' NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
PRIMARY KEY ("id")
);
ALTER SEQUENCE "jam_status_log_id_seq" OWNED BY "jam_status_log"."id";
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_status_log_jam_fkey') THEN
ALTER TABLE "jam_status_log" ADD CONSTRAINT "jam_status_log_jam_fkey"
FOREIGN KEY ("jam_id") REFERENCES "jams" ("id");
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_status_log_to_status_check') THEN
ALTER TABLE "jam_status_log" ADD CONSTRAINT "jam_status_log_to_status_check"
CHECK ("to_status" IN ('RECRUIT', 'DEV', 'EVAL', 'CLOSED'));
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'jam_status_log_transition_type_check') THEN
ALTER TABLE "jam_status_log" ADD CONSTRAINT "jam_status_log_transition_type_check"
CHECK ("transition_type" IN ('MANUAL', 'AUTO'));
END IF;
END
$$;
CREATE INDEX IF NOT EXISTS "idx_jam_status_log_jam" ON "jam_status_log" ("jam_id", "created_at" DESC);