91 lines
3.8 KiB
SQL
91 lines
3.8 KiB
SQL
-- W4 유저 배지/평판. 멱등. db/apply-local-ddl.sh 로 실행 DB 비파괴 적용.
|
|
-- 신규 도메인(스토리지 0). 추가만, 파괴 없음. search_path=dev.
|
|
|
|
-- 1) badges (배지 카탈로그 — 정의 가능·확장 가능)
|
|
CREATE SEQUENCE IF NOT EXISTS "badges_id_seq";
|
|
CREATE TABLE IF NOT EXISTS "badges" (
|
|
"id" bigint DEFAULT nextval('badges_id_seq'::regclass) NOT NULL,
|
|
"badge_key" character varying(50) NOT NULL,
|
|
"display_name" character varying(100) NOT NULL,
|
|
"description" character varying(500),
|
|
"badge_type" character varying(30) NOT NULL,
|
|
"criteria_json" text,
|
|
"is_active" boolean DEFAULT true NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
PRIMARY KEY ("id")
|
|
);
|
|
ALTER SEQUENCE "badges_id_seq" OWNED BY "badges"."id";
|
|
CREATE UNIQUE INDEX IF NOT EXISTS "ux_badges_key" ON "badges" ("badge_key");
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'badges_type_check') THEN
|
|
ALTER TABLE "badges"
|
|
ADD CONSTRAINT "badges_type_check"
|
|
CHECK ("badge_type" IN ('REVIEWER', 'TECHNICIAN'));
|
|
END IF;
|
|
END
|
|
$$;
|
|
|
|
-- 2) user_badges (유저↔배지 보유. 자동/수동 부여 공통 기록)
|
|
CREATE SEQUENCE IF NOT EXISTS "user_badges_id_seq";
|
|
CREATE TABLE IF NOT EXISTS "user_badges" (
|
|
"id" bigint DEFAULT nextval('user_badges_id_seq'::regclass) NOT NULL,
|
|
"user_id" bigint NOT NULL,
|
|
"badge_key" character varying(50) NOT NULL,
|
|
"awarded_by" bigint,
|
|
"awarded_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"revoked_at" timestamp with time zone,
|
|
"revoke_reason" character varying(500),
|
|
PRIMARY KEY ("id")
|
|
);
|
|
ALTER SEQUENCE "user_badges_id_seq" OWNED BY "user_badges"."id";
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'user_badges_user_id_fkey') THEN
|
|
ALTER TABLE "user_badges"
|
|
ADD CONSTRAINT "user_badges_user_id_fkey"
|
|
FOREIGN KEY ("user_id") REFERENCES "users" ("id");
|
|
END IF;
|
|
END
|
|
$$;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS "ux_user_badges_active"
|
|
ON "user_badges" ("user_id", "badge_key") WHERE "revoked_at" IS NULL;
|
|
CREATE INDEX IF NOT EXISTS "idx_user_badges_user_active"
|
|
ON "user_badges" ("user_id") WHERE "revoked_at" IS NULL;
|
|
|
|
-- 3) reputation_events (평판 신호 감사로그 — append-only, 임계 판정 단일 소스)
|
|
CREATE SEQUENCE IF NOT EXISTS "reputation_events_id_seq";
|
|
CREATE TABLE IF NOT EXISTS "reputation_events" (
|
|
"id" bigint DEFAULT nextval('reputation_events_id_seq'::regclass) NOT NULL,
|
|
"user_id" bigint NOT NULL,
|
|
"event_type" character varying(40) NOT NULL,
|
|
"source_ref" character varying(100),
|
|
"weight" integer DEFAULT 1 NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
PRIMARY KEY ("id")
|
|
);
|
|
ALTER SEQUENCE "reputation_events_id_seq" OWNED BY "reputation_events"."id";
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'reputation_events_type_check') THEN
|
|
ALTER TABLE "reputation_events"
|
|
ADD CONSTRAINT "reputation_events_type_check"
|
|
CHECK ("event_type" IN ('REVIEW_WRITTEN', 'GAME_UPLOADED'));
|
|
END IF;
|
|
END
|
|
$$;
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'reputation_events_user_id_fkey') THEN
|
|
ALTER TABLE "reputation_events"
|
|
ADD CONSTRAINT "reputation_events_user_id_fkey"
|
|
FOREIGN KEY ("user_id") REFERENCES "users" ("id");
|
|
END IF;
|
|
END
|
|
$$;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS "ux_reputation_events_source"
|
|
ON "reputation_events" ("user_id", "event_type", "source_ref")
|
|
WHERE "source_ref" IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS "idx_reputation_events_user_type"
|
|
ON "reputation_events" ("user_id", "event_type");
|