@marinoscar/kvox-eval 0.0.0-bootstrap → 0.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/ask/index.d.ts +6 -0
- package/dist/ask/index.js +28 -0
- package/dist/ask/question-schema.d.ts +121 -0
- package/dist/ask/question-schema.js +167 -0
- package/dist/ask/report.d.ts +88 -0
- package/dist/ask/report.js +170 -0
- package/dist/ask/scorer.d.ts +104 -0
- package/dist/ask/scorer.js +164 -0
- package/dist/ask-run/ask-command.d.ts +62 -0
- package/dist/ask-run/ask-command.js +254 -0
- package/dist/ask-run/host/app.d.ts +65 -0
- package/dist/ask-run/host/app.js +146 -0
- package/dist/ask-run/host/db.d.ts +38 -0
- package/dist/ask-run/host/db.js +126 -0
- package/dist/ask-run/host/ports.d.ts +35 -0
- package/dist/ask-run/host/ports.js +113 -0
- package/dist/ask-run/index.d.ts +13 -0
- package/dist/ask-run/index.js +35 -0
- package/dist/ask-run/replay.d.ts +128 -0
- package/dist/ask-run/replay.js +212 -0
- package/dist/ask-run/run-ask-eval.d.ts +125 -0
- package/dist/ask-run/run-ask-eval.js +193 -0
- package/dist/ask-run/seed-golden-graph.d.ts +64 -0
- package/dist/ask-run/seed-golden-graph.js +495 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +12 -0
- package/dist/cli/kg-command.d.ts +66 -0
- package/dist/cli/kg-command.js +238 -0
- package/dist/cli/main.d.ts +18 -0
- package/dist/cli/main.js +69 -0
- package/dist/fixtures/domains.d.ts +16 -0
- package/dist/fixtures/domains.js +33 -0
- package/dist/fixtures/fixture-schema.d.ts +323 -0
- package/dist/fixtures/fixture-schema.js +199 -0
- package/dist/fixtures/index.d.ts +16 -0
- package/dist/fixtures/index.js +40 -0
- package/dist/fixtures/load.d.ts +73 -0
- package/dist/fixtures/load.js +137 -0
- package/dist/fixtures/questions.d.ts +15 -0
- package/dist/fixtures/questions.js +26 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +36 -0
- package/dist/kg/gold-runner.d.ts +13 -0
- package/dist/kg/gold-runner.js +57 -0
- package/dist/kg/index.d.ts +17 -0
- package/dist/kg/index.js +65 -0
- package/dist/kg/internals.d.ts +7 -0
- package/dist/kg/internals.js +17 -0
- package/dist/kg/prediction-schema.d.ts +245 -0
- package/dist/kg/prediction-schema.js +102 -0
- package/dist/kg/predictions.d.ts +11 -0
- package/dist/kg/predictions.js +49 -0
- package/dist/kg/report.d.ts +84 -0
- package/dist/kg/report.js +125 -0
- package/dist/kg/run-kg-eval.d.ts +77 -0
- package/dist/kg/run-kg-eval.js +137 -0
- package/dist/kg/runner.d.ts +72 -0
- package/dist/kg/runner.js +51 -0
- package/dist/kg/runners/extract-resolve-runner.d.ts +40 -0
- package/dist/kg/runners/extract-resolve-runner.js +199 -0
- package/dist/kg/runners/extract-runner.d.ts +65 -0
- package/dist/kg/runners/extract-runner.js +243 -0
- package/dist/kg/scorer.d.ts +226 -0
- package/dist/kg/scorer.js +463 -0
- package/dist/kg/targets.d.ts +17 -0
- package/dist/kg/targets.js +16 -0
- package/dist/kg/text.d.ts +45 -0
- package/dist/kg/text.js +100 -0
- package/dist/live/adapters.d.ts +16 -0
- package/dist/live/adapters.js +58 -0
- package/dist/live/env.d.ts +39 -0
- package/dist/live/env.js +56 -0
- package/dist/live/index.d.ts +6 -0
- package/dist/live/index.js +16 -0
- package/dist/live/live-ai.d.ts +104 -0
- package/dist/live/live-ai.js +157 -0
- package/dist/parity/constants.d.ts +79 -0
- package/dist/parity/constants.js +104 -0
- package/dist/parity/index.d.ts +20 -0
- package/dist/parity/index.js +38 -0
- package/dist/parity/internals.d.ts +8 -0
- package/dist/parity/internals.js +16 -0
- package/dist/parity/scenario.d.ts +45 -0
- package/dist/parity/scenario.js +245 -0
- package/dist/parity/script.d.ts +44 -0
- package/dist/parity/script.js +136 -0
- package/dist/parity/snapshot.d.ts +43 -0
- package/dist/parity/snapshot.js +71 -0
- package/dist/real-data/index.d.ts +2 -0
- package/dist/real-data/index.js +12 -0
- package/dist/real-data/real-data.d.ts +76 -0
- package/dist/real-data/real-data.js +156 -0
- package/fixtures/kg-golden/README.md +136 -0
- package/fixtures/kg-golden/ask-questions.json +458 -0
- package/fixtures/kg-golden/meetings/m01-northwind-pilot-kickoff.json +792 -0
- package/fixtures/kg-golden/meetings/m02-halden-migration-planning.json +814 -0
- package/fixtures/kg-golden/meetings/m03-larkspur-weekly-sync.json +601 -0
- package/fixtures/kg-golden/meetings/m04-corvid-intake-discovery.json +690 -0
- package/fixtures/kg-golden/meetings/m05-hosting-vendor-selection.json +631 -0
- package/fixtures/kg-golden/meetings/m06-northwind-floor-data-review.json +649 -0
- package/fixtures/kg-golden/meetings/m07-gullwing-intro-notes.json +428 -0
- package/fixtures/kg-golden/meetings/m08-halden-migration-checkpoint.json +672 -0
- package/fixtures/kg-golden/meetings/m09-northwind-platform-org-update.json +711 -0
- package/fixtures/kg-golden/meetings/m10-corvid-prototype-review.json +623 -0
- package/fixtures/kg-golden/meetings/m11-solvane-grid-dashboard-scoping.json +689 -0
- package/fixtures/kg-golden/meetings/m12-northwind-pilot-replan.json +681 -0
- package/fixtures/kg-golden/meetings/m13-halden-cutover-go-no-go.json +721 -0
- package/fixtures/kg-golden/meetings/m14-gullwing-discovery-readout.json +719 -0
- package/fixtures/kg-golden/meetings/m15-halden-handover-ravi-leaving.json +716 -0
- package/fixtures/kg-golden/meetings/m16-varden-claims-portal-intro.json +704 -0
- package/fixtures/kg-golden/meetings/m17-corvid-usability-debrief.json +572 -0
- package/fixtures/kg-golden/meetings/m18-hosting-decision-revisited.json +655 -0
- package/fixtures/kg-golden/meetings/m19-solvane-integration-kickoff.json +726 -0
- package/fixtures/kg-golden/meetings/m20-northwind-go-live-retro.json +673 -0
- package/fixtures/kg-golden/meetings/m21-quarterly-account-review.json +449 -0
- package/fixtures/kg-golden/meetings/m22-halden-intro-call-2020.json +558 -0
- package/fixtures/kg-golden/meetings/m23-gullwing-model-review.json +702 -0
- package/fixtures/kg-golden/meetings/m24-varden-discovery-midpoint.json +643 -0
- package/fixtures/kg-golden/meetings/m25-corvid-rollout-planning.json +642 -0
- package/fixtures/kg-golden/meetings/m26-larkspur-engineering-prep.json +695 -0
- package/fixtures/kg-golden/meetings/m27-solvane-phase-one-demo.json +649 -0
- package/fixtures/kg-golden/meetings/m28-northwind-building-5-scoping.json +715 -0
- package/fixtures/kg-golden/meetings/m29-halden-southern-cutover-review.json +752 -0
- package/fixtures/kg-golden/meetings/m30-varden-portal-build-kickoff.json +697 -0
- package/fixtures/kg-golden/meetings/m31-gullwing-rollout-renewal.json +681 -0
- package/fixtures/kg-golden/meetings/m32-brambleway-weekly-sync.json +472 -0
- package/fixtures/kg-golden/meetings/m33-nina-oliver-one-on-one.json +342 -0
- package/fixtures/kg-golden/meetings/m34-coffee-with-dana.json +249 -0
- package/fixtures/kg-golden/meetings/m35-brambleway-june-sync.json +553 -0
- package/fixtures/kg-golden/meetings/m36-copenhagen-conference-planning.json +296 -0
- package/host/generated/client.d.ts +1 -0
- package/host/generated/client.js +5 -0
- package/host/generated/default.d.ts +1 -0
- package/host/generated/default.js +5 -0
- package/host/generated/edge.d.ts +1 -0
- package/host/generated/edge.js +1658 -0
- package/host/generated/index-browser.js +1684 -0
- package/host/generated/index.d.ts +192335 -0
- package/host/generated/index.js +1658 -0
- package/host/generated/package.json +139 -0
- package/host/generated/query_compiler_fast_bg.js +2 -0
- package/host/generated/query_compiler_fast_bg.wasm +0 -0
- package/host/generated/query_compiler_fast_bg.wasm-base64.js +2 -0
- package/host/generated/runtime/client.d.ts +3433 -0
- package/host/generated/runtime/client.js +110 -0
- package/host/generated/runtime/index-browser.d.ts +90 -0
- package/host/generated/runtime/index-browser.js +6 -0
- package/host/generated/runtime/wasm-compiler-edge.js +100 -0
- package/host/generated/schema.prisma +6312 -0
- package/host/generated/wasm-edge-light-loader.mjs +5 -0
- package/host/generated/wasm-worker-loader.mjs +5 -0
- package/host/prisma/fragments/kvox.ask.prisma +126 -0
- package/host/prisma/fragments/kvox.graph.prisma +1073 -0
- package/host/prisma/fragments/kvox.notes.prisma +787 -0
- package/host/prisma/fragments/kvox.search.prisma +211 -0
- package/host/prisma/fragments/kvox.transcripts.prisma +790 -0
- package/host/prisma/kvox.lock +101 -0
- package/host/prisma/migrations/20240101000000_initial/migration.sql +297 -0
- package/host/prisma/migrations/20240101000001_add_personal_access_tokens/migration.sql +31 -0
- package/host/prisma/migrations/20240101000002_add_credentials/migration.sql +20 -0
- package/host/prisma/migrations/20240101000003_add_notification_deliveries/migration.sql +27 -0
- package/host/prisma/migrations/20240101000004_drop_stale_uuid_defaults/migration.sql +35 -0
- package/host/prisma/migrations/20240101000005_add_notifications/migration.sql +22 -0
- package/host/prisma/migrations/20240101000006_add_push_subscriptions/migration.sql +25 -0
- package/host/prisma/migrations/20240101000007_add_jobs/migration.sql +110 -0
- package/host/prisma/migrations/20240101000008_add_worker_nodes/migration.sql +90 -0
- package/host/prisma/migrations/20240101000009_add_database_backup_runs/migration.sql +104 -0
- package/host/prisma/migrations/20240101000010_add_notification_broadcasts/migration.sql +57 -0
- package/host/prisma/migrations/20240101000011_add_backup_run_job_link/migration.sql +87 -0
- package/host/prisma/migrations/20240101000012_add_job_node_secrets/migration.sql +61 -0
- package/host/prisma/migrations/20240101000013_add_backup_run_pg_dump_version/migration.sql +26 -0
- package/host/prisma/migrations/20240101000014_add_job_claim_token/migration.sql +92 -0
- package/host/prisma/migrations/20240101000015_add_ai_platform/migration.sql +108 -0
- package/host/prisma/migrations/20240101000016_revoke_viewer_ai_use/migration.sql +32 -0
- package/host/prisma/migrations/20240101000017_add_user_credentials/migration.sql +29 -0
- package/host/prisma/migrations/20240101000018_add_device_session_credential_link/migration.sql +52 -0
- package/host/prisma/migrations/20240101000019_add_worker_node_vitals/migration.sql +3 -0
- package/host/prisma/migrations/20240101000020_add_job_trace_context/migration.sql +6 -0
- package/host/prisma/migrations/20240101000021_add_retention_created_at_indexes/migration.sql +13 -0
- package/host/prisma/migrations/20240101000022_add_organizations/migration.sql +142 -0
- package/host/prisma/migrations/20240101000023_split_system_org_roles/migration.sql +131 -0
- package/host/prisma/migrations/20240101000024_org_scoped_rls/migration.sql +215 -0
- package/host/prisma/migrations/20240101000025_add_groups/migration.sql +165 -0
- package/host/prisma/migrations/20240101000026_add_grants/migration.sql +117 -0
- package/host/prisma/migrations/20240101000027_add_org_settings/migration.sql +49 -0
- package/host/prisma/migrations/20240101000028_add_org_credentials/migration.sql +54 -0
- package/host/prisma/migrations/20240101000029_add_jobs_org_id/migration.sql +18 -0
- package/host/prisma/migrations/20240101000030_add_jobs_org_id_status_index/migration.sql +6 -0
- package/host/prisma/migrations/20240101000031_add_broadcast_target_org/migration.sql +21 -0
- package/host/prisma/migrations/20240101000032_add_android_app/migration.sql +60 -0
- package/host/prisma/migrations/20240101000033_open_job_reason/migration.sql +16 -0
- package/host/prisma/migrations/20240101000034_ai_usage_feature/migration.sql +37 -0
- package/host/prisma/migrations/20240101000035_add_app_metadata/migration.sql +49 -0
- package/host/prisma/migrations/20240101000036_open_sharing_vocabularies/migration.sql +97 -0
- package/host/prisma/migrations/20260914130000_kvox_add_transcripts/migration.sql +322 -0
- package/host/prisma/migrations/20260914140000_kvox_add_notes/migration.sql +311 -0
- package/host/prisma/migrations/20260915120000_kvox_add_search_vectors/migration.sql +150 -0
- package/host/prisma/migrations/20260915130000_kvox_add_search_embeddings/migration.sql +362 -0
- package/host/prisma/migrations/20260915210000_kvox_add_note_title_source/migration.sql +30 -0
- package/host/prisma/migrations/20260923120000_kvox_add_note_generation_context_snapshot/migration.sql +24 -0
- package/host/prisma/migrations/20260923130000_kvox_add_user_hidden_note_templates/migration.sql +35 -0
- package/host/prisma/migrations/20260923140000_kvox_add_transcript_speaker_identities/migration.sql +6 -0
- package/host/prisma/migrations/20260923150000_kvox_transcript_name_checks/migration.sql +95 -0
- package/host/prisma/migrations/20260923160000_kvox_add_note_body_format/migration.sql +27 -0
- package/host/prisma/migrations/20260923170000_kvox_add_note_version_body_format/migration.sql +23 -0
- package/host/prisma/migrations/20260926012548_kvox_add_knowledge_graph/migration.sql +680 -0
- package/host/prisma/migrations/20260926030000_kvox_fix_kg_relations_valid_precision_chk/migration.sql +29 -0
- package/host/prisma/migrations/20260926030100_kvox_add_transcript_recorded_at/migration.sql +9 -0
- package/host/prisma/migrations/20260926030200_kvox_kg_evidence_invariant/migration.sql +60 -0
- package/host/prisma/migrations/20260926040000_kvox_add_kg_graph_layouts/migration.sql +30 -0
- package/host/prisma/migrations/20260926050000_kvox_add_ask_conversations/migration.sql +99 -0
- package/host/prisma/migrations/20260926231512_kvox_add_kg_exports/migration.sql +52 -0
- package/host/prisma/migrations/20261016120000_kvox_transcripts_org_id/migration.sql +49 -0
- package/host/prisma/platform.lock +319 -0
- package/host/prisma/schema/app.kvox.ask.prisma +110 -0
- package/host/prisma/schema/app.kvox.graph.prisma +1030 -0
- package/host/prisma/schema/app.kvox.notes.prisma +746 -0
- package/host/prisma/schema/app.kvox.search.prisma +208 -0
- package/host/prisma/schema/app.kvox.transcripts.prisma +726 -0
- package/host/prisma/schema/platform.ai.prisma +419 -0
- package/host/prisma/schema/platform.android-app.prisma +46 -0
- package/host/prisma/schema/platform.base.prisma +15 -0
- package/host/prisma/schema/platform.credentials.prisma +156 -0
- package/host/prisma/schema/platform.db-backup.prisma +359 -0
- package/host/prisma/schema/platform.identity.prisma +638 -0
- package/host/prisma/schema/platform.jobs.prisma +824 -0
- package/host/prisma/schema/platform.notifications.prisma +641 -0
- package/host/prisma/schema/platform.settings.prisma +53 -0
- package/host/prisma/schema/platform.sharing.prisma +208 -0
- package/host/prisma/schema/platform.storage.prisma +118 -0
- package/package.json +112 -1
- package/parity/requests.ask.json +2681 -0
- package/parity/requests.m01.json +1554 -0
- package/parity/requests.m02.json +1554 -0
- package/parity/requests.m03.json +1554 -0
- package/parity/requests.m04.json +1554 -0
- package/parity/requests.m05.json +1554 -0
- package/parity/requests.m06.json +1554 -0
- package/parity/requests.m07.json +1554 -0
- package/parity/requests.m08.json +1554 -0
- package/parity/requests.m09.json +1554 -0
- package/parity/requests.m10.json +1554 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Open the sharing vocabularies (PP-14.15b, issue #967)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- Two closed Prisma enums become plain TEXT, so an app can add a group role
|
|
6
|
+
-- (`registerGroupRole`) and a persisted grantee kind (`registerGranteeKind`)
|
|
7
|
+
-- at zero further migrations:
|
|
8
|
+
--
|
|
9
|
+
-- group_members.role, group_invites.role "GroupRole" admin | editor | viewer
|
|
10
|
+
-- grants.grantee_kind "GrantGranteeKind" user | group | link
|
|
11
|
+
--
|
|
12
|
+
-- Every stored value is kept as it is (the cast is the enum's own label) and
|
|
13
|
+
-- both enums are dropped. No CHECK on the role columns on purpose: a row must
|
|
14
|
+
-- outlive the role that wrote it, and the allowed set is the API's registry.
|
|
15
|
+
--
|
|
16
|
+
-- grants gains the nullable `grantee_ref` TEXT: the reference of a grantee of an
|
|
17
|
+
-- app-registered kind (a domain, a team id), as the kind normalised it. The
|
|
18
|
+
-- built-in kinds keep their own columns (grantee_user_id, grantee_group_id,
|
|
19
|
+
-- link_token_hash) and leave it NULL.
|
|
20
|
+
--
|
|
21
|
+
-- RAW SQL (intentional schema drift, as in 0027_add_grants):
|
|
22
|
+
-- grants_grantee_consistency_check relaxed: the three built-in row shapes
|
|
23
|
+
-- (now also with grantee_ref NULL) OR a row
|
|
24
|
+
-- of any OTHER kind that carries a
|
|
25
|
+
-- grantee_ref and none of the built-in
|
|
26
|
+
-- grantee columns. This CHECK is the second
|
|
27
|
+
-- line of defence behind the API.
|
|
28
|
+
-- grants_active_user_uniq_idx,
|
|
29
|
+
-- grants_active_group_uniq_idx rebuilt unchanged apart from the predicate
|
|
30
|
+
-- literal, which was an enum cast and is
|
|
31
|
+
-- now text (an index predicate over a column
|
|
32
|
+
-- whose type changes cannot be re-parsed).
|
|
33
|
+
-- grants_active_ref_uniq_idx NEW: at most one ACTIVE grant per
|
|
34
|
+
-- (resource, app kind, reference); the grants
|
|
35
|
+
-- API upserts on it.
|
|
36
|
+
-- All three indexes are listed in raw-sql-indexes.json.
|
|
37
|
+
--
|
|
38
|
+
-- group_members, group_invites and grants are organization tables under forced
|
|
39
|
+
-- row-level security, so the migration runs with the bypass on for its
|
|
40
|
+
-- transaction (set_config with is_local = true: transaction-local, never
|
|
41
|
+
-- session-level).
|
|
42
|
+
--
|
|
43
|
+
-- LOCKING. Each ALTER TABLE takes an ACCESS EXCLUSIVE lock held until COMMIT, so
|
|
44
|
+
-- no concurrent write can slip a duplicate in while an index is dropped and
|
|
45
|
+
-- rebuilt. The three column changes rewrite their tables (the sharing tables
|
|
46
|
+
-- are small: one row per membership, invite and grant).
|
|
47
|
+
-- =============================================================================
|
|
48
|
+
|
|
49
|
+
BEGIN;
|
|
50
|
+
SELECT set_config('app.rls_bypass', 'on', true);
|
|
51
|
+
|
|
52
|
+
-- Dependents of grants.grantee_kind: the two partial unique indexes and the CHECK.
|
|
53
|
+
DROP INDEX "grants_active_user_uniq_idx";
|
|
54
|
+
DROP INDEX "grants_active_group_uniq_idx";
|
|
55
|
+
ALTER TABLE "grants" DROP CONSTRAINT "grants_grantee_consistency_check";
|
|
56
|
+
|
|
57
|
+
-- AlterTable (the default is an enum literal: drop it first, set the text one after)
|
|
58
|
+
ALTER TABLE "group_members" ALTER COLUMN "role" DROP DEFAULT;
|
|
59
|
+
ALTER TABLE "group_members" ALTER COLUMN "role" TYPE TEXT USING "role"::text;
|
|
60
|
+
ALTER TABLE "group_members" ALTER COLUMN "role" SET DEFAULT 'viewer';
|
|
61
|
+
|
|
62
|
+
-- AlterTable
|
|
63
|
+
ALTER TABLE "group_invites" ALTER COLUMN "role" DROP DEFAULT;
|
|
64
|
+
ALTER TABLE "group_invites" ALTER COLUMN "role" TYPE TEXT USING "role"::text;
|
|
65
|
+
ALTER TABLE "group_invites" ALTER COLUMN "role" SET DEFAULT 'viewer';
|
|
66
|
+
|
|
67
|
+
-- AlterTable
|
|
68
|
+
ALTER TABLE "grants" ALTER COLUMN "grantee_kind" TYPE TEXT USING "grantee_kind"::text;
|
|
69
|
+
ALTER TABLE "grants" ADD COLUMN "grantee_ref" TEXT;
|
|
70
|
+
|
|
71
|
+
-- DropEnum
|
|
72
|
+
DROP TYPE "GroupRole";
|
|
73
|
+
|
|
74
|
+
-- DropEnum
|
|
75
|
+
DROP TYPE "GrantGranteeKind";
|
|
76
|
+
|
|
77
|
+
-- CreateIndex (partial: one active grant per resource and user)
|
|
78
|
+
CREATE UNIQUE INDEX "grants_active_user_uniq_idx" ON "grants"("resource_type", "resource_id", "grantee_user_id") WHERE "grantee_kind" = 'user' AND "revoked_at" IS NULL;
|
|
79
|
+
|
|
80
|
+
-- CreateIndex (partial: one active grant per resource and group)
|
|
81
|
+
CREATE UNIQUE INDEX "grants_active_group_uniq_idx" ON "grants"("resource_type", "resource_id", "grantee_group_id") WHERE "grantee_kind" = 'group' AND "revoked_at" IS NULL;
|
|
82
|
+
|
|
83
|
+
-- CreateIndex (partial: one active grant per resource, app-registered kind and reference)
|
|
84
|
+
CREATE UNIQUE INDEX "grants_active_ref_uniq_idx" ON "grants"("resource_type", "resource_id", "grantee_kind", "grantee_ref") WHERE "grantee_kind" NOT IN ('user', 'group', 'link') AND "revoked_at" IS NULL;
|
|
85
|
+
|
|
86
|
+
-- AddCheckConstraint (the grantee columns match the grantee kind)
|
|
87
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_grantee_consistency_check" CHECK (
|
|
88
|
+
("grantee_kind" = 'user' AND "grantee_user_id" IS NOT NULL AND "grantee_group_id" IS NULL AND "link_token_hash" IS NULL AND "grantee_ref" IS NULL)
|
|
89
|
+
OR
|
|
90
|
+
("grantee_kind" = 'group' AND "grantee_user_id" IS NULL AND "grantee_group_id" IS NOT NULL AND "link_token_hash" IS NULL AND "grantee_ref" IS NULL)
|
|
91
|
+
OR
|
|
92
|
+
("grantee_kind" = 'link' AND "grantee_user_id" IS NULL AND "grantee_group_id" IS NULL AND "link_token_hash" IS NOT NULL AND "grantee_ref" IS NULL)
|
|
93
|
+
OR
|
|
94
|
+
("grantee_kind" NOT IN ('user', 'group', 'link') AND "grantee_ref" IS NOT NULL AND "grantee_user_id" IS NULL AND "grantee_group_id" IS NULL AND "link_token_hash" IS NULL)
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
COMMIT;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Transcripts (issue #24, epic #19)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
-- Six tables: `transcripts`, `transcript_speakers`, `transcript_segments`,
|
|
5
|
+
-- `transcript_versions`, `transcript_shares`, `transcript_exports`. See the
|
|
6
|
+
-- block comment above the `Transcript` model in prisma/schema.prisma for the
|
|
7
|
+
-- full reasoning behind every `onDelete` choice below (in particular why
|
|
8
|
+
-- `owner_id` cascades while every `storage_objects` FK on these tables
|
|
9
|
+
-- restricts, and why `speaker_id` on `transcript_segments` also restricts)
|
|
10
|
+
-- and docs/specs/transcription.md §3–§6 for the product reasoning this file
|
|
11
|
+
-- intentionally does not restate at length.
|
|
12
|
+
--
|
|
13
|
+
-- ONE HAND-WRITTEN, PRISMA-INEXPRESSIBLE CONSTRAINT, flagged where it
|
|
14
|
+
-- appears below: `transcript_speakers_transcript_id_label_key`, a PARTIAL
|
|
15
|
+
-- unique index (`WHERE "label" IS NOT NULL`) — the same
|
|
16
|
+
-- Prisma-DSL-has-no-WHERE-clause pattern `jobs_active_dedup_uniq_idx` and
|
|
17
|
+
-- `database_backup_runs_active_uniq_idx` already establish in this
|
|
18
|
+
-- repository. `prisma migrate dev`/`diff` will never regenerate it and will
|
|
19
|
+
-- want to drop it on a naive reconcile — do not let it. Every OTHER unique
|
|
20
|
+
-- constraint in this migration (`transcript_versions` on `(transcript_id,
|
|
21
|
+
-- version)` and `(transcript_id, client_batch_id)`, `transcript_shares` on
|
|
22
|
+
-- `(transcript_id, user_id)`) is a plain, fully Prisma-expressible unique
|
|
23
|
+
-- index and needed no such treatment.
|
|
24
|
+
-- =============================================================================
|
|
25
|
+
|
|
26
|
+
-- CreateEnum
|
|
27
|
+
CREATE TYPE "TranscriptStatus" AS ENUM ('uploading', 'processing', 'ready', 'failed', 'deleting');
|
|
28
|
+
|
|
29
|
+
-- CreateEnum
|
|
30
|
+
CREATE TYPE "TranscriptionStatus" AS ENUM ('waiting_input', 'queued', 'submitting', 'submitted', 'processing', 'completed', 'failed', 'cancelled');
|
|
31
|
+
|
|
32
|
+
-- CreateEnum
|
|
33
|
+
CREATE TYPE "PlaybackStatus" AS ENUM ('pending', 'processing', 'ready', 'failed', 'not_needed');
|
|
34
|
+
|
|
35
|
+
-- CreateEnum
|
|
36
|
+
CREATE TYPE "WordsAlignment" AS ENUM ('exact', 'interpolated', 'none');
|
|
37
|
+
|
|
38
|
+
-- CreateEnum
|
|
39
|
+
CREATE TYPE "SegmentOrigin" AS ENUM ('ai', 'user');
|
|
40
|
+
|
|
41
|
+
-- CreateEnum
|
|
42
|
+
CREATE TYPE "TranscriptVersionKind" AS ENUM ('ai_original', 'edit', 'restore');
|
|
43
|
+
|
|
44
|
+
-- CreateEnum
|
|
45
|
+
CREATE TYPE "TranscriptShareRole" AS ENUM ('viewer', 'editor');
|
|
46
|
+
|
|
47
|
+
-- CreateEnum
|
|
48
|
+
CREATE TYPE "TranscriptExportStatus" AS ENUM ('pending', 'ready', 'failed');
|
|
49
|
+
|
|
50
|
+
-- CreateTable
|
|
51
|
+
CREATE TABLE "transcripts" (
|
|
52
|
+
"id" UUID NOT NULL,
|
|
53
|
+
"owner_id" UUID NOT NULL,
|
|
54
|
+
"title" TEXT NOT NULL,
|
|
55
|
+
"language" TEXT,
|
|
56
|
+
"status" "TranscriptStatus" NOT NULL DEFAULT 'uploading',
|
|
57
|
+
"transcription_status" "TranscriptionStatus" NOT NULL DEFAULT 'waiting_input',
|
|
58
|
+
"playback_status" "PlaybackStatus" NOT NULL DEFAULT 'pending',
|
|
59
|
+
"source_object_id" UUID NOT NULL,
|
|
60
|
+
"playback_object_id" UUID,
|
|
61
|
+
"raw_result_object_id" UUID,
|
|
62
|
+
"provider" TEXT NOT NULL,
|
|
63
|
+
"provider_job_id" TEXT,
|
|
64
|
+
"provider_options" JSONB,
|
|
65
|
+
"submitted_at" TIMESTAMPTZ,
|
|
66
|
+
"last_polled_at" TIMESTAMPTZ,
|
|
67
|
+
"completed_at" TIMESTAMPTZ,
|
|
68
|
+
"remote_deleted_at" TIMESTAMPTZ,
|
|
69
|
+
"deleted_at" TIMESTAMPTZ,
|
|
70
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
71
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
72
|
+
"duration_ms" INTEGER,
|
|
73
|
+
"failure_reason" TEXT,
|
|
74
|
+
"current_version" INTEGER NOT NULL DEFAULT 0,
|
|
75
|
+
"speaker_count" INTEGER NOT NULL DEFAULT 0,
|
|
76
|
+
"word_count" INTEGER NOT NULL DEFAULT 0,
|
|
77
|
+
|
|
78
|
+
CONSTRAINT "transcripts_pkey" PRIMARY KEY ("id")
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
-- CreateTable
|
|
82
|
+
CREATE TABLE "transcript_speakers" (
|
|
83
|
+
"id" UUID NOT NULL,
|
|
84
|
+
"transcript_id" UUID NOT NULL,
|
|
85
|
+
"label" TEXT,
|
|
86
|
+
"display_name" TEXT NOT NULL,
|
|
87
|
+
"color_index" INTEGER NOT NULL,
|
|
88
|
+
"rev" INTEGER NOT NULL DEFAULT 1,
|
|
89
|
+
|
|
90
|
+
CONSTRAINT "transcript_speakers_pkey" PRIMARY KEY ("id")
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
-- CreateTable
|
|
94
|
+
CREATE TABLE "transcript_segments" (
|
|
95
|
+
"id" UUID NOT NULL,
|
|
96
|
+
"transcript_id" UUID NOT NULL,
|
|
97
|
+
"speaker_id" UUID NOT NULL,
|
|
98
|
+
"start_ms" INTEGER NOT NULL,
|
|
99
|
+
"end_ms" INTEGER NOT NULL,
|
|
100
|
+
"ordinal" DOUBLE PRECISION NOT NULL,
|
|
101
|
+
"text" TEXT NOT NULL,
|
|
102
|
+
"words" JSONB NOT NULL,
|
|
103
|
+
"words_alignment" "WordsAlignment" NOT NULL DEFAULT 'exact',
|
|
104
|
+
"confidence" DOUBLE PRECISION,
|
|
105
|
+
"origin" "SegmentOrigin" NOT NULL DEFAULT 'ai',
|
|
106
|
+
"rev" INTEGER NOT NULL DEFAULT 1,
|
|
107
|
+
"edited_by_id" UUID,
|
|
108
|
+
"edited_at" TIMESTAMPTZ,
|
|
109
|
+
|
|
110
|
+
CONSTRAINT "transcript_segments_pkey" PRIMARY KEY ("id")
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
-- CreateTable
|
|
114
|
+
CREATE TABLE "transcript_versions" (
|
|
115
|
+
"id" UUID NOT NULL,
|
|
116
|
+
"transcript_id" UUID NOT NULL,
|
|
117
|
+
"version" INTEGER NOT NULL,
|
|
118
|
+
"kind" "TranscriptVersionKind" NOT NULL,
|
|
119
|
+
"author_id" UUID,
|
|
120
|
+
"summary" TEXT,
|
|
121
|
+
"ops" JSONB NOT NULL,
|
|
122
|
+
"restored_from_version" INTEGER,
|
|
123
|
+
"snapshot_object_id" UUID,
|
|
124
|
+
"client_batch_id" TEXT,
|
|
125
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
126
|
+
|
|
127
|
+
CONSTRAINT "transcript_versions_pkey" PRIMARY KEY ("id")
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
-- CreateTable
|
|
131
|
+
CREATE TABLE "transcript_shares" (
|
|
132
|
+
"id" UUID NOT NULL,
|
|
133
|
+
"transcript_id" UUID NOT NULL,
|
|
134
|
+
"user_id" UUID NOT NULL,
|
|
135
|
+
"role" "TranscriptShareRole" NOT NULL,
|
|
136
|
+
"granted_by_id" UUID NOT NULL,
|
|
137
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
138
|
+
|
|
139
|
+
CONSTRAINT "transcript_shares_pkey" PRIMARY KEY ("id")
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
-- CreateTable
|
|
143
|
+
CREATE TABLE "transcript_exports" (
|
|
144
|
+
"id" UUID NOT NULL,
|
|
145
|
+
"transcript_id" UUID NOT NULL,
|
|
146
|
+
"version" INTEGER NOT NULL,
|
|
147
|
+
"format" TEXT NOT NULL,
|
|
148
|
+
"options" JSONB NOT NULL,
|
|
149
|
+
"options_hash" TEXT NOT NULL,
|
|
150
|
+
"status" "TranscriptExportStatus" NOT NULL DEFAULT 'pending',
|
|
151
|
+
"object_id" UUID,
|
|
152
|
+
"job_id" UUID,
|
|
153
|
+
"requested_by_id" UUID NOT NULL,
|
|
154
|
+
"error" TEXT,
|
|
155
|
+
"expires_at" TIMESTAMPTZ NOT NULL,
|
|
156
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
157
|
+
|
|
158
|
+
CONSTRAINT "transcript_exports_pkey" PRIMARY KEY ("id")
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
-- CreateIndex
|
|
162
|
+
-- "This owner's transcripts, newest first" — the transcript list view.
|
|
163
|
+
CREATE INDEX "transcripts_owner_id_updated_at_idx" ON "transcripts"("owner_id", "updated_at" DESC);
|
|
164
|
+
|
|
165
|
+
-- CreateIndex
|
|
166
|
+
-- "Every transcript in state X" — transcripts.housekeeping's scans (spec
|
|
167
|
+
-- §1.5.8) and any future admin-adjacent health check.
|
|
168
|
+
CREATE INDEX "transcripts_status_idx" ON "transcripts"("status");
|
|
169
|
+
|
|
170
|
+
-- =============================================================================
|
|
171
|
+
-- HAND-WRITTEN INDEX — INTENTIONAL SCHEMA DRIFT (issue #24, epic #19)
|
|
172
|
+
-- =============================================================================
|
|
173
|
+
-- NOT emitted by `prisma migrate dev`/`diff` and never will be: it needs a
|
|
174
|
+
-- partial-index `WHERE` clause, which the Prisma schema language has no
|
|
175
|
+
-- syntax for. See the block comment above the `Transcript` model in
|
|
176
|
+
-- prisma/schema.prisma for the same fact recorded where anyone reading the
|
|
177
|
+
-- schema without this file open will see it, and
|
|
178
|
+
-- 20260907120000_add_database_backup_runs/migration.sql's own header for the
|
|
179
|
+
-- precedent this follows to the letter.
|
|
180
|
+
--
|
|
181
|
+
-- ⚠ `prisma migrate dev` WILL WANT TO DROP THIS on the next diff. Do not
|
|
182
|
+
-- "reconcile" that away, and do not expect `prisma migrate diff` against a
|
|
183
|
+
-- live database to come back clean — this drift is deliberate and permanent
|
|
184
|
+
-- for as long as Prisma's DSL lacks partial indexes.
|
|
185
|
+
--
|
|
186
|
+
-- A provider-labelled speaker's `label` (e.g. "A") must be unique per
|
|
187
|
+
-- transcript; a user-created speaker (`speaker.create`, spec §4.1)
|
|
188
|
+
-- legitimately has none, so the constraint is scoped to labelled rows only.
|
|
189
|
+
-- =============================================================================
|
|
190
|
+
CREATE UNIQUE INDEX "transcript_speakers_transcript_id_label_key"
|
|
191
|
+
ON "transcript_speakers" ("transcript_id", "label") WHERE "label" IS NOT NULL;
|
|
192
|
+
|
|
193
|
+
-- CreateIndex
|
|
194
|
+
-- The compound order a segment list and a time-window query
|
|
195
|
+
-- (`GET /:id/words?fromMs&toMs`) both need (spec §3.3).
|
|
196
|
+
CREATE INDEX "transcript_segments_transcript_id_start_ms_ordinal_idx" ON "transcript_segments"("transcript_id", "start_ms", "ordinal");
|
|
197
|
+
|
|
198
|
+
-- CreateIndex
|
|
199
|
+
-- The version sequence itself, and what `materialize()` (spec §4.4) looks
|
|
200
|
+
-- up by. A plain UNIQUE index — Postgres needs no partial clause here.
|
|
201
|
+
CREATE UNIQUE INDEX "transcript_versions_transcript_id_version_key" ON "transcript_versions"("transcript_id", "version");
|
|
202
|
+
|
|
203
|
+
-- CreateIndex
|
|
204
|
+
-- The idempotent-retry key for a batch save (spec §5). Also a plain UNIQUE
|
|
205
|
+
-- index, deliberately NOT hand-written like the speaker label above:
|
|
206
|
+
-- PostgreSQL's standard NULLS-DISTINCT behaviour already gives exactly the
|
|
207
|
+
-- wanted semantics for this nullable column (any number of
|
|
208
|
+
-- null-`client_batch_id` versions, e.g. ingest/restore, may coexist; at most
|
|
209
|
+
-- one per transcript for any given non-null value).
|
|
210
|
+
CREATE UNIQUE INDEX "transcript_versions_transcript_id_client_batch_id_key" ON "transcript_versions"("transcript_id", "client_batch_id");
|
|
211
|
+
|
|
212
|
+
-- CreateIndex
|
|
213
|
+
-- `POST /api/transcripts/:id/shares` (spec §6.3) upserts on this pair — one
|
|
214
|
+
-- role per (transcript, user), never two competing rows.
|
|
215
|
+
CREATE UNIQUE INDEX "transcript_shares_transcript_id_user_id_key" ON "transcript_shares"("transcript_id", "user_id");
|
|
216
|
+
|
|
217
|
+
-- CreateIndex
|
|
218
|
+
-- One `transcript_exports` row per rendering job — mirrors
|
|
219
|
+
-- `database_backup_runs_job_id_key` exactly (see that model's own `jobId`
|
|
220
|
+
-- comment): a second render for the SAME job is unrepresentable.
|
|
221
|
+
CREATE UNIQUE INDEX "transcript_exports_job_id_key" ON "transcript_exports"("job_id");
|
|
222
|
+
|
|
223
|
+
-- CreateIndex
|
|
224
|
+
-- The reuse-by-content-hash lookup spec §8.5 names explicitly ("the index
|
|
225
|
+
-- issue #24 declares for exactly this lookup"). Not unique: an expired or
|
|
226
|
+
-- failed row may briefly coexist with a fresh one sharing the same key
|
|
227
|
+
-- before housekeeping removes the stale one. Named explicitly
|
|
228
|
+
-- (`map: "transcript_exports_lookup_idx"` in schema.prisma) because the
|
|
229
|
+
-- default four-column name is 64 bytes, one over PostgreSQL's 63-byte
|
|
230
|
+
-- identifier limit.
|
|
231
|
+
CREATE INDEX "transcript_exports_lookup_idx" ON "transcript_exports"("transcript_id", "version", "format", "options_hash");
|
|
232
|
+
|
|
233
|
+
-- AddForeignKey
|
|
234
|
+
-- Cascade: a transcript's only reason to exist is that exactly one user
|
|
235
|
+
-- owns it, and this application's access model has no path to it once its
|
|
236
|
+
-- owner is gone (no `transcripts:read_any`, spec §6.2). See the block
|
|
237
|
+
-- comment above the `Transcript` model for the full reasoning, including
|
|
238
|
+
-- the honestly-stated consequence for storage cleanup on a raw user delete.
|
|
239
|
+
ALTER TABLE "transcripts" ADD CONSTRAINT "transcripts_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
240
|
+
|
|
241
|
+
-- AddForeignKey
|
|
242
|
+
-- Restrict, not Cascade: a storage_objects row a transcript still
|
|
243
|
+
-- references may never be deleted out from under it by an unrelated
|
|
244
|
+
-- storage cleanup. The only path that may remove it is `transcript.purge`
|
|
245
|
+
-- deleting the referencing transcripts row first (spec §1.5.7, §10), which
|
|
246
|
+
-- Restrict permits freely.
|
|
247
|
+
ALTER TABLE "transcripts" ADD CONSTRAINT "transcripts_source_object_id_fkey" FOREIGN KEY ("source_object_id") REFERENCES "storage_objects"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
248
|
+
|
|
249
|
+
-- AddForeignKey
|
|
250
|
+
ALTER TABLE "transcripts" ADD CONSTRAINT "transcripts_playback_object_id_fkey" FOREIGN KEY ("playback_object_id") REFERENCES "storage_objects"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
251
|
+
|
|
252
|
+
-- AddForeignKey
|
|
253
|
+
ALTER TABLE "transcripts" ADD CONSTRAINT "transcripts_raw_result_object_id_fkey" FOREIGN KEY ("raw_result_object_id") REFERENCES "storage_objects"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
254
|
+
|
|
255
|
+
-- AddForeignKey
|
|
256
|
+
ALTER TABLE "transcript_speakers" ADD CONSTRAINT "transcript_speakers_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
257
|
+
|
|
258
|
+
-- AddForeignKey
|
|
259
|
+
ALTER TABLE "transcript_segments" ADD CONSTRAINT "transcript_segments_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
260
|
+
|
|
261
|
+
-- AddForeignKey
|
|
262
|
+
-- Restrict: a speaker may not be deleted while a segment still names it.
|
|
263
|
+
-- `speaker.merge` (spec §4.1) re-points every segment away first, in the
|
|
264
|
+
-- same transaction, before deleting the source speaker rows.
|
|
265
|
+
ALTER TABLE "transcript_segments" ADD CONSTRAINT "transcript_segments_speaker_id_fkey" FOREIGN KEY ("speaker_id") REFERENCES "transcript_speakers"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
266
|
+
|
|
267
|
+
-- AddForeignKey
|
|
268
|
+
-- SetNull, matching AuditEvent.actorUserId / Credential.updatedByUserId:
|
|
269
|
+
-- "who last hand-edited this line" is an audit fact, not something the
|
|
270
|
+
-- segment's own existence depends on.
|
|
271
|
+
ALTER TABLE "transcript_segments" ADD CONSTRAINT "transcript_segments_edited_by_id_fkey" FOREIGN KEY ("edited_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
272
|
+
|
|
273
|
+
-- AddForeignKey
|
|
274
|
+
ALTER TABLE "transcript_versions" ADD CONSTRAINT "transcript_versions_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
275
|
+
|
|
276
|
+
-- AddForeignKey
|
|
277
|
+
-- SetNull: a version is permanent history (spec §4.5 — nothing ever deletes
|
|
278
|
+
-- a transcript_versions row short of purging the whole transcript) and must
|
|
279
|
+
-- survive its author's own account being deleted, the same audit posture as
|
|
280
|
+
-- DatabaseBackupRun.createdById. NULL already means "the AI" for a
|
|
281
|
+
-- different reason (the ingest handler never sets an author at all) — this
|
|
282
|
+
-- FK action only ever fires for a human-authored version whose author was
|
|
283
|
+
-- later deleted.
|
|
284
|
+
ALTER TABLE "transcript_versions" ADD CONSTRAINT "transcript_versions_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
285
|
+
|
|
286
|
+
-- AddForeignKey
|
|
287
|
+
-- Restrict, matching every other storage_objects FK on this feature above.
|
|
288
|
+
ALTER TABLE "transcript_versions" ADD CONSTRAINT "transcript_versions_snapshot_object_id_fkey" FOREIGN KEY ("snapshot_object_id") REFERENCES "storage_objects"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
289
|
+
|
|
290
|
+
-- AddForeignKey
|
|
291
|
+
ALTER TABLE "transcript_shares" ADD CONSTRAINT "transcript_shares_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
292
|
+
|
|
293
|
+
-- AddForeignKey
|
|
294
|
+
-- Cascade: a share row has no meaning once its recipient is gone.
|
|
295
|
+
ALTER TABLE "transcript_shares" ADD CONSTRAINT "transcript_shares_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
296
|
+
|
|
297
|
+
-- AddForeignKey
|
|
298
|
+
-- Cascade: today the granter is always the owner, whose deletion already
|
|
299
|
+
-- cascades the transcript (and this row via transcript_id) regardless; see
|
|
300
|
+
-- the schema.prisma block comment for the full reasoning.
|
|
301
|
+
ALTER TABLE "transcript_shares" ADD CONSTRAINT "transcript_shares_granted_by_id_fkey" FOREIGN KEY ("granted_by_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
302
|
+
|
|
303
|
+
-- AddForeignKey
|
|
304
|
+
ALTER TABLE "transcript_exports" ADD CONSTRAINT "transcript_exports_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
305
|
+
|
|
306
|
+
-- AddForeignKey
|
|
307
|
+
-- Restrict, matching every other storage_objects FK on this feature above.
|
|
308
|
+
ALTER TABLE "transcript_exports" ADD CONSTRAINT "transcript_exports_object_id_fkey" FOREIGN KEY ("object_id") REFERENCES "storage_objects"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
309
|
+
|
|
310
|
+
-- AddForeignKey
|
|
311
|
+
-- SetNull, mirroring DatabaseBackupRun.jobId exactly: job.history.purge
|
|
312
|
+
-- deletes jobs rows on a retention schedule independent of this row's own
|
|
313
|
+
-- 7-day export expiry, and losing the LINK must never mean losing the
|
|
314
|
+
-- EXPORT.
|
|
315
|
+
ALTER TABLE "transcript_exports" ADD CONSTRAINT "transcript_exports_job_id_fkey" FOREIGN KEY ("job_id") REFERENCES "jobs"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
316
|
+
|
|
317
|
+
-- AddForeignKey
|
|
318
|
+
-- Cascade: unlike every SetNull audit column elsewhere in this schema, an
|
|
319
|
+
-- export is a disposable, byte-for-byte reproducible artifact with a 7-day
|
|
320
|
+
-- expiry already built in — nothing is lost by deleting a pending/ready
|
|
321
|
+
-- export row alongside the account that requested it.
|
|
322
|
+
ALTER TABLE "transcript_exports" ADD CONSTRAINT "transcript_exports_requested_by_id_fkey" FOREIGN KEY ("requested_by_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|