feat: 实现投瓶和异步内容审核

This commit is contained in:
root
2026-09-15 01:28:11 +08:00
parent b480d2c91f
commit f455552e92
25 changed files with 1204 additions and 18 deletions
@@ -0,0 +1,16 @@
ALTER TABLE "bottles" ADD COLUMN "client_request_id" VARCHAR(128);
UPDATE "bottles" SET "client_request_id" = "id"::text WHERE "client_request_id" IS NULL;
ALTER TABLE "bottles" ALTER COLUMN "client_request_id" SET NOT NULL;
CREATE UNIQUE INDEX "bottles_author_id_client_request_id_key"
ON "bottles"("author_id", "client_request_id");
CREATE UNIQUE INDEX "moderation_tasks_target_type_target_id_key"
ON "moderation_tasks"("target_type", "target_id");
ALTER TABLE "outbox_events"
ADD COLUMN "dedupe_key" VARCHAR(255),
ADD COLUMN "locked_at" TIMESTAMPTZ(3);
UPDATE "outbox_events" SET "dedupe_key" = "id"::text WHERE "dedupe_key" IS NULL;
ALTER TABLE "outbox_events" ALTER COLUMN "dedupe_key" SET NOT NULL;
CREATE UNIQUE INDEX "outbox_events_dedupe_key_key" ON "outbox_events"("dedupe_key");
CREATE INDEX "outbox_events_processing_lease_idx" ON "outbox_events"("status", "locked_at");
+21 -16
View File
@@ -193,23 +193,25 @@ model RefreshToken {
}
model Bottle {
id String @id @default(uuid()) @db.Uuid
authorId String @map("author_id") @db.Uuid
contentText String @map("content_text") @db.Text
reviewStatus ReviewStatus @default(DRAFT) @map("review_status")
poolStatus BottlePoolStatus @default(CLOSED) @map("pool_status")
version Int @default(1)
approvedAt DateTime? @map("approved_at") @db.Timestamptz(3)
consumedAt DateTime? @map("consumed_at") @db.Timestamptz(3)
expiresAt DateTime? @map("expires_at") @db.Timestamptz(3)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
author Account @relation(fields: [authorId], references: [id], onDelete: Restrict)
leases BottlePickLease[]
pickHistory BottlePickHistory[]
conversation Conversation?
reports Report[]
id String @id @default(uuid()) @db.Uuid
authorId String @map("author_id") @db.Uuid
clientRequestId String @default(uuid()) @map("client_request_id") @db.VarChar(128)
contentText String @map("content_text") @db.Text
reviewStatus ReviewStatus @default(DRAFT) @map("review_status")
poolStatus BottlePoolStatus @default(CLOSED) @map("pool_status")
version Int @default(1)
approvedAt DateTime? @map("approved_at") @db.Timestamptz(3)
consumedAt DateTime? @map("consumed_at") @db.Timestamptz(3)
expiresAt DateTime? @map("expires_at") @db.Timestamptz(3)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
author Account @relation(fields: [authorId], references: [id], onDelete: Restrict)
leases BottlePickLease[]
pickHistory BottlePickHistory[]
conversation Conversation?
reports Report[]
@@unique([authorId, clientRequestId])
@@index([poolStatus, createdAt])
@@index([reviewStatus, createdAt])
@@index([authorId, createdAt])
@@ -380,6 +382,7 @@ model ModerationTask {
assignedTo Account? @relation("Moderator", fields: [assignedToId], references: [id], onDelete: SetNull)
sanctions Sanction[]
@@unique([targetType, targetId])
@@index([status, createdAt])
@@index([targetType, targetId])
@@index([assignedToId, status])
@@ -426,10 +429,12 @@ model OutboxEvent {
aggregateType String @map("aggregate_type") @db.VarChar(100)
aggregateId String @map("aggregate_id") @db.Uuid
eventType String @map("event_type") @db.VarChar(150)
dedupeKey String @unique @default(uuid()) @map("dedupe_key") @db.VarChar(255)
payload Json
status OutboxStatus @default(PENDING)
attempts Int @default(0)
nextRetryAt DateTime @default(now()) @map("next_retry_at") @db.Timestamptz(3)
lockedAt DateTime? @map("locked_at") @db.Timestamptz(3)
publishedAt DateTime? @map("published_at") @db.Timestamptz(3)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)