@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,165 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Groups: sharing groups inside an organization (PP-7.1, issue #728)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- Three org-owned tables, each with a NOT NULL org_id and a FORCEd
|
|
6
|
+
-- <table>_org_isolation policy copied from 0025_org_scoped_rls:
|
|
7
|
+
--
|
|
8
|
+
-- groups a set of users inside ONE organization that can own content
|
|
9
|
+
-- (spec decision D6: a group is never a tenant)
|
|
10
|
+
-- group_members one row per (group, user), with a GroupRole
|
|
11
|
+
-- group_invites an invitation of an e-mail address to a group
|
|
12
|
+
--
|
|
13
|
+
-- ORG CONSISTENCY. A member and an invite reach their group through the
|
|
14
|
+
-- COMPOSITE key (group_id, org_id) -> groups (id, org_id), with the supporting
|
|
15
|
+
-- UNIQUE (id, org_id) on groups: a foreign-key check bypasses row-level
|
|
16
|
+
-- security, so a plain key would let one organization store a reference to
|
|
17
|
+
-- another's group, and the composite key also guarantees that
|
|
18
|
+
-- group_members.org_id and group_invites.org_id equal groups.org_id.
|
|
19
|
+
--
|
|
20
|
+
-- RAW-SQL INDEX (intentional schema drift, listed in raw-sql-indexes.json):
|
|
21
|
+
-- group_invites_pending_uniq_idx at most one PENDING invite per (group,
|
|
22
|
+
-- email); a declined, revoked or accepted
|
|
23
|
+
-- invite does not block a new one. Prisma
|
|
24
|
+
-- cannot express a partial unique index.
|
|
25
|
+
--
|
|
26
|
+
-- No backfill: the tables are new, so the policies are enabled at once.
|
|
27
|
+
-- =============================================================================
|
|
28
|
+
|
|
29
|
+
-- CreateEnum
|
|
30
|
+
CREATE TYPE "GroupRole" AS ENUM ('admin', 'editor', 'viewer');
|
|
31
|
+
|
|
32
|
+
-- CreateTable
|
|
33
|
+
CREATE TABLE "groups" (
|
|
34
|
+
"id" UUID NOT NULL,
|
|
35
|
+
"org_id" UUID NOT NULL,
|
|
36
|
+
"name" TEXT NOT NULL,
|
|
37
|
+
"description" TEXT,
|
|
38
|
+
"metadata" JSONB,
|
|
39
|
+
"created_by_id" UUID,
|
|
40
|
+
"version" INTEGER NOT NULL DEFAULT 1,
|
|
41
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
42
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
43
|
+
|
|
44
|
+
CONSTRAINT "groups_pkey" PRIMARY KEY ("id")
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
-- CreateTable
|
|
48
|
+
CREATE TABLE "group_members" (
|
|
49
|
+
"id" UUID NOT NULL,
|
|
50
|
+
"group_id" UUID NOT NULL,
|
|
51
|
+
"user_id" UUID NOT NULL,
|
|
52
|
+
"org_id" UUID NOT NULL,
|
|
53
|
+
"role" "GroupRole" NOT NULL DEFAULT 'viewer',
|
|
54
|
+
"added_by_id" UUID,
|
|
55
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
56
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
57
|
+
|
|
58
|
+
CONSTRAINT "group_members_pkey" PRIMARY KEY ("id")
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
-- CreateTable
|
|
62
|
+
CREATE TABLE "group_invites" (
|
|
63
|
+
"id" UUID NOT NULL,
|
|
64
|
+
"group_id" UUID NOT NULL,
|
|
65
|
+
"org_id" UUID NOT NULL,
|
|
66
|
+
"email" TEXT NOT NULL,
|
|
67
|
+
"role" "GroupRole" NOT NULL DEFAULT 'viewer',
|
|
68
|
+
"invited_by_id" UUID,
|
|
69
|
+
"expires_at" TIMESTAMPTZ,
|
|
70
|
+
"accepted_at" TIMESTAMPTZ,
|
|
71
|
+
"accepted_by_id" UUID,
|
|
72
|
+
"declined_at" TIMESTAMPTZ,
|
|
73
|
+
"revoked_at" TIMESTAMPTZ,
|
|
74
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
75
|
+
|
|
76
|
+
CONSTRAINT "group_invites_pkey" PRIMARY KEY ("id")
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
-- CreateIndex
|
|
80
|
+
CREATE INDEX "groups_org_id_idx" ON "groups"("org_id");
|
|
81
|
+
|
|
82
|
+
-- CreateIndex
|
|
83
|
+
CREATE UNIQUE INDEX "groups_id_org_id_key" ON "groups"("id", "org_id");
|
|
84
|
+
|
|
85
|
+
-- CreateIndex
|
|
86
|
+
CREATE INDEX "group_members_user_id_idx" ON "group_members"("user_id");
|
|
87
|
+
|
|
88
|
+
-- CreateIndex
|
|
89
|
+
CREATE INDEX "group_members_org_id_idx" ON "group_members"("org_id");
|
|
90
|
+
|
|
91
|
+
-- CreateIndex
|
|
92
|
+
CREATE UNIQUE INDEX "group_members_group_id_user_id_key" ON "group_members"("group_id", "user_id");
|
|
93
|
+
|
|
94
|
+
-- CreateIndex
|
|
95
|
+
CREATE INDEX "group_invites_email_idx" ON "group_invites"("email");
|
|
96
|
+
|
|
97
|
+
-- CreateIndex
|
|
98
|
+
CREATE INDEX "group_invites_group_id_idx" ON "group_invites"("group_id");
|
|
99
|
+
|
|
100
|
+
-- CreateIndex
|
|
101
|
+
CREATE INDEX "group_invites_org_id_idx" ON "group_invites"("org_id");
|
|
102
|
+
|
|
103
|
+
-- AddForeignKey
|
|
104
|
+
ALTER TABLE "groups" ADD CONSTRAINT "groups_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
105
|
+
|
|
106
|
+
-- AddForeignKey
|
|
107
|
+
ALTER TABLE "groups" ADD CONSTRAINT "groups_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
108
|
+
|
|
109
|
+
-- AddForeignKey
|
|
110
|
+
ALTER TABLE "group_members" ADD CONSTRAINT "group_members_group_id_org_id_fkey" FOREIGN KEY ("group_id", "org_id") REFERENCES "groups"("id", "org_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
111
|
+
|
|
112
|
+
-- AddForeignKey
|
|
113
|
+
ALTER TABLE "group_members" ADD CONSTRAINT "group_members_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
114
|
+
|
|
115
|
+
-- AddForeignKey
|
|
116
|
+
ALTER TABLE "group_members" ADD CONSTRAINT "group_members_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
117
|
+
|
|
118
|
+
-- AddForeignKey
|
|
119
|
+
ALTER TABLE "group_members" ADD CONSTRAINT "group_members_added_by_id_fkey" FOREIGN KEY ("added_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
120
|
+
|
|
121
|
+
-- AddForeignKey
|
|
122
|
+
ALTER TABLE "group_invites" ADD CONSTRAINT "group_invites_group_id_org_id_fkey" FOREIGN KEY ("group_id", "org_id") REFERENCES "groups"("id", "org_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
123
|
+
|
|
124
|
+
-- AddForeignKey
|
|
125
|
+
ALTER TABLE "group_invites" ADD CONSTRAINT "group_invites_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
126
|
+
|
|
127
|
+
-- AddForeignKey
|
|
128
|
+
ALTER TABLE "group_invites" ADD CONSTRAINT "group_invites_invited_by_id_fkey" FOREIGN KEY ("invited_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
129
|
+
|
|
130
|
+
-- AddForeignKey
|
|
131
|
+
ALTER TABLE "group_invites" ADD CONSTRAINT "group_invites_accepted_by_id_fkey" FOREIGN KEY ("accepted_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
132
|
+
|
|
133
|
+
-- CreateIndex (partial: one pending invite per group and address)
|
|
134
|
+
CREATE UNIQUE INDEX "group_invites_pending_uniq_idx" ON "group_invites"("group_id", "email") WHERE "accepted_at" IS NULL AND "declined_at" IS NULL AND "revoked_at" IS NULL;
|
|
135
|
+
|
|
136
|
+
-- =============================================================================
|
|
137
|
+
-- Row-level security, as in 0025_org_scoped_rls. The policy names are listed in
|
|
138
|
+
-- RLS_POLICIES (rls-policies.json) and asserted against pg_policies by the
|
|
139
|
+
-- drift test. NULLIF(..., '') because current_setting(name, true) is the empty
|
|
140
|
+
-- string on a connection that ever held a transaction-local value.
|
|
141
|
+
-- =============================================================================
|
|
142
|
+
|
|
143
|
+
ALTER TABLE "groups" ENABLE ROW LEVEL SECURITY;
|
|
144
|
+
ALTER TABLE "groups" FORCE ROW LEVEL SECURITY;
|
|
145
|
+
CREATE POLICY "groups_org_isolation" ON "groups"
|
|
146
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
147
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
148
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
149
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
150
|
+
|
|
151
|
+
ALTER TABLE "group_members" ENABLE ROW LEVEL SECURITY;
|
|
152
|
+
ALTER TABLE "group_members" FORCE ROW LEVEL SECURITY;
|
|
153
|
+
CREATE POLICY "group_members_org_isolation" ON "group_members"
|
|
154
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
155
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
156
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
157
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
158
|
+
|
|
159
|
+
ALTER TABLE "group_invites" ENABLE ROW LEVEL SECURITY;
|
|
160
|
+
ALTER TABLE "group_invites" FORCE ROW LEVEL SECURITY;
|
|
161
|
+
CREATE POLICY "group_invites_org_isolation" ON "group_invites"
|
|
162
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
163
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
164
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
165
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Grants: share one record with a user, a group or a link (PP-7.2, issue #729)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- One org-owned table, `grants`, with a NOT NULL org_id and a FORCEd
|
|
6
|
+
-- grants_org_isolation policy copied from 0025_org_scoped_rls.
|
|
7
|
+
--
|
|
8
|
+
-- POLYMORPHIC RESOURCE. (resource_type, resource_id) names a row of an app
|
|
9
|
+
-- table the platform cannot know, so there is no foreign key to it. Integrity
|
|
10
|
+
-- comes from GrantsService.deleteForResources() (inside the app's delete
|
|
11
|
+
-- transaction) and the sharing.grants.prune job.
|
|
12
|
+
--
|
|
13
|
+
-- ORG CONSISTENCY. A group grantee reaches its group through the COMPOSITE key
|
|
14
|
+
-- (grantee_group_id, org_id) -> groups (id, org_id): a foreign-key check
|
|
15
|
+
-- bypasses row-level security, so a plain key would let a grant name another
|
|
16
|
+
-- organization's group. A user is not org-scoped; the API checks that the
|
|
17
|
+
-- grantee is an active member of the resource's organization.
|
|
18
|
+
--
|
|
19
|
+
-- The link columns (link_token_hash, link_token_ciphertext, link_label) are
|
|
20
|
+
-- created now so #730 needs no migration.
|
|
21
|
+
--
|
|
22
|
+
-- RAW SQL (intentional schema drift: Prisma can express neither):
|
|
23
|
+
-- grants_active_user_uniq_idx at most one ACTIVE (unrevoked) grant per
|
|
24
|
+
-- (resource, user): the API upserts on it
|
|
25
|
+
-- grants_active_group_uniq_idx the same per (resource, group)
|
|
26
|
+
-- grants_grantee_consistency_check the grantee columns match grantee_kind
|
|
27
|
+
-- The two indexes are listed in raw-sql-indexes.json.
|
|
28
|
+
--
|
|
29
|
+
-- No backfill: the table is new, so the policy is enabled at once.
|
|
30
|
+
-- =============================================================================
|
|
31
|
+
|
|
32
|
+
-- CreateEnum
|
|
33
|
+
CREATE TYPE "GrantGranteeKind" AS ENUM ('user', 'group', 'link');
|
|
34
|
+
|
|
35
|
+
-- CreateTable
|
|
36
|
+
CREATE TABLE "grants" (
|
|
37
|
+
"id" UUID NOT NULL,
|
|
38
|
+
"org_id" UUID NOT NULL,
|
|
39
|
+
"resource_type" TEXT NOT NULL,
|
|
40
|
+
"resource_id" UUID NOT NULL,
|
|
41
|
+
"grantee_kind" "GrantGranteeKind" NOT NULL,
|
|
42
|
+
"grantee_user_id" UUID,
|
|
43
|
+
"grantee_group_id" UUID,
|
|
44
|
+
"role" TEXT NOT NULL,
|
|
45
|
+
"link_token_hash" TEXT,
|
|
46
|
+
"link_token_ciphertext" TEXT,
|
|
47
|
+
"link_label" TEXT,
|
|
48
|
+
"expires_at" TIMESTAMPTZ,
|
|
49
|
+
"revoked_at" TIMESTAMPTZ,
|
|
50
|
+
"revoked_by_id" UUID,
|
|
51
|
+
"granted_by_id" UUID,
|
|
52
|
+
"metadata" JSONB,
|
|
53
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
54
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
55
|
+
|
|
56
|
+
CONSTRAINT "grants_pkey" PRIMARY KEY ("id")
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- CreateIndex
|
|
60
|
+
CREATE UNIQUE INDEX "grants_link_token_hash_key" ON "grants"("link_token_hash");
|
|
61
|
+
|
|
62
|
+
-- CreateIndex
|
|
63
|
+
CREATE INDEX "grants_resource_type_resource_id_idx" ON "grants"("resource_type", "resource_id");
|
|
64
|
+
|
|
65
|
+
-- CreateIndex
|
|
66
|
+
CREATE INDEX "grants_grantee_user_id_idx" ON "grants"("grantee_user_id");
|
|
67
|
+
|
|
68
|
+
-- CreateIndex
|
|
69
|
+
CREATE INDEX "grants_grantee_group_id_idx" ON "grants"("grantee_group_id");
|
|
70
|
+
|
|
71
|
+
-- CreateIndex
|
|
72
|
+
CREATE INDEX "grants_org_id_idx" ON "grants"("org_id");
|
|
73
|
+
|
|
74
|
+
-- AddForeignKey
|
|
75
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
76
|
+
|
|
77
|
+
-- AddForeignKey
|
|
78
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_grantee_user_id_fkey" FOREIGN KEY ("grantee_user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
79
|
+
|
|
80
|
+
-- AddForeignKey
|
|
81
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_grantee_group_id_org_id_fkey" FOREIGN KEY ("grantee_group_id", "org_id") REFERENCES "groups"("id", "org_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
82
|
+
|
|
83
|
+
-- AddForeignKey
|
|
84
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_revoked_by_id_fkey" FOREIGN KEY ("revoked_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
85
|
+
|
|
86
|
+
-- AddForeignKey
|
|
87
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_granted_by_id_fkey" FOREIGN KEY ("granted_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
88
|
+
|
|
89
|
+
-- CreateIndex (partial: one active grant per resource and user)
|
|
90
|
+
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;
|
|
91
|
+
|
|
92
|
+
-- CreateIndex (partial: one active grant per resource and group)
|
|
93
|
+
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;
|
|
94
|
+
|
|
95
|
+
-- AddCheckConstraint (the grantee columns match the grantee kind)
|
|
96
|
+
ALTER TABLE "grants" ADD CONSTRAINT "grants_grantee_consistency_check" CHECK (
|
|
97
|
+
("grantee_kind" = 'user' AND "grantee_user_id" IS NOT NULL AND "grantee_group_id" IS NULL AND "link_token_hash" IS NULL)
|
|
98
|
+
OR
|
|
99
|
+
("grantee_kind" = 'group' AND "grantee_user_id" IS NULL AND "grantee_group_id" IS NOT NULL AND "link_token_hash" IS NULL)
|
|
100
|
+
OR
|
|
101
|
+
("grantee_kind" = 'link' AND "grantee_user_id" IS NULL AND "grantee_group_id" IS NULL AND "link_token_hash" IS NOT NULL)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
-- =============================================================================
|
|
105
|
+
-- Row-level security, as in 0025_org_scoped_rls. The policy name is listed in
|
|
106
|
+
-- RLS_POLICIES (rls-policies.json) and asserted against pg_policies by the
|
|
107
|
+
-- drift test. NULLIF(..., '') because current_setting(name, true) is the empty
|
|
108
|
+
-- string on a connection that ever held a transaction-local value.
|
|
109
|
+
-- =============================================================================
|
|
110
|
+
|
|
111
|
+
ALTER TABLE "grants" ENABLE ROW LEVEL SECURITY;
|
|
112
|
+
ALTER TABLE "grants" FORCE ROW LEVEL SECURITY;
|
|
113
|
+
CREATE POLICY "grants_org_isolation" ON "grants"
|
|
114
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
115
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
116
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
117
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Organization settings: one organization's overrides (PP-8.1, issue #733)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- One org-owned table, `org_settings`: one row per organization, holding only
|
|
6
|
+
-- the org-overridable fields of each system settings namespace that declares
|
|
7
|
+
-- an `org` block ({ "<namespace>": { "<field>": value } }), with its own
|
|
8
|
+
-- version for If-Match. NOT NULL org_id, ENABLE and FORCE ROW LEVEL SECURITY
|
|
9
|
+
-- and an org_settings_org_isolation policy copied from 0025_org_scoped_rls:
|
|
10
|
+
-- organization A's transaction never reads or writes organization B's row.
|
|
11
|
+
-- system_settings (deployment-level) and user_settings (user-owned) are
|
|
12
|
+
-- unchanged.
|
|
13
|
+
-- =============================================================================
|
|
14
|
+
|
|
15
|
+
-- CreateTable
|
|
16
|
+
CREATE TABLE "org_settings" (
|
|
17
|
+
"id" UUID NOT NULL,
|
|
18
|
+
"org_id" UUID NOT NULL,
|
|
19
|
+
"value" JSONB NOT NULL,
|
|
20
|
+
"version" INTEGER NOT NULL DEFAULT 1,
|
|
21
|
+
"updated_by_user_id" UUID,
|
|
22
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
23
|
+
|
|
24
|
+
CONSTRAINT "org_settings_pkey" PRIMARY KEY ("id")
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
-- CreateIndex
|
|
28
|
+
CREATE UNIQUE INDEX "org_settings_org_id_key" ON "org_settings"("org_id");
|
|
29
|
+
|
|
30
|
+
-- AddForeignKey
|
|
31
|
+
ALTER TABLE "org_settings" ADD CONSTRAINT "org_settings_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
32
|
+
|
|
33
|
+
-- AddForeignKey
|
|
34
|
+
ALTER TABLE "org_settings" ADD CONSTRAINT "org_settings_updated_by_user_id_fkey" FOREIGN KEY ("updated_by_user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
35
|
+
|
|
36
|
+
-- =============================================================================
|
|
37
|
+
-- Row-level security, as in 0025_org_scoped_rls. The policy name is listed in
|
|
38
|
+
-- RLS_POLICIES (rls-policies.json) and asserted against pg_policies by the
|
|
39
|
+
-- drift test. NULLIF(..., '') because current_setting(name, true) is the empty
|
|
40
|
+
-- string on a connection that ever held a transaction-local value.
|
|
41
|
+
-- =============================================================================
|
|
42
|
+
|
|
43
|
+
ALTER TABLE "org_settings" ENABLE ROW LEVEL SECURITY;
|
|
44
|
+
ALTER TABLE "org_settings" FORCE ROW LEVEL SECURITY;
|
|
45
|
+
CREATE POLICY "org_settings_org_isolation" ON "org_settings"
|
|
46
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
47
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
48
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
49
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Organization credentials: the org tier of the credential store (PP-8.8, #735)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- One org-owned table, mirroring user_credentials with an organization as the
|
|
6
|
+
-- owner: org_credentials, addressed by (org_id, purpose, name), each secret
|
|
7
|
+
-- encrypted under the org-bound sub-key domain org:<orgId>:<purpose>.
|
|
8
|
+
--
|
|
9
|
+
-- A plain composite UNIQUE suffices (all three columns are NOT NULL), so no
|
|
10
|
+
-- raw-SQL index. The table is tenant data with a NOT NULL org_id and a FORCEd
|
|
11
|
+
-- org_credentials_org_isolation policy copied from 0025_org_scoped_rls.
|
|
12
|
+
--
|
|
13
|
+
-- No backfill: the table is new, so the policy is enabled at once.
|
|
14
|
+
-- =============================================================================
|
|
15
|
+
|
|
16
|
+
-- CreateTable
|
|
17
|
+
CREATE TABLE "org_credentials" (
|
|
18
|
+
"id" UUID NOT NULL,
|
|
19
|
+
"org_id" UUID NOT NULL,
|
|
20
|
+
"purpose" TEXT NOT NULL,
|
|
21
|
+
"name" TEXT NOT NULL,
|
|
22
|
+
"secret" TEXT NOT NULL,
|
|
23
|
+
"hint" TEXT,
|
|
24
|
+
"label" TEXT,
|
|
25
|
+
"updated_by_user_id" UUID,
|
|
26
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
27
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
28
|
+
|
|
29
|
+
CONSTRAINT "org_credentials_pkey" PRIMARY KEY ("id")
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
-- CreateIndex
|
|
33
|
+
CREATE UNIQUE INDEX "org_credentials_org_id_purpose_name_key" ON "org_credentials"("org_id", "purpose", "name");
|
|
34
|
+
|
|
35
|
+
-- AddForeignKey
|
|
36
|
+
ALTER TABLE "org_credentials" ADD CONSTRAINT "org_credentials_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
37
|
+
|
|
38
|
+
-- AddForeignKey
|
|
39
|
+
ALTER TABLE "org_credentials" ADD CONSTRAINT "org_credentials_updated_by_user_id_fkey" FOREIGN KEY ("updated_by_user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
40
|
+
|
|
41
|
+
-- =============================================================================
|
|
42
|
+
-- Row-level security, as in 0025_org_scoped_rls. The policy name is listed in
|
|
43
|
+
-- RLS_POLICIES (rls-policies.json) and asserted against pg_policies by the
|
|
44
|
+
-- drift test. NULLIF(..., '') because current_setting(name, true) is the empty
|
|
45
|
+
-- string on a connection that ever held a transaction-local value.
|
|
46
|
+
-- =============================================================================
|
|
47
|
+
|
|
48
|
+
ALTER TABLE "org_credentials" ENABLE ROW LEVEL SECURITY;
|
|
49
|
+
ALTER TABLE "org_credentials" FORCE ROW LEVEL SECURITY;
|
|
50
|
+
CREATE POLICY "org_credentials_org_isolation" ON "org_credentials"
|
|
51
|
+
USING ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
52
|
+
OR current_setting('app.rls_bypass', true) = 'on')
|
|
53
|
+
WITH CHECK ("org_id" = NULLIF(current_setting('app.org_id', true), '')::uuid
|
|
54
|
+
OR current_setting('app.rls_bypass', true) = 'on');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Jobs carry the organization they belong to (issue #734, PP-8.2).
|
|
2
|
+
--
|
|
3
|
+
-- Nullable with no default: a metadata-only ADD COLUMN, no table rewrite.
|
|
4
|
+
-- NULL is a deployment-wide (system) job, and every row written before this
|
|
5
|
+
-- migration is one. No row-level security on `jobs` (the claim is one
|
|
6
|
+
-- cross-organization statement); see the `Job.orgId` comment in the jobs
|
|
7
|
+
-- fragment. The `(org_id, status)` index is built CONCURRENTLY in the next
|
|
8
|
+
-- migration, on its own, because `jobs` is a big table.
|
|
9
|
+
|
|
10
|
+
-- AlterTable
|
|
11
|
+
ALTER TABLE "jobs" ADD COLUMN "org_id" UUID;
|
|
12
|
+
|
|
13
|
+
-- AddForeignKey
|
|
14
|
+
-- NOT VALID then VALIDATE: the add takes its lock without scanning `jobs`,
|
|
15
|
+
-- and the validation scan runs under a lock that does not block writes.
|
|
16
|
+
-- ON DELETE SET NULL keeps an organization's job history when it is deleted.
|
|
17
|
+
ALTER TABLE "jobs" ADD CONSTRAINT "jobs_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "organizations"("id") ON DELETE SET NULL ON UPDATE CASCADE NOT VALID;
|
|
18
|
+
ALTER TABLE "jobs" VALIDATE CONSTRAINT "jobs_org_id_fkey";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- "This organization's jobs by status" (issue #734, PP-8.2): the admin job
|
|
2
|
+
-- list's orgId filter and offboarding's cancel of an organization's pending
|
|
3
|
+
-- jobs. CONCURRENTLY, so building it never blocks the queue's writes, and
|
|
4
|
+
-- therefore the only statement in this migration (it cannot run inside a
|
|
5
|
+
-- transaction, and Prisma runs a single such statement outside one).
|
|
6
|
+
CREATE INDEX CONCURRENTLY IF NOT EXISTS "jobs_org_id_status_idx" ON "jobs"("org_id", "status");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Broadcasts can target one organization (issue #738, PP-8.5).
|
|
2
|
+
--
|
|
3
|
+
-- Nullable with no default: a metadata-only ADD COLUMN. NULL is a system
|
|
4
|
+
-- broadcast (every active user of the deployment), and every row written
|
|
5
|
+
-- before this migration is one. No row-level security on
|
|
6
|
+
-- `notification_broadcasts`: a system broadcast belongs to no organization and
|
|
7
|
+
-- the delivering job must read it; the API authorizes `target_org_id` instead.
|
|
8
|
+
-- ON DELETE CASCADE: an organization's broadcasts have no audience once it is
|
|
9
|
+
-- deleted.
|
|
10
|
+
|
|
11
|
+
-- AlterTable
|
|
12
|
+
ALTER TABLE "notification_broadcasts" ADD COLUMN "target_org_id" UUID;
|
|
13
|
+
|
|
14
|
+
-- CreateIndex
|
|
15
|
+
CREATE INDEX "notification_broadcasts_target_org_id_idx" ON "notification_broadcasts"("target_org_id");
|
|
16
|
+
|
|
17
|
+
-- AddForeignKey
|
|
18
|
+
-- NOT VALID then VALIDATE, as for `jobs.org_id`: the add takes its lock
|
|
19
|
+
-- without scanning the table, and the validation scan does not block writes.
|
|
20
|
+
ALTER TABLE "notification_broadcasts" ADD CONSTRAINT "notification_broadcasts_target_org_id_fkey" FOREIGN KEY ("target_org_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE NOT VALID;
|
|
21
|
+
ALTER TABLE "notification_broadcasts" VALIDATE CONSTRAINT "notification_broadcasts_target_org_id_fkey";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- The Android companion slice (#746, PP-9.4; merged from EvoPath and
|
|
2
|
+
-- MemoriaHub). Expand-only: one new table and one defaulted column.
|
|
3
|
+
|
|
4
|
+
-- CreateTable
|
|
5
|
+
CREATE TABLE "android_app_releases" (
|
|
6
|
+
"id" UUID NOT NULL,
|
|
7
|
+
"package_name" TEXT NOT NULL,
|
|
8
|
+
"version_name" VARCHAR(50) NOT NULL,
|
|
9
|
+
"version_code" INTEGER NOT NULL,
|
|
10
|
+
"signing_sha256" TEXT NOT NULL,
|
|
11
|
+
"file_sha256" CHAR(64) NOT NULL,
|
|
12
|
+
"size_bytes" BIGINT NOT NULL,
|
|
13
|
+
"storage_key" TEXT NOT NULL,
|
|
14
|
+
"storage_provider" TEXT,
|
|
15
|
+
"bucket" TEXT,
|
|
16
|
+
"notes" VARCHAR(2000),
|
|
17
|
+
"is_current" BOOLEAN NOT NULL DEFAULT false,
|
|
18
|
+
"uploaded_by_id" UUID,
|
|
19
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
20
|
+
|
|
21
|
+
CONSTRAINT "android_app_releases_pkey" PRIMARY KEY ("id")
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
-- CreateIndex
|
|
25
|
+
CREATE INDEX "android_app_releases_created_at_idx" ON "android_app_releases"("created_at");
|
|
26
|
+
|
|
27
|
+
-- CreateIndex
|
|
28
|
+
CREATE INDEX "android_app_releases_uploaded_by_id_idx" ON "android_app_releases"("uploaded_by_id");
|
|
29
|
+
|
|
30
|
+
-- CreateIndex
|
|
31
|
+
CREATE UNIQUE INDEX "android_app_releases_package_name_version_code_key" ON "android_app_releases"("package_name", "version_code");
|
|
32
|
+
|
|
33
|
+
-- AddForeignKey
|
|
34
|
+
ALTER TABLE "android_app_releases" ADD CONSTRAINT "android_app_releases_uploaded_by_id_fkey" FOREIGN KEY ("uploaded_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
35
|
+
|
|
36
|
+
-- =============================================================================
|
|
37
|
+
-- Raw-SQL constraints (intentional schema drift: Prisma cannot express these).
|
|
38
|
+
-- Never declare android_app_releases_one_current_uniq_idx as @@unique and never
|
|
39
|
+
-- replace it with a findFirst pre-check; make-current clears the old flag and
|
|
40
|
+
-- sets the new one in one transaction, and the database rejects a second
|
|
41
|
+
-- current row (P2002, mapped to 409 RELEASE_CURRENT_CONFLICT).
|
|
42
|
+
-- =============================================================================
|
|
43
|
+
|
|
44
|
+
-- At most one current release deployment-wide.
|
|
45
|
+
CREATE UNIQUE INDEX "android_app_releases_one_current_uniq_idx" ON "android_app_releases" ((true)) WHERE "is_current";
|
|
46
|
+
|
|
47
|
+
-- Push subscription platform: tags each Web Push subscription with the surface
|
|
48
|
+
-- that registered it, so the `android_app` notification channel can target the
|
|
49
|
+
-- Android companion alone. Existing rows are browser subscriptions. A constant
|
|
50
|
+
-- default makes this a metadata-only ADD COLUMN (no table rewrite).
|
|
51
|
+
|
|
52
|
+
-- AlterTable
|
|
53
|
+
ALTER TABLE "push_subscriptions" ADD COLUMN "platform" TEXT NOT NULL DEFAULT 'browser';
|
|
54
|
+
|
|
55
|
+
-- Prisma cannot express a CHECK constraint, so it lives here only (intentional
|
|
56
|
+
-- schema drift, like the raw-SQL partial unique indexes). The contract's
|
|
57
|
+
-- PUSH_SUBSCRIPTION_PLATFORMS mirrors it.
|
|
58
|
+
ALTER TABLE "push_subscriptions"
|
|
59
|
+
ADD CONSTRAINT "push_subscriptions_platform_check"
|
|
60
|
+
CHECK ("platform" IN ('browser', 'android_app'));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- Open the job-reason vocabulary: "jobs"."reason" goes from the closed
|
|
2
|
+
-- "JobReason" enum ('upload', 'rerun', 'backfill') to plain TEXT, so an app can
|
|
3
|
+
-- register its own reasons (`registerJobReason`) at zero migrations. Every
|
|
4
|
+
-- stored value is kept as it is: the cast is the enum's own label.
|
|
5
|
+
--
|
|
6
|
+
-- No CHECK constraint on purpose: a row must outlive the reason that wrote it,
|
|
7
|
+
-- and the allowed shape is the contract's `jobReasonSchema` pattern at the API
|
|
8
|
+
-- edge. "jobs" has no row-level security, so no bypass is needed here.
|
|
9
|
+
--
|
|
10
|
+
-- The column type changes in place (a table rewrite, taken under an ACCESS
|
|
11
|
+
-- EXCLUSIVE lock for its duration); no index covers "reason", so nothing is
|
|
12
|
+
-- rebuilt besides the heap. The enum type is dropped last: nothing else uses it.
|
|
13
|
+
ALTER TABLE "jobs" ALTER COLUMN "reason" TYPE TEXT USING "reason"::text;
|
|
14
|
+
|
|
15
|
+
-- DropEnum
|
|
16
|
+
DROP TYPE "JobReason";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Per-feature AI usage (PP-14.17, #935)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- Persist the registered AI feature (`registerAiFeature`) a call was made for,
|
|
6
|
+
-- so usage can be filtered and grouped per feature from the database:
|
|
7
|
+
--
|
|
8
|
+
-- ai_runs.feature the feature a background run was started for
|
|
9
|
+
-- ai_usage_events.feature the feature a provider round trip was made for
|
|
10
|
+
--
|
|
11
|
+
-- Both columns are nullable plain TEXT: every row written before this
|
|
12
|
+
-- migration, a call made without a feature, and a catalogue sync have none.
|
|
13
|
+
-- No backfill, no default, no foreign key (a feature is code, not data, and a
|
|
14
|
+
-- row must outlive the feature that wrote it).
|
|
15
|
+
--
|
|
16
|
+
-- ai_runs and ai_usage_events are organization tables under forced row-level
|
|
17
|
+
-- security, so the migration runs with the bypass on for its transaction
|
|
18
|
+
-- (set_config with is_local = true: transaction-local, never session-level).
|
|
19
|
+
-- Adding a nullable column rewrites nothing; the index is built under the
|
|
20
|
+
-- table's SHARE lock, which blocks writes to ai_usage_events for the length of
|
|
21
|
+
-- the build (the table holds one row per provider round trip, an append-only
|
|
22
|
+
-- ledger a retention purge keeps bounded).
|
|
23
|
+
-- =============================================================================
|
|
24
|
+
|
|
25
|
+
BEGIN;
|
|
26
|
+
SELECT set_config('app.rls_bypass', 'on', true);
|
|
27
|
+
|
|
28
|
+
-- AlterTable
|
|
29
|
+
ALTER TABLE "ai_runs" ADD COLUMN "feature" TEXT;
|
|
30
|
+
|
|
31
|
+
-- AlterTable
|
|
32
|
+
ALTER TABLE "ai_usage_events" ADD COLUMN "feature" TEXT;
|
|
33
|
+
|
|
34
|
+
-- CreateIndex
|
|
35
|
+
CREATE INDEX "ai_usage_events_org_id_feature_created_at_idx" ON "ai_usage_events"("org_id", "feature", "created_at");
|
|
36
|
+
|
|
37
|
+
COMMIT;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- App metadata on users and organizations; composite-key targets (PP-14.27, #945)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
--
|
|
5
|
+
-- users.metadata and organizations.metadata are JSONB documents an app fills
|
|
6
|
+
-- with namespaced fields of its own (registerUserMetadataSchema,
|
|
7
|
+
-- registerOrganizationMetadataSchema): one top-level key per registered
|
|
8
|
+
-- namespace, validated against that namespace's zod schema on write. They are
|
|
9
|
+
-- not a secret store; a secret-named field is refused at registration.
|
|
10
|
+
--
|
|
11
|
+
-- NOT NULL DEFAULT '{}': every existing row gets an empty document; no backfill
|
|
12
|
+
-- and no rewrite (a constant default is stored in the catalog, PostgreSQL 11+).
|
|
13
|
+
--
|
|
14
|
+
-- The size CHECK is a backstop, not the contract. The writer enforces 16 KiB of
|
|
15
|
+
-- compact JSON per row; the constraint allows 32 KiB of jsonb text, because the
|
|
16
|
+
-- text form of a jsonb value carries a space after every colon and comma, so
|
|
17
|
+
-- the two measures differ by a few percent. A constraint that matched the
|
|
18
|
+
-- writer's limit exactly would reject a document the writer accepted.
|
|
19
|
+
--
|
|
20
|
+
-- ai_runs and grants get a unique index on (id, org_id): the target of a
|
|
21
|
+
-- composite foreign key (grant_id, org_id) from an organization-owned table an
|
|
22
|
+
-- app adds, exactly as groups and storage_objects already are. A plain key on
|
|
23
|
+
-- id alone would let a row of one organization point at another's, since a
|
|
24
|
+
-- foreign-key check bypasses row-level security. No existing key changes.
|
|
25
|
+
--
|
|
26
|
+
-- ai_runs and grants are organization tables under forced row-level security,
|
|
27
|
+
-- so the migration runs with the bypass on for its transaction (set_config with
|
|
28
|
+
-- is_local = true: transaction-local, never session-level). users and
|
|
29
|
+
-- organizations have no row-level security.
|
|
30
|
+
-- =============================================================================
|
|
31
|
+
|
|
32
|
+
BEGIN;
|
|
33
|
+
SELECT set_config('app.rls_bypass', 'on', true);
|
|
34
|
+
|
|
35
|
+
-- AlterTable
|
|
36
|
+
ALTER TABLE "users" ADD COLUMN "metadata" JSONB NOT NULL DEFAULT '{}';
|
|
37
|
+
ALTER TABLE "users" ADD CONSTRAINT "users_metadata_size_check" CHECK (jsonb_typeof("metadata") = 'object' AND octet_length("metadata"::text) <= 32768);
|
|
38
|
+
|
|
39
|
+
-- AlterTable
|
|
40
|
+
ALTER TABLE "organizations" ADD COLUMN "metadata" JSONB NOT NULL DEFAULT '{}';
|
|
41
|
+
ALTER TABLE "organizations" ADD CONSTRAINT "organizations_metadata_size_check" CHECK (jsonb_typeof("metadata") = 'object' AND octet_length("metadata"::text) <= 32768);
|
|
42
|
+
|
|
43
|
+
-- CreateIndex
|
|
44
|
+
CREATE UNIQUE INDEX "ai_runs_id_org_id_key" ON "ai_runs"("id", "org_id");
|
|
45
|
+
|
|
46
|
+
-- CreateIndex
|
|
47
|
+
CREATE UNIQUE INDEX "grants_id_org_id_key" ON "grants"("id", "org_id");
|
|
48
|
+
|
|
49
|
+
COMMIT;
|