Files
t5de-hub/packages/db/drizzle/0012_cases.sql
T
dhkatzandClaude Opus 5.5 8af4b7b6a9
Pull request / title (pull_request) Successful in 1s
CI / test (pull_request) Successful in 1m5s
CI / image (apps/api/Dockerfile, t5de-hub-api) (pull_request) Skipped
CI / image (apps/web/Dockerfile, t5de-hub-web) (pull_request) Skipped
feat: cases (reports, rating reviews, removal and deletion requests, appeals) and notifications
Cases are one queue for what someone has to decide, each with a thread (internal notes for those deciding), an
assignee and a decision. Reports about a product go to the teams of the catalogs hosting it and to moderators, and
only the reporter and moderators know who reported. A creator lowering a rating opens a rating review; a catalog's
owner asking to delete it opens a deletion request; a catalog's team can ask for a product's removal everywhere; the
person an action affected can appeal it once, decided by another moderator (an admin may decide their own, flagged).
Resolving carries the case out: the rating is lowered, the product removed, the catalog deleted.

Notifications reach people on the website (a bell with the unread count) and their proxies (realtime): moderators'
edits to their products, removals and restores, decisions and replies on their cases, membership decisions.

Also: moderators can restore a removed product, and a product's creator and moderators can see it when it's adult
without an adult account (getting and wearing it still need one).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 07:03:59 -08:00

46 lines
2.8 KiB
SQL

CREATE TABLE "case_note" (
"id" serial PRIMARY KEY NOT NULL,
"case_id" integer NOT NULL,
"by_id" text,
"body" text NOT NULL,
"internal" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "moderation_case" (
"id" serial PRIMARY KEY NOT NULL,
"kind" text NOT NULL,
"status" text DEFAULT 'open' NOT NULL,
"tags" jsonb DEFAULT '{}'::jsonb NOT NULL,
"opened_by" text,
"assignee" text,
"reason" text DEFAULT '' NOT NULL,
"data" jsonb DEFAULT '{}'::jsonb NOT NULL,
"resolution" text DEFAULT '' NOT NULL,
"decided_by" text,
"decided_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "notification" (
"id" serial PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"type" text NOT NULL,
"tags" jsonb DEFAULT '{}'::jsonb NOT NULL,
"data" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"read_at" timestamp with time zone
);
--> statement-breakpoint
ALTER TABLE "case_note" ADD CONSTRAINT "case_note_case_id_moderation_case_id_fk" FOREIGN KEY ("case_id") REFERENCES "public"."moderation_case"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "case_note" ADD CONSTRAINT "case_note_by_id_user_id_fk" FOREIGN KEY ("by_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "moderation_case" ADD CONSTRAINT "moderation_case_opened_by_user_id_fk" FOREIGN KEY ("opened_by") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "moderation_case" ADD CONSTRAINT "moderation_case_assignee_user_id_fk" FOREIGN KEY ("assignee") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "moderation_case" ADD CONSTRAINT "moderation_case_decided_by_user_id_fk" FOREIGN KEY ("decided_by") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "notification" ADD CONSTRAINT "notification_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "case_note_case" ON "case_note" USING btree ("case_id","id");--> statement-breakpoint
CREATE INDEX "moderation_case_status" ON "moderation_case" USING btree ("status","id");--> statement-breakpoint
CREATE INDEX "moderation_case_opened_by" ON "moderation_case" USING btree ("opened_by");--> statement-breakpoint
CREATE INDEX "moderation_case_tags" ON "moderation_case" USING gin ("tags");--> statement-breakpoint
CREATE INDEX "notification_user" ON "notification" USING btree ("user_id","id");