feat: Datenmodell Sprachnotizen (T7 L2 Task 4)
VoiceCapture und VoiceCaptureAudio nach Spec §3 mit CHECKs (audioBytes 1..2 MiB, durationSec 1..240, CONFIRMED genau mit inspectionId, audioMime nur bei AUDIO), Recht voice-captures:use für ADMIN, BEEKEEPER und STAFF, Sperrreihenfolge mit VoiceCapture am Ende, Ausschluss aus dem Backup mit Begründung, Wächter gegen Suche und Export. Refs #27 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
257286fbef
commit
af9df0afe4
10 files changed
+412
No files matched your search
@@ -0,0 +1,96 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "VoiceCaptureSource" AS ENUM ('AUDIO', 'TEXT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "VoiceCaptureStatus" AS ENUM ('QUEUED', 'TRANSCRIBING', 'TRANSCRIBED', 'EXTRACTING', 'READY', 'CONFIRMED', 'DISCARDED', 'FAILED', 'EXPIRED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VoiceCapture" (
|
||||
"id" TEXT NOT NULL,
|
||||
"ownerUserId" TEXT NOT NULL,
|
||||
"colonyId" TEXT NOT NULL,
|
||||
"inspectionDate" DATE NOT NULL,
|
||||
"source" "VoiceCaptureSource" NOT NULL,
|
||||
"status" "VoiceCaptureStatus" NOT NULL DEFAULT 'QUEUED',
|
||||
"audioMime" TEXT,
|
||||
"audioBytes" INTEGER,
|
||||
"durationSec" INTEGER,
|
||||
"transcriptEnc" TEXT,
|
||||
"suggestionEnc" TEXT,
|
||||
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||
"availableAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"claimedAt" TIMESTAMP(3),
|
||||
"claimToken" TEXT,
|
||||
"lastErrorCode" TEXT,
|
||||
"model" TEXT,
|
||||
"inputTokens" INTEGER,
|
||||
"outputTokens" INTEGER,
|
||||
"inspectionId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"readyAt" TIMESTAMP(3),
|
||||
"contentExpiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"contentDeletedAt" TIMESTAMP(3),
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "VoiceCapture_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VoiceCaptureAudio" (
|
||||
"captureId" TEXT NOT NULL,
|
||||
"dataEnc" BYTEA NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "VoiceCaptureAudio_pkey" PRIMARY KEY ("captureId")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceCapture_status_availableAt_idx" ON "VoiceCapture"("status", "availableAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceCapture_ownerUserId_status_idx" ON "VoiceCapture"("ownerUserId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceCapture_contentExpiresAt_idx" ON "VoiceCapture"("contentExpiresAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceCapture" ADD CONSTRAINT "VoiceCapture_ownerUserId_fkey" FOREIGN KEY ("ownerUserId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceCapture" ADD CONSTRAINT "VoiceCapture_colonyId_fkey" FOREIGN KEY ("colonyId") REFERENCES "Colony"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceCaptureAudio" ADD CONSTRAINT "VoiceCaptureAudio_captureId_fkey" FOREIGN KEY ("captureId") REFERENCES "VoiceCapture"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
|
||||
-- Constraints Prisma cannot express.
|
||||
ALTER TABLE "VoiceCapture"
|
||||
ADD CONSTRAINT "VoiceCapture_audioBytes_range"
|
||||
CHECK ("audioBytes" IS NULL OR "audioBytes" BETWEEN 1 AND 2097152);
|
||||
|
||||
ALTER TABLE "VoiceCapture"
|
||||
ADD CONSTRAINT "VoiceCapture_durationSec_range"
|
||||
CHECK ("durationSec" IS NULL OR "durationSec" BETWEEN 1 AND 240);
|
||||
|
||||
ALTER TABLE "VoiceCapture"
|
||||
ADD CONSTRAINT "VoiceCapture_confirmed_matches_inspection"
|
||||
CHECK (("status" = 'CONFIRMED') = ("inspectionId" IS NOT NULL));
|
||||
|
||||
ALTER TABLE "VoiceCapture"
|
||||
ADD CONSTRAINT "VoiceCapture_audioMime_only_for_audio"
|
||||
CHECK ("source" = 'AUDIO' OR "audioMime" IS NULL);
|
||||
|
||||
-- Permission: the boot-time catalog sync only grants new permissions to
|
||||
-- system roles (ADMIN), so the grants are made here (same as T6). READONLY
|
||||
-- and API_CLIENT get nothing: voice notes are for people who inspect.
|
||||
INSERT INTO "Permission" (id, key, resource, action, "labelDe", "groupDe", "sortOrder")
|
||||
VALUES
|
||||
(gen_random_uuid()::text, 'voice-captures:use', 'voice-captures', 'use', 'Benutzen', 'Sprache', 4000)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
INSERT INTO "RolePermission" ("roleId", "permissionId", "grantedAt")
|
||||
SELECT r.id, p.id, now()
|
||||
FROM "Role" r, "Permission" p
|
||||
WHERE p.key = 'voice-captures:use'
|
||||
AND r.key IN ('ADMIN', 'BEEKEEPER', 'STAFF')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Reference in new issue
Block a user