feat: enforce signature-scoped drainage authorization before SMS submission

This commit is contained in:
hectorzhao
2026-09-10 13:29:04 +08:00
parent 5bcdbb2a03
commit 0c3f820cc9
35 changed files with 2769 additions and 791 deletions
@@ -0,0 +1,30 @@
ALTER TABLE "SmsMessageRecord" ADD COLUMN "drainageGate" JSONB;
ALTER TABLE "SmsSubmitRecord" ADD COLUMN "drainageGate" JSONB;
ALTER TABLE "SmsMessageRecord" ADD COLUMN "drainageReceiptPending" BOOLEAN NOT NULL DEFAULT false;
CREATE INDEX "SmsMessageRecord_drainage_receipt_pending" ON "SmsMessageRecord" ("updatedAt") WHERE "drainageReceiptPending" = true;
CREATE TABLE "SmsDrainageDecision" (
"id" TEXT PRIMARY KEY,
"messageRecordId" TEXT NOT NULL,
"decidedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"snapshot" JSONB NOT NULL
);
CREATE INDEX "SmsDrainageDecision_messageRecordId_decidedAt_idx" ON "SmsDrainageDecision" ("messageRecordId", "decidedAt");
CREATE OR REPLACE FUNCTION drainage_authorization_lock() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF TG_OP = 'UPDATE' AND OLD."signatureId" IS DISTINCT FROM NEW."signatureId" THEN
PERFORM pg_advisory_xact_lock(hashtextextended(value, 910))
FROM unnest(ARRAY[OLD."signatureId", NEW."signatureId"]) AS ids(value) ORDER BY value;
RETURN NEW;
END IF;
IF TG_OP = 'DELETE' THEN
PERFORM pg_advisory_xact_lock(hashtextextended(OLD."signatureId", 910));
RETURN OLD;
END IF;
PERFORM pg_advisory_xact_lock(hashtextextended(NEW."signatureId", 910));
RETURN NEW;
END $$;
CREATE TRIGGER drainage_material_authorization_lock BEFORE INSERT OR UPDATE OR DELETE ON "SmsDrainageInfo"
FOR EACH ROW EXECUTE FUNCTION drainage_authorization_lock();
CREATE TRIGGER drainage_report_authorization_lock BEFORE INSERT OR UPDATE OR DELETE ON "ChannelSignatureReportTask"
FOR EACH ROW EXECUTE FUNCTION drainage_authorization_lock();
+11
View File
@@ -1790,6 +1790,14 @@ model SmsApiRequest {
@@index([batchTaskId])
}
model SmsDrainageDecision {
id String @id @default(cuid())
messageRecordId String
decidedAt DateTime @default(now())
snapshot Json
@@index([messageRecordId, decidedAt])
}
model SmsMessageRecord {
monitorFacts SendingMonitorFact[]
id String @id @default(cuid())
@@ -1808,6 +1816,8 @@ model SmsMessageRecord {
content String
hasDrainageContent Boolean?
drainageDetection Json?
drainageGate Json?
drainageReceiptPending Boolean @default(false)
drainageDetectionVersion String?
drainageEvaluatedAt DateTime?
billingUnits Int @default(1)
@@ -1880,6 +1890,7 @@ model CmppSubmitSession {
}
model SmsSubmitRecord {
drainageGate Json?
id String @id @default(cuid())
tenantId String?
batchTaskId String?