@taodigital/database 0.0.0-stage → 1.2.1
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/README.md +21 -2
- package/dist/index.d.ts +58 -0
- package/dist/index.js +209 -0
- package/package.json +29 -4
- package/prisma/migrations/0000_init/migration.sql +220 -0
- package/prisma/migrations/0001_tenant_isolation/migration.sql +43 -0
- package/prisma/migrations/0002_app_runtime_role/migration.sql +14 -0
- package/prisma/migrations/0003_skill_taxonomy/migration.sql +30 -0
- package/prisma/migrations/0004_extended_models/migration.sql +215 -0
- package/prisma/migrations/0005_enhanced_test_artifacts/migration.sql +24 -0
- package/prisma/migrations/0006_tenant_settings/migration.sql +28 -0
- package/prisma/migrations/0007_project_slug/migration.sql +11 -0
- package/prisma/migrations/0008_project_crawl_config/migration.sql +3 -0
- package/prisma/migrations/0009_tenant_slug/migration.sql +11 -0
- package/prisma/migrations/0010_user_password/migration.sql +3 -0
- package/prisma/migrations/0011_oauth_connections/migration.sql +78 -0
- package/prisma/migrations/0012_agent_webhooks/migration.sql +46 -0
- package/prisma/migrations/0013_project_artifacts/migration.sql +27 -0
- package/prisma/migrations/0014_knowledge_chunks/migration.sql +37 -0
- package/prisma/migrations/20260626022056_platform_job_migration/migration.sql +44 -0
- package/prisma/migrations/20260626053339_kag_schema_update/migration.sql +27 -0
- package/prisma/migrations/20260626053340_restore_bm25_index/migration.sql +13 -0
- package/prisma/migrations/20260626063704_token_optimisation/migration.sql +86 -0
- package/prisma/migrations/20260626080000_job_name/migration.sql +2 -0
- package/prisma/migrations/20260626090000_rls_missing_tables/migration.sql +39 -0
- package/prisma/migrations/20260626100000_token_budget/migration.sql +21 -0
- package/prisma/migrations/20260626110000_screen_groups/migration.sql +42 -0
- package/prisma/migrations/20260626120000_artifact_intelligence/migration.sql +5 -0
- package/prisma/migrations/20260626130000_notifications/migration.sql +34 -0
- package/prisma/migrations/20260627100000_element_viewport/migration.sql +2 -0
- package/prisma/migrations/20260627100000_screenshot_cloud_url/migration.sql +2 -0
- package/prisma/migrations/20260627110000_screenshot_index/migration.sql +2 -0
- package/prisma/migrations/20260627140000_artifact_storage_key/migration.sql +3 -0
- package/prisma/migrations/20260627150000_screen_lifecycle/migration.sql +5 -0
- package/prisma/migrations/20260627160000_native_app_support/migration.sql +41 -0
- package/prisma/migrations/20260627200000_rls_missing_tables/migration.sql +57 -0
- package/prisma/migrations/20260627210000_llmcalllog_tasktype/migration.sql +1 -0
- package/prisma/migrations/20260628100000_element_enrichment/migration.sql +7 -0
- package/prisma/migrations/20260628110000_element_hash/migration.sql +6 -0
- package/prisma/migrations/20260628120000_screen_diff/migration.sql +20 -0
- package/prisma/migrations/20260628130000_probe_observations/migration.sql +19 -0
- package/prisma/migrations/20260629100000_visual_baseline_masking/migration.sql +1 -0
- package/prisma/migrations/20260629110000_testcase_viewports/migration.sql +1 -0
- package/prisma/migrations/20260630100000_visual_baseline_element_snapshot/migration.sql +1 -0
- package/prisma/migrations/20260630110000_git_branched_baselines/migration.sql +11 -0
- package/prisma/migrations/20260630120000_testcase_viewport_constraint/migration.sql +1 -0
- package/prisma/migrations/20260630130000_test_case_runs/migration.sql +22 -0
- package/prisma/migrations/20260630140000_perf_env_comments/migration.sql +68 -0
- package/prisma/migrations/20260630150000_testcase_gen_at/migration.sql +2 -0
- package/prisma/migrations/20260630160000_rls_catchup_late_tables/migration.sql +41 -0
- package/prisma/migrations/20260701100000_skill_file_diff_approval/migration.sql +9 -0
- package/prisma/migrations/20260701200000_workspace_connector/migration.sql +20 -0
- package/prisma/migrations/20260701220000_screen_a11y_security/migration.sql +2 -0
- package/prisma/migrations/20260702100000_ci_threshold_root_cause/migration.sql +2 -0
- package/prisma/migrations/20260702120000_medium_priority_gaps/migration.sql +28 -0
- package/prisma/migrations/20260702140000_testcase_v2_technique/migration.sql +7 -0
- package/prisma/migrations/20260702150000_add_app_field/migration.sql +40 -0
- package/prisma/migrations/20260702160000_add_requirement_model/migration.sql +62 -0
- package/prisma/migrations/20260702180000_add_invitation_model/migration.sql +53 -0
- package/prisma/migrations/20260702190000_suite_hierarchy_artifact_trace/migration.sql +28 -0
- package/prisma/migrations/20260702200000_project_member_access/migration.sql +31 -0
- package/prisma/migrations/20260703000000_add_system_config/migration.sql +11 -0
- package/prisma/migrations/20260703000000_custom_roles/migration.sql +29 -0
- package/prisma/migrations/20260703100000_platform_admin/migration.sql +11 -0
- package/prisma/migrations/20260703110000_add_extension_models/migration.sql +106 -0
- package/prisma/migrations/20260703120000_project_restricted_column/migration.sql +1 -0
- package/prisma/migrations/20260703200000_system_config_category_index/migration.sql +1 -0
- package/prisma/migrations/20260703210000_workspace_layer/migration.sql +24 -0
- package/prisma/migrations/20260703230000_workspace_agent_tokens/migration.sql +2 -0
- package/prisma/migrations/20260704000000_requirement_rls_policy/migration.sql +35 -0
- package/prisma/migrations/20260704100000_fix_oauth_auditlog_cascade/migration.sql +9 -0
- package/prisma/migrations/20260704110000_skillfile_approval_status/migration.sql +2 -0
- package/prisma/migrations/20260704120000_scenario_suspect_workspace/migration.sql +35 -0
- package/prisma/migrations/20260704130000_testcase_traceto_suspect_indexes/migration.sql +5 -0
- package/prisma/migrations/20260704140000_workspace_rls/migration.sql +19 -0
- package/prisma/migrations/20260704150000_project_cascade_deletes/migration.sql +125 -0
- package/prisma/migrations/20260705100000_platform_job_worker_id/migration.sql +12 -0
- package/prisma/migrations/20260705110000_screen_discovery_method/migration.sql +7 -0
- package/prisma/migrations/20260705120000_webhook_delivery/migration.sql +32 -0
- package/prisma/migrations/20260705130000_tenant_feature_flags/migration.sql +23 -0
- package/prisma/migrations/20260705140000_auth_sessions/migration.sql +30 -0
- package/prisma/migrations/20260705150000_fix_rls_wrong_session_var/migration.sql +51 -0
- package/prisma/migrations/20260705160000_testcase_flaky_quarantine/migration.sql +14 -0
- package/prisma/migrations/20260705170000_testcaserun_browser/migration.sql +6 -0
- package/prisma/migrations/20260705180000_allow_custom_roles/migration.sql +22 -0
- package/prisma/migrations/20260706050000_screen_markdown_extraction/migration.sql +8 -0
- package/prisma/migrations/20260706090000_add_lighthouse_to_performance_snapshot/migration.sql +4 -0
- package/prisma/migrations/20260706100000_add_lighthouse_bp_and_job_index/migration.sql +5 -0
- package/prisma/migrations/20260706110000_add_visual_diff_ai_summary/migration.sql +2 -0
- package/prisma/migrations/20260707120000_script_bundles/migration.sql +25 -0
- package/prisma/migrations/20260707130000_requirement_source_section/migration.sql +4 -0
- package/prisma/migrations/20260707140000_structured_skill_metadata/migration.sql +8 -0
- package/prisma/migrations/20260707150000_crawler_platform_primitives/migration.sql +112 -0
- package/prisma/migrations/20260707160000_screen_group_versioning/migration.sql +9 -0
- package/prisma/migrations/20260707170000_add_mfa_fields/migration.sql +24 -0
- package/prisma/migrations/20260707180000_add_missing_tables/migration.sql +158 -0
- package/prisma/migrations/20260707190000_add_missing_columns/migration.sql +15 -0
- package/prisma/migrations/20260707200000_add_plan_sessions/migration.sql +1 -0
- package/prisma/migrations/20260708100000_missing_columns_comprehensive/migration.sql +15 -0
- package/prisma/migrations/20260708200000_testcase_dataset_column/migration.sql +16 -0
- package/prisma/migrations/20260709100000_add_filename_to_native_app_build/migration.sql +1 -0
- package/prisma/migrations/20260709200000_cloud_url_visual_artifacts/migration.sql +6 -0
- package/prisma/migrations/20260714200000_add_cached_scenarios_to_artifact/migration.sql +4 -0
- package/prisma/migrations/20260715200000_screen_markdown_content/migration.sql +2 -0
- package/prisma/migrations/20260716100000_github_repo_coverage_tables/migration.sql +114 -0
- package/prisma/migrations/20260716200000_github_pr_script_validation/migration.sql +48 -0
- package/prisma/migrations/20260716210000_s3_content_keys/migration.sql +20 -0
- package/prisma/migrations/20260717220000_ide_push_token/migration.sql +21 -0
- package/prisma/migrations/20260717230000_ide_push_script_ids/migration.sql +2 -0
- package/prisma/migrations/20260730040000_add_step_evidence_and_validation/migration.sql +93 -0
- package/prisma/migrations/20260803000000_add_tenantId_to_test_data_row/migration.sql +40 -0
- package/prisma/migrations/20260804000000_add_project_restricted/migration.sql +6 -0
- package/prisma/migrations/20260804000000_add_user_avatar_url/migration.sql +4 -0
- package/prisma/migrations/20260805000000_add_auditlog_ipaddress/migration.sql +2 -0
- package/prisma/migrations/20260807000000_add_test_data_classification/migration.sql +18 -0
- package/prisma/migrations/20260807000001_add_test_case_notes/migration.sql +5 -0
- package/prisma/migrations/20260807000002_add_visual_baseline_browser_structured_steps/migration.sql +11 -0
- package/prisma/migrations/20260807100000_add_tenant_plan_config/migration.sql +14 -0
- package/prisma/migrations/20260808000000_agent_token_missing_columns/migration.sql +22 -0
- package/prisma/migrations/20260808000001_visual_diff_image_and_threshold/migration.sql +8 -0
- package/prisma/migrations/20260808000002_ssoconfig_email_domains/migration.sql +7 -0
- package/prisma/migrations/20260808000003_project_status_description_updatedat/migration.sql +7 -0
- package/prisma/migrations/20260814000000_workspace_require_mfa/migration.sql +2 -0
- package/prisma/migrations/20260814000001_add_screenshot_dpr/migration.sql +2 -0
- package/prisma/migrations/20260818000000_add_content_hash_to_test_case/migration.sql +6 -0
- package/prisma/migrations/20260818000001_add_grounding_hash_to_test_case/migration.sql +3 -0
- package/prisma/migrations/20260819000000_coverage_mapping_cross_encoder_fields/migration.sql +3 -0
- package/prisma/migrations/20260820000000_add_locators_json_to_test_case/migration.sql +6 -0
- package/prisma/migrations/20260820000001_add_test_case_version/migration.sql +27 -0
- package/prisma/migrations/20260826000000_add_capture_step_screenshots/migration.sql +1 -0
- package/prisma/migrations/20260903000000_add_platform_job_dlq/migration.sql +10 -0
- package/prisma/migrations/20260903000002_add_versioning_tables/migration.sql +38 -0
- package/prisma/migrations/20260903000003_add_learning_models/migration.sql +71 -0
- package/prisma/migrations/20260903000004_add_workspace_agent_prompts/migration.sql +33 -0
- package/prisma/migrations/20260903000005_add_config_history/migration.sql +70 -0
- package/prisma/migrations/20260903000006_add_skill_file_config/migration.sql +24 -0
- package/prisma/migrations/20260904000000_add_agent_prompt_platform_table/migration.sql +23 -0
- package/prisma/migrations/20260904180424_rbac_role_configs_admin_roles/migration.sql +606 -0
- package/prisma/migrations/20260907000000_fix_testcase_timestamps/migration.sql +13 -0
- package/prisma/migrations/20260907000001_add_artifact_imported_suite_id/migration.sql +1 -0
- package/prisma/migrations/20260907000002_add_user_login_tracking/migration.sql +9 -0
- package/prisma/migrations/20260907000003_add_artifact_import_tracking/migration.sql +9 -0
- package/prisma/migrations/20260907000004_add_artifact_version_chain/migration.sql +18 -0
- package/prisma/migrations/20260908000000_add_project_vsa_enabled/migration.sql +2 -0
- package/prisma/migrations/20260908000001_rbac_migration_catchup/migration.sql +314 -0
- package/prisma/migrations/20260908000002_fix_role_configs_empty_permissions/migration.sql +22 -0
- package/prisma/migrations/20260908000003_sync_builtin_role_permissions/migration.sql +38 -0
- package/prisma/migrations/20260909000000_add_filepath_to_testscript/migration.sql +5 -0
- package/prisma/migrations/20260909000001_add_alignment_result_table/migration.sql +31 -0
- package/prisma/migrations/20260910000000_add_admin_mfa/migration.sql +35 -0
- package/prisma/migrations/20260910000000_add_dom_snapshot_cloud_url/migration.sql +2 -0
- package/prisma/migrations/20260910000001_add_requires_auth_to_screen/migration.sql +1 -0
- package/prisma/migrations/20260910000002_add_screen_requires_auth/migration.sql +2 -0
- package/prisma/migrations/20260910000003_add_admin_auth_sessions/migration.sql +17 -0
- package/prisma/migrations/20260916000001_add_admin_last_login/migration.sql +1 -0
- package/prisma/migrations/20260916000002_add_admin_failed_login/migration.sql +2 -0
- package/prisma/migrations/20260916000003_seed_system_tenant/migration.sql +6 -0
- package/prisma/migrations/20260918000000_fix_permissions_comprehensive/migration.sql +63 -0
- package/prisma/migrations/20260924000000_add_screen_role_access/migration.sql +2 -0
- package/prisma/migrations/20260928000000_add_navigation_graph/migration.sql +41 -0
- package/prisma/migrations/20260929000000_artifact_content_hash_suite_unique/migration.sql +25 -0
- package/prisma/migrations/20260929000000_navigation_graph_unique_constraint/migration.sql +5 -0
- package/prisma/migrations/20260929000001_add_membership_status/migration.sql +7 -0
- package/prisma/migrations/20260929000002_add_sso_config_scim_token_hash/migration.sql +8 -0
- package/prisma/migrations/20261005000001_jobs_workers_hardening/migration.sql +63 -0
- package/prisma/migrations/20261009000001_add_suite_category/migration.sql +2 -0
- package/prisma/migrations/20261009000002_add_testcase_approved_fields/migration.sql +3 -0
- package/prisma/migrations/20261012_auto_version_history/migration.sql +111 -0
- package/prisma/migrations/20261015000001_traceability_alignment_gaps/migration.sql +11 -0
- package/prisma/migrations/20261028000001_context_intelligence_p1_p7/migration.sql +76 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +2901 -0
- package/prisma/seed.ts +1262 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
-- Catch-up migration for failed 20260904180424_rbac_role_configs_admin_roles.
|
|
2
|
+
-- That migration had a bug (KnowledgeChunk.tsv DROP DEFAULT on a generated column)
|
|
3
|
+
-- which caused a PostgreSQL error and rolled back the entire migration, but Prisma
|
|
4
|
+
-- marked it as "applied". This migration re-applies everything idempotently.
|
|
5
|
+
-- All statements use IF NOT EXISTS / IF EXISTS / DO $$ blocks for safety.
|
|
6
|
+
|
|
7
|
+
-- ============================================================
|
|
8
|
+
-- 1. COLUMN ADDITIONS (critical — missing columns cause 500s)
|
|
9
|
+
-- ============================================================
|
|
10
|
+
|
|
11
|
+
-- AdminUser.role (RBAC)
|
|
12
|
+
ALTER TABLE "AdminUser" ADD COLUMN IF NOT EXISTS "role" TEXT NOT NULL DEFAULT 'SUPER_ADMIN';
|
|
13
|
+
|
|
14
|
+
-- Project.vsaEnabled (schema drift — was added to schema.prisma without a migration)
|
|
15
|
+
ALTER TABLE "Project" ADD COLUMN IF NOT EXISTS "vsaEnabled" BOOLEAN NOT NULL DEFAULT false;
|
|
16
|
+
|
|
17
|
+
-- TestCase timestamps (were added in the RBAC migration, required NOT NULL fields)
|
|
18
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
|
19
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
|
20
|
+
|
|
21
|
+
-- ============================================================
|
|
22
|
+
-- 2. COLUMN DROPS (remove deprecated columns; IF EXISTS = safe)
|
|
23
|
+
-- ============================================================
|
|
24
|
+
|
|
25
|
+
ALTER TABLE "TestCase" DROP COLUMN IF EXISTS "genAt";
|
|
26
|
+
ALTER TABLE "TestResult" DROP COLUMN IF EXISTS "dataRow";
|
|
27
|
+
ALTER TABLE "TestResult" DROP COLUMN IF EXISTS "networkTimings";
|
|
28
|
+
ALTER TABLE "TestResult" DROP COLUMN IF EXISTS "rootCauseSummary";
|
|
29
|
+
ALTER TABLE "VisualBaseline" DROP COLUMN IF EXISTS "domSnapshotPath";
|
|
30
|
+
ALTER TABLE "Screen" DROP COLUMN IF EXISTS "a11yViolations";
|
|
31
|
+
ALTER TABLE "Screen" DROP COLUMN IF EXISTS "securityHeaders";
|
|
32
|
+
ALTER TABLE "PerformanceSnapshot" DROP COLUMN IF EXISTS "lighthouseReport";
|
|
33
|
+
ALTER TABLE "PlatformJob" DROP COLUMN IF EXISTS "appiumSessionId";
|
|
34
|
+
ALTER TABLE "PlatformJob" DROP COLUMN IF EXISTS "deviceFarm";
|
|
35
|
+
ALTER TABLE "PlatformJob" DROP COLUMN IF EXISTS "deviceModel";
|
|
36
|
+
ALTER TABLE "PlatformJob" DROP COLUMN IF EXISTS "osVersion";
|
|
37
|
+
|
|
38
|
+
-- ============================================================
|
|
39
|
+
-- 3. COLUMN TYPE / DEFAULT CHANGES (idempotent or no-op safe)
|
|
40
|
+
-- ============================================================
|
|
41
|
+
|
|
42
|
+
-- AppField.piiClass default
|
|
43
|
+
DO $$ BEGIN
|
|
44
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='AppField' AND column_name='piiClass') THEN
|
|
45
|
+
ALTER TABLE "AppField" ALTER COLUMN "piiClass" SET DEFAULT 'unknown';
|
|
46
|
+
END IF;
|
|
47
|
+
END $$;
|
|
48
|
+
|
|
49
|
+
-- Comment.userId — allow null (drop not null constraint)
|
|
50
|
+
DO $$ BEGIN
|
|
51
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='Comment' AND column_name='userId' AND is_nullable='NO') THEN
|
|
52
|
+
ALTER TABLE "Comment" ALTER COLUMN "userId" DROP NOT NULL;
|
|
53
|
+
END IF;
|
|
54
|
+
END $$;
|
|
55
|
+
|
|
56
|
+
-- GitHubRepoConnection.testIdPattern default
|
|
57
|
+
DO $$ BEGIN
|
|
58
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='GitHubRepoConnection' AND column_name='testIdPattern') THEN
|
|
59
|
+
ALTER TABLE "GitHubRepoConnection" ALTER COLUMN "testIdPattern" SET DEFAULT 'TC-[A-Z]+-\d+';
|
|
60
|
+
END IF;
|
|
61
|
+
END $$;
|
|
62
|
+
|
|
63
|
+
-- KnowledgeChunk.tsv — if still a generated column, drop expression so it can be reattached
|
|
64
|
+
-- (Use DO block so it's a no-op if already a plain column)
|
|
65
|
+
DO $$ BEGIN
|
|
66
|
+
IF EXISTS (
|
|
67
|
+
SELECT 1 FROM information_schema.columns
|
|
68
|
+
WHERE table_name = 'KnowledgeChunk' AND column_name = 'tsv'
|
|
69
|
+
AND is_generated = 'ALWAYS'
|
|
70
|
+
) THEN
|
|
71
|
+
ALTER TABLE "KnowledgeChunk" ALTER COLUMN "tsv" DROP EXPRESSION;
|
|
72
|
+
END IF;
|
|
73
|
+
END $$;
|
|
74
|
+
|
|
75
|
+
-- PerformanceSnapshot: change lighthouse columns from numeric to double precision
|
|
76
|
+
DO $$ BEGIN
|
|
77
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='PerformanceSnapshot' AND column_name='lighthousePerf') THEN
|
|
78
|
+
ALTER TABLE "PerformanceSnapshot"
|
|
79
|
+
ALTER COLUMN "lighthousePerf" SET DATA TYPE DOUBLE PRECISION,
|
|
80
|
+
ALTER COLUMN "lighthouseA11y" SET DATA TYPE DOUBLE PRECISION,
|
|
81
|
+
ALTER COLUMN "lighthouseSEO" SET DATA TYPE DOUBLE PRECISION,
|
|
82
|
+
ALTER COLUMN "lighthouseBP" SET DATA TYPE DOUBLE PRECISION;
|
|
83
|
+
END IF;
|
|
84
|
+
END $$;
|
|
85
|
+
|
|
86
|
+
-- SharedRunToken: standardize timestamp types
|
|
87
|
+
DO $$ BEGIN
|
|
88
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='SharedRunToken' AND column_name='expiresAt') THEN
|
|
89
|
+
ALTER TABLE "SharedRunToken"
|
|
90
|
+
ALTER COLUMN "expiresAt" SET DATA TYPE TIMESTAMP(3),
|
|
91
|
+
ALTER COLUMN "createdAt" SET DATA TYPE TIMESTAMP(3);
|
|
92
|
+
END IF;
|
|
93
|
+
END $$;
|
|
94
|
+
|
|
95
|
+
-- SsoConfig: set jitProvisioning default to false
|
|
96
|
+
DO $$ BEGIN
|
|
97
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='SsoConfig' AND column_name='jitProvisioning') THEN
|
|
98
|
+
ALTER TABLE "SsoConfig" ALTER COLUMN "jitProvisioning" SET DEFAULT false;
|
|
99
|
+
END IF;
|
|
100
|
+
END $$;
|
|
101
|
+
|
|
102
|
+
-- ============================================================
|
|
103
|
+
-- 4. TABLES (audit history tables + role_configs + LlmPricing)
|
|
104
|
+
-- ============================================================
|
|
105
|
+
|
|
106
|
+
-- SystemConfigHistory / AgentPromptHistory / WorkspaceAgentPromptHistory
|
|
107
|
+
-- These were added in 20260903000005_add_config_history. If that migration
|
|
108
|
+
-- silently failed and was marked applied by Prisma, recreate idempotently.
|
|
109
|
+
CREATE TABLE IF NOT EXISTS "SystemConfigHistory" (
|
|
110
|
+
"id" TEXT NOT NULL,
|
|
111
|
+
"configKey" TEXT NOT NULL,
|
|
112
|
+
"category" TEXT NOT NULL,
|
|
113
|
+
"fieldKey" TEXT NOT NULL,
|
|
114
|
+
"oldValue" TEXT,
|
|
115
|
+
"newValue" TEXT,
|
|
116
|
+
"action" TEXT NOT NULL,
|
|
117
|
+
"sensitive" BOOLEAN NOT NULL DEFAULT false,
|
|
118
|
+
"adminId" TEXT,
|
|
119
|
+
"adminEmail" TEXT,
|
|
120
|
+
"changedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
121
|
+
CONSTRAINT "SystemConfigHistory_pkey" PRIMARY KEY ("id")
|
|
122
|
+
);
|
|
123
|
+
CREATE INDEX IF NOT EXISTS "SystemConfigHistory_configKey_changedAt_idx" ON "SystemConfigHistory"("configKey", "changedAt" DESC);
|
|
124
|
+
CREATE INDEX IF NOT EXISTS "SystemConfigHistory_category_changedAt_idx" ON "SystemConfigHistory"("category", "changedAt" DESC);
|
|
125
|
+
CREATE INDEX IF NOT EXISTS "SystemConfigHistory_adminId_idx" ON "SystemConfigHistory"("adminId");
|
|
126
|
+
|
|
127
|
+
CREATE TABLE IF NOT EXISTS "AgentPromptHistory" (
|
|
128
|
+
"id" TEXT NOT NULL,
|
|
129
|
+
"agentPromptId" TEXT NOT NULL,
|
|
130
|
+
"agentKey" TEXT NOT NULL,
|
|
131
|
+
"passKey" TEXT,
|
|
132
|
+
"oldBody" TEXT NOT NULL,
|
|
133
|
+
"newBody" TEXT NOT NULL,
|
|
134
|
+
"version" INTEGER NOT NULL,
|
|
135
|
+
"adminId" TEXT,
|
|
136
|
+
"adminEmail" TEXT,
|
|
137
|
+
"changedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
138
|
+
CONSTRAINT "AgentPromptHistory_pkey" PRIMARY KEY ("id")
|
|
139
|
+
);
|
|
140
|
+
CREATE INDEX IF NOT EXISTS "AgentPromptHistory_agentPromptId_changedAt_idx" ON "AgentPromptHistory"("agentPromptId", "changedAt" DESC);
|
|
141
|
+
CREATE INDEX IF NOT EXISTS "AgentPromptHistory_agentKey_changedAt_idx" ON "AgentPromptHistory"("agentKey", "changedAt" DESC);
|
|
142
|
+
|
|
143
|
+
CREATE TABLE IF NOT EXISTS "WorkspaceAgentPromptHistory" (
|
|
144
|
+
"id" TEXT NOT NULL,
|
|
145
|
+
"workspaceAgentPromptId" TEXT,
|
|
146
|
+
"tenantId" TEXT NOT NULL,
|
|
147
|
+
"agentKey" TEXT NOT NULL,
|
|
148
|
+
"passKey" TEXT,
|
|
149
|
+
"oldBody" TEXT,
|
|
150
|
+
"newBody" TEXT,
|
|
151
|
+
"action" TEXT NOT NULL,
|
|
152
|
+
"updatedBy" TEXT,
|
|
153
|
+
"changedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
154
|
+
CONSTRAINT "WorkspaceAgentPromptHistory_pkey" PRIMARY KEY ("id")
|
|
155
|
+
);
|
|
156
|
+
CREATE INDEX IF NOT EXISTS "WorkspaceAgentPromptHistory_tenantId_agentKey_changedAt_idx" ON "WorkspaceAgentPromptHistory"("tenantId", "agentKey", "changedAt" DESC);
|
|
157
|
+
CREATE INDEX IF NOT EXISTS "WorkspaceAgentPromptHistory_workspaceAgentPromptId_changedAt_idx" ON "WorkspaceAgentPromptHistory"("workspaceAgentPromptId", "changedAt" DESC);
|
|
158
|
+
|
|
159
|
+
-- role_configs: create with correct schema.
|
|
160
|
+
-- Drop and recreate if table is missing OR has wrong columns (displayName/description
|
|
161
|
+
-- were added by an earlier broken manual attempt on prod).
|
|
162
|
+
DO $$ BEGIN
|
|
163
|
+
IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'role_configs')
|
|
164
|
+
OR EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'role_configs' AND column_name = 'displayName')
|
|
165
|
+
OR EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'role_configs' AND column_name = 'description') THEN
|
|
166
|
+
DROP TABLE IF EXISTS "role_configs";
|
|
167
|
+
CREATE TABLE "role_configs" (
|
|
168
|
+
"roleName" TEXT NOT NULL,
|
|
169
|
+
"rank" INTEGER NOT NULL,
|
|
170
|
+
"permissions" TEXT[],
|
|
171
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT NOW(),
|
|
172
|
+
CONSTRAINT "role_configs_pkey" PRIMARY KEY ("roleName")
|
|
173
|
+
);
|
|
174
|
+
END IF;
|
|
175
|
+
END $$;
|
|
176
|
+
|
|
177
|
+
CREATE TABLE IF NOT EXISTS "LlmPricing" (
|
|
178
|
+
"id" TEXT NOT NULL,
|
|
179
|
+
"modelKey" TEXT NOT NULL,
|
|
180
|
+
"inputPer1M" DOUBLE PRECISION NOT NULL,
|
|
181
|
+
"outputPer1M" DOUBLE PRECISION NOT NULL,
|
|
182
|
+
"cacheReadPer1M" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
183
|
+
"cacheWritePer1M" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
184
|
+
"effectiveDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
185
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
186
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT NOW(),
|
|
187
|
+
CONSTRAINT "LlmPricing_pkey" PRIMARY KEY ("id")
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
-- ============================================================
|
|
191
|
+
-- 5. INDEXES
|
|
192
|
+
-- ============================================================
|
|
193
|
+
|
|
194
|
+
DROP INDEX IF EXISTS "KnowledgeChunk_tsv_idx";
|
|
195
|
+
DROP INDEX IF EXISTS "PlatformJob_status_heartbeatAt_idx";
|
|
196
|
+
DROP INDEX IF EXISTS "Screen_tenantId_projectId_discoveryMethod_idx";
|
|
197
|
+
DROP INDEX IF EXISTS "ScreenGroup_tenantId_projectId_crawlJobId_idx";
|
|
198
|
+
|
|
199
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "role_configs_rank_key" ON "role_configs"("rank");
|
|
200
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "LlmPricing_modelKey_key" ON "LlmPricing"("modelKey");
|
|
201
|
+
CREATE INDEX IF NOT EXISTS "LlmPricing_modelKey_idx" ON "LlmPricing"("modelKey");
|
|
202
|
+
CREATE INDEX IF NOT EXISTS "AuditLog_tenantId_action_idx" ON "AuditLog"("tenantId", "action");
|
|
203
|
+
CREATE INDEX IF NOT EXISTS "Membership_tenantId_idx" ON "Membership"("tenantId");
|
|
204
|
+
CREATE INDEX IF NOT EXISTS "Membership_userId_idx" ON "Membership"("userId");
|
|
205
|
+
CREATE INDEX IF NOT EXISTS "MfaRecoveryCode_userId_idx" ON "MfaRecoveryCode"("userId");
|
|
206
|
+
CREATE INDEX IF NOT EXISTS "PlatformJob_tenantId_projectId_queuedAt_idx" ON "PlatformJob"("tenantId", "projectId", "queuedAt");
|
|
207
|
+
CREATE INDEX IF NOT EXISTS "PlatformJob_status_workerId_idx" ON "PlatformJob"("status", "workerId");
|
|
208
|
+
CREATE INDEX IF NOT EXISTS "Screen_status_idx" ON "Screen"("status");
|
|
209
|
+
CREATE INDEX IF NOT EXISTS "TestCase_status_projectId_idx" ON "TestCase"("status", "projectId");
|
|
210
|
+
CREATE INDEX IF NOT EXISTS "TestCaseRun_tenantId_status_createdAt_idx" ON "TestCaseRun"("tenantId", "status", "createdAt");
|
|
211
|
+
CREATE INDEX IF NOT EXISTS "TestResult_tenantId_runId_status_idx" ON "TestResult"("tenantId", "runId", "status");
|
|
212
|
+
CREATE INDEX IF NOT EXISTS "WebhookDelivery_webhookId_status_idx" ON "WebhookDelivery"("webhookId", "status");
|
|
213
|
+
|
|
214
|
+
-- ============================================================
|
|
215
|
+
-- 6. FOREIGN KEYS (all guarded with IF NOT EXISTS + orphan cleanup)
|
|
216
|
+
-- ============================================================
|
|
217
|
+
|
|
218
|
+
-- Clean up orphaned AuditLog.actorId before adding FK
|
|
219
|
+
UPDATE "AuditLog" SET "actorId" = NULL
|
|
220
|
+
WHERE "actorId" IS NOT NULL
|
|
221
|
+
AND "actorId" NOT IN (SELECT id FROM "User");
|
|
222
|
+
|
|
223
|
+
DO $$ BEGIN
|
|
224
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'AuditLog_actorId_fkey') THEN
|
|
225
|
+
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_actorId_fkey"
|
|
226
|
+
FOREIGN KEY ("actorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
227
|
+
END IF;
|
|
228
|
+
END $$;
|
|
229
|
+
DO $$ BEGIN
|
|
230
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'AuditLog_tenantId_fkey') THEN
|
|
231
|
+
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_tenantId_fkey"
|
|
232
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
233
|
+
END IF;
|
|
234
|
+
END $$;
|
|
235
|
+
DO $$ BEGIN
|
|
236
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'AccessReview_tenantId_fkey') THEN
|
|
237
|
+
ALTER TABLE "AccessReview" ADD CONSTRAINT "AccessReview_tenantId_fkey"
|
|
238
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
239
|
+
END IF;
|
|
240
|
+
END $$;
|
|
241
|
+
DO $$ BEGIN
|
|
242
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'Screen_projectId_fkey') THEN
|
|
243
|
+
ALTER TABLE "Screen" ADD CONSTRAINT "Screen_projectId_fkey"
|
|
244
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
245
|
+
END IF;
|
|
246
|
+
END $$;
|
|
247
|
+
DO $$ BEGIN
|
|
248
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'ScreenA11yViolation_projectId_fkey') THEN
|
|
249
|
+
ALTER TABLE "ScreenA11yViolation" ADD CONSTRAINT "ScreenA11yViolation_projectId_fkey"
|
|
250
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
251
|
+
END IF;
|
|
252
|
+
END $$;
|
|
253
|
+
DO $$ BEGIN
|
|
254
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'ScreenA11yViolation_screenId_fkey') THEN
|
|
255
|
+
ALTER TABLE "ScreenA11yViolation" ADD CONSTRAINT "ScreenA11yViolation_screenId_fkey"
|
|
256
|
+
FOREIGN KEY ("screenId") REFERENCES "Screen"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
257
|
+
END IF;
|
|
258
|
+
END $$;
|
|
259
|
+
DO $$ BEGIN
|
|
260
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'Element_screenId_fkey') THEN
|
|
261
|
+
ALTER TABLE "Element" ADD CONSTRAINT "Element_screenId_fkey"
|
|
262
|
+
FOREIGN KEY ("screenId") REFERENCES "Screen"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
263
|
+
END IF;
|
|
264
|
+
END $$;
|
|
265
|
+
DO $$ BEGIN
|
|
266
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'TestSuite_projectId_fkey') THEN
|
|
267
|
+
ALTER TABLE "TestSuite" ADD CONSTRAINT "TestSuite_projectId_fkey"
|
|
268
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
269
|
+
END IF;
|
|
270
|
+
END $$;
|
|
271
|
+
DO $$ BEGIN
|
|
272
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'TestCase_dataSetId_fkey') THEN
|
|
273
|
+
ALTER TABLE "TestCase" ADD CONSTRAINT "TestCase_dataSetId_fkey"
|
|
274
|
+
FOREIGN KEY ("dataSetId") REFERENCES "TestDataSet"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
275
|
+
END IF;
|
|
276
|
+
END $$;
|
|
277
|
+
DO $$ BEGIN
|
|
278
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'TestRunShard_runId_fkey') THEN
|
|
279
|
+
ALTER TABLE "TestRunShard" ADD CONSTRAINT "TestRunShard_runId_fkey"
|
|
280
|
+
FOREIGN KEY ("runId") REFERENCES "TestRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
281
|
+
END IF;
|
|
282
|
+
END $$;
|
|
283
|
+
DO $$ BEGIN
|
|
284
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'SsoConfig_tenantId_fkey') THEN
|
|
285
|
+
ALTER TABLE "SsoConfig" ADD CONSTRAINT "SsoConfig_tenantId_fkey"
|
|
286
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
287
|
+
END IF;
|
|
288
|
+
END $$;
|
|
289
|
+
DO $$ BEGIN
|
|
290
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'ScreenDiff_screenId_fkey') THEN
|
|
291
|
+
ALTER TABLE "ScreenDiff" ADD CONSTRAINT "ScreenDiff_screenId_fkey"
|
|
292
|
+
FOREIGN KEY ("screenId") REFERENCES "Screen"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
293
|
+
END IF;
|
|
294
|
+
END $$;
|
|
295
|
+
DO $$ BEGIN
|
|
296
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'ProbeObservation_screenId_fkey') THEN
|
|
297
|
+
ALTER TABLE "ProbeObservation" ADD CONSTRAINT "ProbeObservation_screenId_fkey"
|
|
298
|
+
FOREIGN KEY ("screenId") REFERENCES "Screen"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
299
|
+
END IF;
|
|
300
|
+
END $$;
|
|
301
|
+
|
|
302
|
+
-- ============================================================
|
|
303
|
+
-- 7. SEED DATA — role_configs default permissions
|
|
304
|
+
-- ON CONFLICT DO NOTHING so admin customizations are preserved.
|
|
305
|
+
-- ============================================================
|
|
306
|
+
|
|
307
|
+
INSERT INTO "role_configs" ("roleName", "rank", "permissions", "updatedAt") VALUES
|
|
308
|
+
('VIEWER', 0, ARRAY['project:read','connector:read','audit:read','analytics:read'], NOW()),
|
|
309
|
+
('DEVELOPER', 1, ARRAY['project:read','crawl:run','test:generate','test:run','run:execute','connector:read','extension:write','mcp:access'], NOW()),
|
|
310
|
+
('TESTER', 2, ARRAY['project:read','crawl:run','test:generate','test:review','test:run','run:execute','run:cancel','run:share','connector:read','extension:write','analytics:read','report:send','coverage:export'], NOW()),
|
|
311
|
+
('QA_LEAD', 3, ARRAY['project:create','project:read','project:write','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','visual:manage','skill-file:approve','member:invite','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','mcp:access'], NOW()),
|
|
312
|
+
('ADMIN', 4, ARRAY['project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','mcp:access','workspace:session-manage'], NOW()),
|
|
313
|
+
('OWNER', 5, ARRAY['workspace:manage','project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','billing:manage','mcp:access','workspace:session-manage'], NOW())
|
|
314
|
+
ON CONFLICT ("roleName") DO NOTHING;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- Fix role_configs rows that have empty permissions arrays (from the broken initial seed).
|
|
2
|
+
-- The catchup migration (20260908000001) used ON CONFLICT DO NOTHING, leaving existing
|
|
3
|
+
-- rows with permissions = '{}' untouched. This migration updates them to canonical defaults.
|
|
4
|
+
-- Rows with non-empty permissions are left alone (preserves admin customizations).
|
|
5
|
+
|
|
6
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','connector:read','audit:read','analytics:read'], "updatedAt" = NOW()
|
|
7
|
+
WHERE "roleName" = 'VIEWER' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
8
|
+
|
|
9
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','crawl:run','test:generate','test:run','run:execute','connector:read','extension:write','mcp:access'], "updatedAt" = NOW()
|
|
10
|
+
WHERE "roleName" = 'DEVELOPER' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
11
|
+
|
|
12
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','crawl:run','test:generate','test:review','test:run','run:execute','run:cancel','run:share','connector:read','extension:write','analytics:read','report:send','coverage:export'], "updatedAt" = NOW()
|
|
13
|
+
WHERE "roleName" = 'TESTER' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
14
|
+
|
|
15
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:create','project:read','project:write','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','visual:manage','skill-file:approve','member:invite','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','mcp:access'], "updatedAt" = NOW()
|
|
16
|
+
WHERE "roleName" = 'QA_LEAD' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
17
|
+
|
|
18
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','mcp:access','workspace:session-manage'], "updatedAt" = NOW()
|
|
19
|
+
WHERE "roleName" = 'ADMIN' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
20
|
+
|
|
21
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['workspace:manage','project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','billing:manage','mcp:access','workspace:session-manage'], "updatedAt" = NOW()
|
|
22
|
+
WHERE "roleName" = 'OWNER' AND (array_length("permissions", 1) IS NULL OR array_length("permissions", 1) = 0);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
-- Unconditionally sync all built-in role_configs to canonical permission sets.
|
|
2
|
+
-- Previous migration (20260908000002) only fixed EMPTY arrays; rows that had
|
|
3
|
+
-- a non-empty but STALE permissions array (missing permissions added to the
|
|
4
|
+
-- codebase after the row was created) were left untouched, causing 403s for
|
|
5
|
+
-- permissions like artifact:delete that are defined in ROLE_PERMISSIONS but
|
|
6
|
+
-- absent from the DB row.
|
|
7
|
+
--
|
|
8
|
+
-- Built-in roles (OWNER/ADMIN/QA_LEAD/TESTER/DEVELOPER/VIEWER) are always
|
|
9
|
+
-- kept in sync with the canonical list. Only custom roles are admin-managed.
|
|
10
|
+
|
|
11
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','connector:read','audit:read','analytics:read'], "updatedAt" = NOW()
|
|
12
|
+
WHERE "roleName" = 'VIEWER';
|
|
13
|
+
|
|
14
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','crawl:run','test:generate','test:review','test:run','run:execute','run:cancel','run:share','connector:read','extension:write','analytics:read','report:send','coverage:export'], "updatedAt" = NOW()
|
|
15
|
+
WHERE "roleName" = 'TESTER';
|
|
16
|
+
|
|
17
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:read','crawl:run','test:generate','test:run','run:execute','connector:read','extension:write','mcp:access'], "updatedAt" = NOW()
|
|
18
|
+
WHERE "roleName" = 'DEVELOPER';
|
|
19
|
+
|
|
20
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:create','project:read','project:write','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','visual:manage','skill-file:approve','member:invite','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','mcp:access'], "updatedAt" = NOW()
|
|
21
|
+
WHERE "roleName" = 'QA_LEAD';
|
|
22
|
+
|
|
23
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','mcp:access','workspace:session-manage'], "updatedAt" = NOW()
|
|
24
|
+
WHERE "roleName" = 'ADMIN';
|
|
25
|
+
|
|
26
|
+
UPDATE "role_configs" SET "permissions" = ARRAY['workspace:manage','project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','billing:manage','mcp:access','workspace:session-manage'], "updatedAt" = NOW()
|
|
27
|
+
WHERE "roleName" = 'OWNER';
|
|
28
|
+
|
|
29
|
+
-- Insert any missing built-in roles (in case the initial seed never ran)
|
|
30
|
+
INSERT INTO "role_configs" ("roleName", "rank", "permissions", "updatedAt")
|
|
31
|
+
VALUES
|
|
32
|
+
('VIEWER', 1, ARRAY['project:read','connector:read','audit:read','analytics:read'], NOW()),
|
|
33
|
+
('TESTER', 2, ARRAY['project:read','crawl:run','test:generate','test:review','test:run','run:execute','run:cancel','run:share','connector:read','extension:write','analytics:read','report:send','coverage:export'], NOW()),
|
|
34
|
+
('DEVELOPER', 2, ARRAY['project:read','crawl:run','test:generate','test:run','run:execute','connector:read','extension:write','mcp:access'], NOW()),
|
|
35
|
+
('QA_LEAD', 3, ARRAY['project:create','project:read','project:write','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','visual:manage','skill-file:approve','member:invite','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','mcp:access'], NOW()),
|
|
36
|
+
('ADMIN', 4, ARRAY['project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','mcp:access','workspace:session-manage'], NOW()),
|
|
37
|
+
('OWNER', 5, ARRAY['workspace:manage','project:create','project:read','project:write','project:delete','crawl:run','test:generate','test:review','test:run','test:delete','run:execute','run:cancel','run:schedule','run:share','connector:manage','connector:read','audit:read','visual:manage','skill-file:approve','member:invite','member:manage','extension:write','analytics:read','report:send','coverage:export','coverage:remap','performance:alert','artifact:delete','import:manage','token-usage:read','billing:read','billing:manage','mcp:access','workspace:session-manage'], NOW())
|
|
38
|
+
ON CONFLICT ("roleName") DO NOTHING;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Add filePath column to TestScript.
|
|
2
|
+
-- This column was added to schema.prisma in commit 2ee9eed9 without a corresponding
|
|
3
|
+
-- migration, causing Prisma to SELECT a non-existent column → 500 on any query
|
|
4
|
+
-- that includes TestScript (e.g. listTestCases with scripts: true).
|
|
5
|
+
ALTER TABLE "TestScript" ADD COLUMN IF NOT EXISTS "filePath" TEXT;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- CreateTable: AlignmentResult
|
|
2
|
+
-- Dedicated table for AI alignment verification results.
|
|
3
|
+
-- Replaces the previous hack of storing JSON blobs in TestScript rows
|
|
4
|
+
-- with a synthetic language suffix (e.g. 'playwright-ts:alignment').
|
|
5
|
+
|
|
6
|
+
CREATE TABLE "AlignmentResult" (
|
|
7
|
+
"id" TEXT NOT NULL,
|
|
8
|
+
"tenantId" TEXT NOT NULL,
|
|
9
|
+
"projectId" TEXT NOT NULL,
|
|
10
|
+
"testCaseId" TEXT NOT NULL,
|
|
11
|
+
"language" TEXT NOT NULL,
|
|
12
|
+
"score" INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
"aligned" BOOLEAN NOT NULL DEFAULT false,
|
|
14
|
+
"issues" JSONB NOT NULL DEFAULT '[]',
|
|
15
|
+
"verifiedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
16
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
17
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
18
|
+
|
|
19
|
+
CONSTRAINT "AlignmentResult_pkey" PRIMARY KEY ("id")
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE UNIQUE INDEX "AlignmentResult_testCaseId_language_key" ON "AlignmentResult"("testCaseId", "language");
|
|
23
|
+
CREATE INDEX "AlignmentResult_tenantId_projectId_idx" ON "AlignmentResult"("tenantId", "projectId");
|
|
24
|
+
CREATE INDEX "AlignmentResult_tenantId_testCaseId_idx" ON "AlignmentResult"("tenantId", "testCaseId");
|
|
25
|
+
|
|
26
|
+
-- Apply Row-Level Security (same pattern as all other tenant tables).
|
|
27
|
+
ALTER TABLE "AlignmentResult" ENABLE ROW LEVEL SECURITY;
|
|
28
|
+
ALTER TABLE "AlignmentResult" FORCE ROW LEVEL SECURITY;
|
|
29
|
+
CREATE POLICY tenant_isolation ON "AlignmentResult"
|
|
30
|
+
USING ("tenantId" = current_setting('app.current_tenant', true))
|
|
31
|
+
WITH CHECK ("tenantId" = current_setting('app.current_tenant', true));
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
ALTER TABLE "AdminUser"
|
|
2
|
+
ADD COLUMN "mfaEnabled" BOOLEAN NOT NULL DEFAULT false,
|
|
3
|
+
ADD COLUMN "mfaSecret_enc" TEXT,
|
|
4
|
+
ADD COLUMN "mfaVerifiedAt" TIMESTAMP(3);
|
|
5
|
+
|
|
6
|
+
CREATE TABLE "AdminMfaRecoveryCode" (
|
|
7
|
+
"id" TEXT NOT NULL,
|
|
8
|
+
"adminId" TEXT NOT NULL,
|
|
9
|
+
"codeHash" TEXT NOT NULL,
|
|
10
|
+
"usedAt" TIMESTAMP(3),
|
|
11
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
12
|
+
CONSTRAINT "AdminMfaRecoveryCode_pkey" PRIMARY KEY ("id")
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE TABLE "AdminMfaChallenge" (
|
|
16
|
+
"id" TEXT NOT NULL,
|
|
17
|
+
"adminId" TEXT NOT NULL,
|
|
18
|
+
"purpose" TEXT NOT NULL,
|
|
19
|
+
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
20
|
+
"usedAt" TIMESTAMP(3),
|
|
21
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
CONSTRAINT "AdminMfaChallenge_pkey" PRIMARY KEY ("id")
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX "AdminMfaRecoveryCode_adminId_idx" ON "AdminMfaRecoveryCode"("adminId");
|
|
26
|
+
CREATE INDEX "AdminMfaChallenge_adminId_purpose_usedAt_idx" ON "AdminMfaChallenge"("adminId", "purpose", "usedAt");
|
|
27
|
+
CREATE INDEX "AdminMfaChallenge_expiresAt_idx" ON "AdminMfaChallenge"("expiresAt");
|
|
28
|
+
|
|
29
|
+
ALTER TABLE "AdminMfaRecoveryCode"
|
|
30
|
+
ADD CONSTRAINT "AdminMfaRecoveryCode_adminId_fkey"
|
|
31
|
+
FOREIGN KEY ("adminId") REFERENCES "AdminUser"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
32
|
+
|
|
33
|
+
ALTER TABLE "AdminMfaChallenge"
|
|
34
|
+
ADD CONSTRAINT "AdminMfaChallenge_adminId_fkey"
|
|
35
|
+
FOREIGN KEY ("adminId") REFERENCES "AdminUser"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "Screen" ADD COLUMN "requiresAuth" BOOLEAN NOT NULL DEFAULT false;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CREATE TABLE "AdminAuthSession" (
|
|
2
|
+
"id" TEXT NOT NULL,
|
|
3
|
+
"adminId" TEXT NOT NULL,
|
|
4
|
+
"userAgent" TEXT,
|
|
5
|
+
"ipAddress" TEXT,
|
|
6
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
7
|
+
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
8
|
+
"revokedAt" TIMESTAMP(3),
|
|
9
|
+
CONSTRAINT "AdminAuthSession_pkey" PRIMARY KEY ("id")
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE INDEX "AdminAuthSession_adminId_idx" ON "AdminAuthSession"("adminId");
|
|
13
|
+
CREATE INDEX "AdminAuthSession_lastSeenAt_idx" ON "AdminAuthSession"("lastSeenAt");
|
|
14
|
+
|
|
15
|
+
ALTER TABLE "AdminAuthSession"
|
|
16
|
+
ADD CONSTRAINT "AdminAuthSession_adminId_fkey"
|
|
17
|
+
FOREIGN KEY ("adminId") REFERENCES "AdminUser"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "AdminUser" ADD COLUMN "lastLoginAt" TIMESTAMP(3);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Sentinel tenant for platform-admin audit events that have no tenant context
|
|
2
|
+
-- (e.g. admin.login / admin.login.failed). AuditLog.tenantId is NOT NULL with
|
|
3
|
+
-- an enforced FK, so a real Tenant row is required. Idempotent.
|
|
4
|
+
INSERT INTO "Tenant" (id, name, slug, isolation, region)
|
|
5
|
+
VALUES ('system', 'Platform (System)', 'system', 'POOL', 'GLOBAL')
|
|
6
|
+
ON CONFLICT (id) DO NOTHING;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- Comprehensive permissions fix
|
|
3
|
+
--
|
|
4
|
+
-- Gaps fixed:
|
|
5
|
+
-- 1. ALTER DEFAULT PRIVILEGES was missing FOR ROLE zeta_admin — tables created
|
|
6
|
+
-- by zeta_admin in migrations after 0002 did not auto-grant to qip_app.
|
|
7
|
+
-- This caused 42501 on Notification, ScreenGroup, WebhookDelivery, etc.
|
|
8
|
+
--
|
|
9
|
+
-- 2. Eight tables have ENABLE ROW LEVEL SECURITY but not FORCE ROW LEVEL
|
|
10
|
+
-- SECURITY, allowing the table owner (zeta_admin / migration role) to
|
|
11
|
+
-- bypass RLS silently. Consistent with all other tenant-scoped tables.
|
|
12
|
+
--
|
|
13
|
+
-- 3. Re-grants all existing tables and sequences to qip_app (catchup for
|
|
14
|
+
-- any table created after the initial 0002 grant ran without default privs).
|
|
15
|
+
-- ============================================================================
|
|
16
|
+
|
|
17
|
+
-- ---- 1. Fix DEFAULT PRIVILEGES so future tables auto-grant to qip_app ------
|
|
18
|
+
-- Without FOR ROLE the grant only applies to the role that ran migration 0002,
|
|
19
|
+
-- not to zeta_admin which creates all schema objects in production migrations.
|
|
20
|
+
DO $$
|
|
21
|
+
BEGIN
|
|
22
|
+
-- Set default privileges for zeta_admin-created objects going forward.
|
|
23
|
+
-- Idempotent: repeated runs are harmless.
|
|
24
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'zeta_admin') THEN
|
|
25
|
+
EXECUTE $q$ALTER DEFAULT PRIVILEGES FOR ROLE zeta_admin IN SCHEMA public
|
|
26
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO qip_app$q$;
|
|
27
|
+
EXECUTE $q$ALTER DEFAULT PRIVILEGES FOR ROLE zeta_admin IN SCHEMA public
|
|
28
|
+
GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO qip_app$q$;
|
|
29
|
+
END IF;
|
|
30
|
+
END $$;
|
|
31
|
+
|
|
32
|
+
-- ---- 2. Catchup grant: all tables and sequences that exist right now --------
|
|
33
|
+
GRANT USAGE ON SCHEMA public TO qip_app;
|
|
34
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO qip_app;
|
|
35
|
+
GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO qip_app;
|
|
36
|
+
|
|
37
|
+
-- ---- 3. Add FORCE ROW LEVEL SECURITY to tables missing it ------------------
|
|
38
|
+
-- These tables have RLS enabled but not FORCE, letting the owner bypass policies.
|
|
39
|
+
DO $$
|
|
40
|
+
DECLARE
|
|
41
|
+
t text;
|
|
42
|
+
tables text[] := ARRAY[
|
|
43
|
+
'TenantSetting',
|
|
44
|
+
'AgentToken',
|
|
45
|
+
'Webhook',
|
|
46
|
+
'ProjectArtifact',
|
|
47
|
+
'KnowledgeChunk',
|
|
48
|
+
'Invitation',
|
|
49
|
+
'ProjectMember',
|
|
50
|
+
'CustomRole'
|
|
51
|
+
];
|
|
52
|
+
BEGIN
|
|
53
|
+
FOREACH t IN ARRAY tables LOOP
|
|
54
|
+
-- Only apply if table exists and RLS is already enabled
|
|
55
|
+
IF EXISTS (
|
|
56
|
+
SELECT 1 FROM pg_class c
|
|
57
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
58
|
+
WHERE c.relname = t AND n.nspname = 'public' AND c.relrowsecurity = true
|
|
59
|
+
) THEN
|
|
60
|
+
EXECUTE format('ALTER TABLE "%s" FORCE ROW LEVEL SECURITY;', t);
|
|
61
|
+
END IF;
|
|
62
|
+
END LOOP;
|
|
63
|
+
END $$;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Navigation Knowledge Graph: Phase 1 schema additions
|
|
2
|
+
|
|
3
|
+
-- Screen: add crawl depth and parent URL for graph traversal
|
|
4
|
+
ALTER TABLE "Screen" ADD COLUMN IF NOT EXISTS "depth" INTEGER;
|
|
5
|
+
ALTER TABLE "Screen" ADD COLUMN IF NOT EXISTS "parentUrl" TEXT;
|
|
6
|
+
|
|
7
|
+
-- DiscoveredLink: hyperlink edges between screens discovered during crawl
|
|
8
|
+
CREATE TABLE IF NOT EXISTS "DiscoveredLink" (
|
|
9
|
+
"id" TEXT NOT NULL,
|
|
10
|
+
"tenantId" TEXT NOT NULL,
|
|
11
|
+
"projectId" TEXT NOT NULL,
|
|
12
|
+
"fromScreenId" TEXT NOT NULL,
|
|
13
|
+
"toScreenId" TEXT,
|
|
14
|
+
"href" TEXT NOT NULL,
|
|
15
|
+
"text" TEXT,
|
|
16
|
+
"landmark" TEXT,
|
|
17
|
+
"linkType" TEXT NOT NULL DEFAULT 'NAV_LINK',
|
|
18
|
+
"source" TEXT NOT NULL DEFAULT 'DOM',
|
|
19
|
+
"confidence" DOUBLE PRECISION NOT NULL DEFAULT 1.0,
|
|
20
|
+
"jobId" TEXT,
|
|
21
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
|
|
23
|
+
CONSTRAINT "DiscoveredLink_pkey" PRIMARY KEY ("id")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
-- Foreign keys
|
|
27
|
+
ALTER TABLE "DiscoveredLink" ADD CONSTRAINT "DiscoveredLink_projectId_fkey"
|
|
28
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
29
|
+
|
|
30
|
+
ALTER TABLE "DiscoveredLink" ADD CONSTRAINT "DiscoveredLink_fromScreenId_fkey"
|
|
31
|
+
FOREIGN KEY ("fromScreenId") REFERENCES "Screen"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
32
|
+
|
|
33
|
+
ALTER TABLE "DiscoveredLink" ADD CONSTRAINT "DiscoveredLink_toScreenId_fkey"
|
|
34
|
+
FOREIGN KEY ("toScreenId") REFERENCES "Screen"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
35
|
+
|
|
36
|
+
-- Indexes
|
|
37
|
+
CREATE INDEX IF NOT EXISTS "DiscoveredLink_tenantId_projectId_idx" ON "DiscoveredLink"("tenantId", "projectId");
|
|
38
|
+
CREATE INDEX IF NOT EXISTS "DiscoveredLink_tenantId_projectId_jobId_idx" ON "DiscoveredLink"("tenantId", "projectId", "jobId");
|
|
39
|
+
CREATE INDEX IF NOT EXISTS "DiscoveredLink_fromScreenId_idx" ON "DiscoveredLink"("fromScreenId");
|
|
40
|
+
CREATE INDEX IF NOT EXISTS "DiscoveredLink_toScreenId_idx" ON "DiscoveredLink"("toScreenId");
|
|
41
|
+
CREATE INDEX IF NOT EXISTS "DiscoveredLink_href_idx" ON "DiscoveredLink"("href");
|