@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,62 @@
|
|
|
1
|
+
-- Migration: add_requirement_model
|
|
2
|
+
-- Additive only — no existing tables modified.
|
|
3
|
+
-- Every TestCase.traceTo references a reqId from this table.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS "Requirement" (
|
|
6
|
+
"id" TEXT NOT NULL,
|
|
7
|
+
"tenantId" TEXT NOT NULL,
|
|
8
|
+
"projectId" TEXT NOT NULL,
|
|
9
|
+
"reqId" TEXT NOT NULL,
|
|
10
|
+
"title" TEXT NOT NULL,
|
|
11
|
+
"actor" TEXT,
|
|
12
|
+
"type" TEXT NOT NULL DEFAULT 'functional',
|
|
13
|
+
"priority" TEXT NOT NULL DEFAULT 'HIGH',
|
|
14
|
+
"acceptanceCriteria" JSONB NOT NULL DEFAULT '[]',
|
|
15
|
+
"businessRules" JSONB NOT NULL DEFAULT '[]',
|
|
16
|
+
"relatedScreenHints" JSONB NOT NULL DEFAULT '[]',
|
|
17
|
+
"derived" BOOLEAN NOT NULL DEFAULT false,
|
|
18
|
+
"status" TEXT NOT NULL DEFAULT 'pending',
|
|
19
|
+
"source" TEXT NOT NULL DEFAULT 'AI_GENERATED',
|
|
20
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
21
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
|
|
23
|
+
CONSTRAINT "Requirement_pkey" PRIMARY KEY ("id")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
-- Unique constraint: one reqId per project per tenant
|
|
27
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "Requirement_tenantId_projectId_reqId_key"
|
|
28
|
+
ON "Requirement"("tenantId", "projectId", "reqId");
|
|
29
|
+
|
|
30
|
+
-- General project lookup
|
|
31
|
+
CREATE INDEX IF NOT EXISTS "Requirement_tenantId_projectId_idx"
|
|
32
|
+
ON "Requirement"("tenantId", "projectId");
|
|
33
|
+
|
|
34
|
+
-- Priority-based filtering
|
|
35
|
+
CREATE INDEX IF NOT EXISTS "Requirement_tenantId_projectId_priority_idx"
|
|
36
|
+
ON "Requirement"("tenantId", "projectId", "priority");
|
|
37
|
+
|
|
38
|
+
-- Status-based filtering (covered/untested/unbuilt)
|
|
39
|
+
CREATE INDEX IF NOT EXISTS "Requirement_tenantId_projectId_status_idx"
|
|
40
|
+
ON "Requirement"("tenantId", "projectId", "status");
|
|
41
|
+
|
|
42
|
+
-- FK to Project with cascade delete
|
|
43
|
+
ALTER TABLE "Requirement"
|
|
44
|
+
ADD CONSTRAINT "Requirement_projectId_fkey"
|
|
45
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
46
|
+
|
|
47
|
+
-- Enable RLS (consistent with all other tenant tables)
|
|
48
|
+
ALTER TABLE "Requirement" ENABLE ROW LEVEL SECURITY;
|
|
49
|
+
|
|
50
|
+
-- Updated-at trigger (reuse existing function if present)
|
|
51
|
+
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
52
|
+
RETURNS TRIGGER AS $$
|
|
53
|
+
BEGIN
|
|
54
|
+
NEW."updatedAt" = CURRENT_TIMESTAMP;
|
|
55
|
+
RETURN NEW;
|
|
56
|
+
END;
|
|
57
|
+
$$ language 'plpgsql';
|
|
58
|
+
|
|
59
|
+
DROP TRIGGER IF EXISTS "Requirement_updatedAt" ON "Requirement";
|
|
60
|
+
CREATE TRIGGER "Requirement_updatedAt"
|
|
61
|
+
BEFORE UPDATE ON "Requirement"
|
|
62
|
+
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- Migration: add_invitation_model
|
|
2
|
+
-- Pending workspace invitations for users who have not registered yet.
|
|
3
|
+
-- Additive only — no existing tables modified except a NOT VALID role check on Membership.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS "Invitation" (
|
|
6
|
+
"id" TEXT NOT NULL,
|
|
7
|
+
"tenantId" TEXT NOT NULL,
|
|
8
|
+
"email" TEXT NOT NULL,
|
|
9
|
+
"role" TEXT NOT NULL,
|
|
10
|
+
"tokenHash" TEXT NOT NULL,
|
|
11
|
+
"invitedBy" TEXT,
|
|
12
|
+
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
|
13
|
+
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
14
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
15
|
+
"acceptedAt" TIMESTAMP(3),
|
|
16
|
+
|
|
17
|
+
CONSTRAINT "Invitation_pkey" PRIMARY KEY ("id"),
|
|
18
|
+
CONSTRAINT "Invitation_role_check" CHECK ("role" IN ('OWNER','ADMIN','QA_LEAD','TESTER','DEVELOPER','VIEWER')),
|
|
19
|
+
CONSTRAINT "Invitation_status_check" CHECK ("status" IN ('PENDING','ACCEPTED','REVOKED','EXPIRED'))
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "Invitation_tokenHash_key" ON "Invitation"("tokenHash");
|
|
23
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "Invitation_tenantId_email_key" ON "Invitation"("tenantId", "email");
|
|
24
|
+
CREATE INDEX IF NOT EXISTS "Invitation_tenantId_status_idx" ON "Invitation"("tenantId", "status");
|
|
25
|
+
|
|
26
|
+
ALTER TABLE "Invitation"
|
|
27
|
+
ADD CONSTRAINT "Invitation_tenantId_fkey"
|
|
28
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
29
|
+
|
|
30
|
+
-- RLS (consistent with all other tenant tables)
|
|
31
|
+
ALTER TABLE "Invitation" ENABLE ROW LEVEL SECURITY;
|
|
32
|
+
|
|
33
|
+
DO $$ BEGIN
|
|
34
|
+
IF NOT EXISTS (
|
|
35
|
+
SELECT 1 FROM pg_policies WHERE tablename = 'Invitation' AND policyname = 'tenant_isolation'
|
|
36
|
+
) THEN
|
|
37
|
+
EXECUTE format(
|
|
38
|
+
'CREATE POLICY tenant_isolation ON "Invitation" USING ("tenantId" = current_setting(''app.current_tenant'', true))'
|
|
39
|
+
);
|
|
40
|
+
END IF;
|
|
41
|
+
END $$;
|
|
42
|
+
|
|
43
|
+
-- Role integrity on Membership — NOT VALID so legacy rows are untouched,
|
|
44
|
+
-- but every new write must use a known role.
|
|
45
|
+
DO $$ BEGIN
|
|
46
|
+
IF NOT EXISTS (
|
|
47
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'Membership_role_check'
|
|
48
|
+
) THEN
|
|
49
|
+
ALTER TABLE "Membership"
|
|
50
|
+
ADD CONSTRAINT "Membership_role_check"
|
|
51
|
+
CHECK ("role" IN ('OWNER','ADMIN','QA_LEAD','TESTER','DEVELOPER','VIEWER')) NOT VALID;
|
|
52
|
+
END IF;
|
|
53
|
+
END $$;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- Migration: suite_hierarchy_artifact_trace
|
|
2
|
+
-- Additive only.
|
|
3
|
+
-- 1. TestSuite.parentId — child suites created per Section column on import.
|
|
4
|
+
-- 2. TestCase.artifactId — traceability from imported test cases back to the source artifact.
|
|
5
|
+
|
|
6
|
+
ALTER TABLE "TestSuite" ADD COLUMN IF NOT EXISTS "parentId" TEXT;
|
|
7
|
+
|
|
8
|
+
DO $$ BEGIN
|
|
9
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'TestSuite_parentId_fkey') THEN
|
|
10
|
+
ALTER TABLE "TestSuite"
|
|
11
|
+
ADD CONSTRAINT "TestSuite_parentId_fkey"
|
|
12
|
+
FOREIGN KEY ("parentId") REFERENCES "TestSuite"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
13
|
+
END IF;
|
|
14
|
+
END $$;
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS "TestSuite_parentId_idx" ON "TestSuite"("parentId");
|
|
17
|
+
|
|
18
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "artifactId" TEXT;
|
|
19
|
+
|
|
20
|
+
DO $$ BEGIN
|
|
21
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'TestCase_artifactId_fkey') THEN
|
|
22
|
+
ALTER TABLE "TestCase"
|
|
23
|
+
ADD CONSTRAINT "TestCase_artifactId_fkey"
|
|
24
|
+
FOREIGN KEY ("artifactId") REFERENCES "ProjectArtifact"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
25
|
+
END IF;
|
|
26
|
+
END $$;
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS "TestCase_artifactId_idx" ON "TestCase"("artifactId");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Migration: project_member_access
|
|
2
|
+
-- Optional per-project access list. No rows = project open to all tenant members.
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS "ProjectMember" (
|
|
5
|
+
"id" TEXT NOT NULL,
|
|
6
|
+
"tenantId" TEXT NOT NULL,
|
|
7
|
+
"projectId" TEXT NOT NULL,
|
|
8
|
+
"userId" TEXT NOT NULL,
|
|
9
|
+
|
|
10
|
+
CONSTRAINT "ProjectMember_pkey" PRIMARY KEY ("id")
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "ProjectMember_projectId_userId_key" ON "ProjectMember"("projectId", "userId");
|
|
14
|
+
CREATE INDEX IF NOT EXISTS "ProjectMember_tenantId_userId_idx" ON "ProjectMember"("tenantId", "userId");
|
|
15
|
+
|
|
16
|
+
ALTER TABLE "ProjectMember"
|
|
17
|
+
ADD CONSTRAINT "ProjectMember_projectId_fkey"
|
|
18
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
19
|
+
|
|
20
|
+
-- RLS (consistent with all other tenant tables)
|
|
21
|
+
ALTER TABLE "ProjectMember" ENABLE ROW LEVEL SECURITY;
|
|
22
|
+
|
|
23
|
+
DO $$ BEGIN
|
|
24
|
+
IF NOT EXISTS (
|
|
25
|
+
SELECT 1 FROM pg_policies WHERE tablename = 'ProjectMember' AND policyname = 'tenant_isolation'
|
|
26
|
+
) THEN
|
|
27
|
+
EXECUTE format(
|
|
28
|
+
'CREATE POLICY tenant_isolation ON "ProjectMember" USING ("tenantId" = current_setting(''app.current_tenant'', true))'
|
|
29
|
+
);
|
|
30
|
+
END IF;
|
|
31
|
+
END $$;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "SystemConfig" (
|
|
3
|
+
"key" TEXT NOT NULL,
|
|
4
|
+
"value" TEXT NOT NULL,
|
|
5
|
+
"category" TEXT NOT NULL,
|
|
6
|
+
"sensitive" BOOLEAN NOT NULL DEFAULT false,
|
|
7
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
8
|
+
"updatedByAdminId" TEXT,
|
|
9
|
+
|
|
10
|
+
CONSTRAINT "SystemConfig_pkey" PRIMARY KEY ("key")
|
|
11
|
+
);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- CreateTable: CustomRole — per-tenant custom roles with explicit permission arrays
|
|
2
|
+
CREATE TABLE "CustomRole" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"tenantId" TEXT NOT NULL,
|
|
5
|
+
"name" TEXT NOT NULL,
|
|
6
|
+
"description" TEXT,
|
|
7
|
+
"permissions" JSONB NOT NULL DEFAULT '[]',
|
|
8
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
9
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
10
|
+
|
|
11
|
+
CONSTRAINT "CustomRole_pkey" PRIMARY KEY ("id")
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
-- UniqueIndex: one name per tenant
|
|
15
|
+
CREATE UNIQUE INDEX "CustomRole_tenantId_name_key" ON "CustomRole"("tenantId", "name");
|
|
16
|
+
|
|
17
|
+
-- FK to Tenant
|
|
18
|
+
ALTER TABLE "CustomRole"
|
|
19
|
+
ADD CONSTRAINT "CustomRole_tenantId_fkey"
|
|
20
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id")
|
|
21
|
+
ON DELETE CASCADE ON UPDATE CASCADE;
|
|
22
|
+
|
|
23
|
+
-- RLS: users only see their own tenant's custom roles
|
|
24
|
+
ALTER TABLE "CustomRole" ENABLE ROW LEVEL SECURITY;
|
|
25
|
+
CREATE POLICY tenant_isolation ON "CustomRole"
|
|
26
|
+
USING (
|
|
27
|
+
"tenantId" = current_setting('app.current_tenant', true)
|
|
28
|
+
OR current_setting('app.current_tenant', true) = ''
|
|
29
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Platform Admin: separate from tenant users, no RLS, cross-tenant authority
|
|
2
|
+
CREATE TABLE "AdminUser" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"email" TEXT NOT NULL,
|
|
5
|
+
"passwordHash" TEXT NOT NULL,
|
|
6
|
+
"name" TEXT,
|
|
7
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
8
|
+
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
9
|
+
CONSTRAINT "AdminUser_pkey" PRIMARY KEY ("id")
|
|
10
|
+
);
|
|
11
|
+
CREATE UNIQUE INDEX "AdminUser_email_key" ON "AdminUser"("email");
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
-- Migration: add_extension_models
|
|
2
|
+
-- Adds ExtensionCapture, ExtensionInteraction, and ExtensionError models.
|
|
3
|
+
-- Also updates the Element model to support extension-captured elements.
|
|
4
|
+
|
|
5
|
+
-- ── Element model updates ───────────────────────────────────────────────────
|
|
6
|
+
-- Make previously required fields nullable (to support extension captures
|
|
7
|
+
-- which don't have a crawled Screen, meaning, role, or isInteractive value).
|
|
8
|
+
ALTER TABLE "Element"
|
|
9
|
+
ALTER COLUMN "screenId" DROP NOT NULL,
|
|
10
|
+
ALTER COLUMN "meaning" DROP NOT NULL,
|
|
11
|
+
ALTER COLUMN "role" DROP NOT NULL,
|
|
12
|
+
ALTER COLUMN "isInteractive" DROP NOT NULL;
|
|
13
|
+
|
|
14
|
+
-- Add extension-specific fields
|
|
15
|
+
ALTER TABLE "Element"
|
|
16
|
+
ADD COLUMN IF NOT EXISTS "selector" TEXT,
|
|
17
|
+
ADD COLUMN IF NOT EXISTS "pageUrl" TEXT,
|
|
18
|
+
ADD COLUMN IF NOT EXISTS "screenshotUrl" TEXT,
|
|
19
|
+
ADD COLUMN IF NOT EXISTS "source" TEXT NOT NULL DEFAULT 'crawl',
|
|
20
|
+
ADD COLUMN IF NOT EXISTS "metadata" JSONB;
|
|
21
|
+
|
|
22
|
+
-- Unique index for upsert from the extension
|
|
23
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "Element_ext_upsert_key"
|
|
24
|
+
ON "Element" ("tenantId", "projectId", "selector", "pageUrl");
|
|
25
|
+
|
|
26
|
+
-- ── ExtensionCapture ────────────────────────────────────────────────────────
|
|
27
|
+
CREATE TABLE IF NOT EXISTS "ExtensionCapture" (
|
|
28
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
29
|
+
"tenantId" TEXT NOT NULL,
|
|
30
|
+
"projectId" TEXT NOT NULL,
|
|
31
|
+
"kind" TEXT NOT NULL,
|
|
32
|
+
"s3Url" TEXT,
|
|
33
|
+
"entryCount" INTEGER NOT NULL DEFAULT 0,
|
|
34
|
+
"capturedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
35
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
36
|
+
"metadata" JSONB,
|
|
37
|
+
CONSTRAINT "ExtensionCapture_projectId_fkey"
|
|
38
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS "ExtensionCapture_tenantId_projectId_idx"
|
|
42
|
+
ON "ExtensionCapture" ("tenantId", "projectId");
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS "ExtensionCapture_tenantId_projectId_kind_idx"
|
|
45
|
+
ON "ExtensionCapture" ("tenantId", "projectId", "kind");
|
|
46
|
+
|
|
47
|
+
CREATE INDEX IF NOT EXISTS "ExtensionCapture_tenantId_projectId_capturedAt_idx"
|
|
48
|
+
ON "ExtensionCapture" ("tenantId", "projectId", "capturedAt");
|
|
49
|
+
|
|
50
|
+
-- ── ExtensionInteraction ────────────────────────────────────────────────────
|
|
51
|
+
CREATE TABLE IF NOT EXISTS "ExtensionInteraction" (
|
|
52
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
53
|
+
"tenantId" TEXT NOT NULL,
|
|
54
|
+
"captureId" TEXT NOT NULL,
|
|
55
|
+
"type" TEXT NOT NULL,
|
|
56
|
+
"selector" TEXT,
|
|
57
|
+
"xpath" TEXT,
|
|
58
|
+
"tagName" TEXT,
|
|
59
|
+
"value" TEXT,
|
|
60
|
+
"url" TEXT,
|
|
61
|
+
"timestamp" BIGINT,
|
|
62
|
+
"metadata" JSONB,
|
|
63
|
+
CONSTRAINT "ExtensionInteraction_captureId_fkey"
|
|
64
|
+
FOREIGN KEY ("captureId") REFERENCES "ExtensionCapture"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
CREATE INDEX IF NOT EXISTS "ExtensionInteraction_tenantId_captureId_idx"
|
|
68
|
+
ON "ExtensionInteraction" ("tenantId", "captureId");
|
|
69
|
+
|
|
70
|
+
CREATE INDEX IF NOT EXISTS "ExtensionInteraction_captureId_idx"
|
|
71
|
+
ON "ExtensionInteraction" ("captureId");
|
|
72
|
+
|
|
73
|
+
-- ── ExtensionError ──────────────────────────────────────────────────────────
|
|
74
|
+
CREATE TABLE IF NOT EXISTS "ExtensionError" (
|
|
75
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
76
|
+
"tenantId" TEXT NOT NULL,
|
|
77
|
+
"projectId" TEXT NOT NULL,
|
|
78
|
+
"pageUrl" TEXT,
|
|
79
|
+
"kind" TEXT NOT NULL,
|
|
80
|
+
"level" TEXT NOT NULL DEFAULT 'error',
|
|
81
|
+
"text" TEXT NOT NULL,
|
|
82
|
+
"url" TEXT,
|
|
83
|
+
"lineNumber" INTEGER,
|
|
84
|
+
"columnNumber" INTEGER,
|
|
85
|
+
"stackTrace" JSONB,
|
|
86
|
+
"source" TEXT,
|
|
87
|
+
"capturedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
88
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
89
|
+
CONSTRAINT "ExtensionError_projectId_fkey"
|
|
90
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX IF NOT EXISTS "ExtensionError_tenantId_projectId_idx"
|
|
94
|
+
ON "ExtensionError" ("tenantId", "projectId");
|
|
95
|
+
|
|
96
|
+
CREATE INDEX IF NOT EXISTS "ExtensionError_tenantId_projectId_pageUrl_idx"
|
|
97
|
+
ON "ExtensionError" ("tenantId", "projectId", "pageUrl");
|
|
98
|
+
|
|
99
|
+
CREATE INDEX IF NOT EXISTS "ExtensionError_tenantId_projectId_kind_idx"
|
|
100
|
+
ON "ExtensionError" ("tenantId", "projectId", "kind");
|
|
101
|
+
|
|
102
|
+
CREATE INDEX IF NOT EXISTS "ExtensionError_tenantId_projectId_level_idx"
|
|
103
|
+
ON "ExtensionError" ("tenantId", "projectId", "level");
|
|
104
|
+
|
|
105
|
+
CREATE INDEX IF NOT EXISTS "ExtensionError_tenantId_projectId_capturedAt_idx"
|
|
106
|
+
ON "ExtensionError" ("tenantId", "projectId", "capturedAt");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "Project" ADD COLUMN IF NOT EXISTS "restricted" BOOLEAN NOT NULL DEFAULT false;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CREATE INDEX "SystemConfig_category_idx" ON "SystemConfig"("category");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- Drop old workspace foreign keys and columns
|
|
2
|
+
ALTER TABLE "Tenant" DROP COLUMN IF EXISTS "workspaceId";
|
|
3
|
+
ALTER TABLE "User" DROP COLUMN IF EXISTS "workspaceId";
|
|
4
|
+
DROP TABLE IF EXISTS "Workspace" CASCADE;
|
|
5
|
+
|
|
6
|
+
-- Create new Workspace table (team/group within a Tenant)
|
|
7
|
+
CREATE TABLE "Workspace" (
|
|
8
|
+
"id" TEXT NOT NULL,
|
|
9
|
+
"tenantId" TEXT NOT NULL,
|
|
10
|
+
"name" TEXT NOT NULL,
|
|
11
|
+
"slug" TEXT NOT NULL,
|
|
12
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
CONSTRAINT "Workspace_pkey" PRIMARY KEY ("id")
|
|
14
|
+
);
|
|
15
|
+
CREATE UNIQUE INDEX "Workspace_tenantId_slug_key" ON "Workspace"("tenantId", "slug");
|
|
16
|
+
CREATE INDEX "Workspace_tenantId_idx" ON "Workspace"("tenantId");
|
|
17
|
+
ALTER TABLE "Workspace" ADD CONSTRAINT "Workspace_tenantId_fkey"
|
|
18
|
+
FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
19
|
+
|
|
20
|
+
-- Add workspaceId to Project (nullable — projects may not be in a workspace yet)
|
|
21
|
+
ALTER TABLE "Project" ADD COLUMN "workspaceId" TEXT;
|
|
22
|
+
ALTER TABLE "Project" ADD CONSTRAINT "Project_workspaceId_fkey"
|
|
23
|
+
FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
24
|
+
CREATE INDEX "Project_workspaceId_idx" ON "Project"("workspaceId");
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- Add RLS policies to Requirement and AppField tables
|
|
3
|
+
--
|
|
4
|
+
-- Both tables were created with ENABLE ROW LEVEL SECURITY but without any
|
|
5
|
+
-- policy. PostgreSQL defaults to deny-all when RLS is enabled with no
|
|
6
|
+
-- policies, causing error 42501 on any write from qip_app.
|
|
7
|
+
--
|
|
8
|
+
-- This migration adds the standard tenant_isolation policy consistent with
|
|
9
|
+
-- all other tenant-scoped tables in this project.
|
|
10
|
+
-- ============================================================================
|
|
11
|
+
|
|
12
|
+
DO $$
|
|
13
|
+
DECLARE
|
|
14
|
+
t text;
|
|
15
|
+
tables text[] := ARRAY['Requirement', 'AppField'];
|
|
16
|
+
BEGIN
|
|
17
|
+
FOREACH t IN ARRAY tables LOOP
|
|
18
|
+
-- Force RLS even for table owner (consistent with other tables)
|
|
19
|
+
EXECUTE format('ALTER TABLE "%s" FORCE ROW LEVEL SECURITY;', t);
|
|
20
|
+
|
|
21
|
+
-- Add tenant isolation policy
|
|
22
|
+
BEGIN
|
|
23
|
+
EXECUTE format($f$
|
|
24
|
+
CREATE POLICY tenant_isolation ON "%s"
|
|
25
|
+
USING ("tenantId" = current_setting('app.current_tenant', true))
|
|
26
|
+
WITH CHECK ("tenantId" = current_setting('app.current_tenant', true));
|
|
27
|
+
$f$, t);
|
|
28
|
+
EXCEPTION WHEN duplicate_object THEN
|
|
29
|
+
NULL; -- already exists, skip
|
|
30
|
+
END;
|
|
31
|
+
|
|
32
|
+
-- Ensure qip_app has table-level privileges
|
|
33
|
+
EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON "%s" TO qip_app;', t);
|
|
34
|
+
END LOOP;
|
|
35
|
+
END $$;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- OAuthConnection: ON DELETE CASCADE so deleting a project removes its OAuth connections
|
|
2
|
+
ALTER TABLE "OAuthConnection" DROP CONSTRAINT IF EXISTS "OAuthConnection_projectId_fkey";
|
|
3
|
+
ALTER TABLE "OAuthConnection" ADD CONSTRAINT "OAuthConnection_projectId_fkey"
|
|
4
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
5
|
+
|
|
6
|
+
-- AuditLog: ON DELETE SET NULL so deleting a project nullifies audit log project references
|
|
7
|
+
ALTER TABLE "AuditLog" DROP CONSTRAINT IF EXISTS "AuditLog_projectId_fkey";
|
|
8
|
+
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_projectId_fkey"
|
|
9
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- Add settings to Workspace
|
|
2
|
+
ALTER TABLE "Workspace" ADD COLUMN IF NOT EXISTS "settings" JSONB;
|
|
3
|
+
|
|
4
|
+
-- Create Scenario table
|
|
5
|
+
CREATE TABLE IF NOT EXISTS "Scenario" (
|
|
6
|
+
"id" TEXT NOT NULL,
|
|
7
|
+
"tenantId" TEXT NOT NULL,
|
|
8
|
+
"projectId" TEXT NOT NULL,
|
|
9
|
+
"requirementId" TEXT NOT NULL,
|
|
10
|
+
"title" TEXT NOT NULL,
|
|
11
|
+
"description" TEXT,
|
|
12
|
+
"gherkin" TEXT NOT NULL DEFAULT '',
|
|
13
|
+
"status" TEXT NOT NULL DEFAULT 'draft',
|
|
14
|
+
"version" INTEGER NOT NULL DEFAULT 1,
|
|
15
|
+
"source" TEXT NOT NULL DEFAULT 'AI_GENERATED',
|
|
16
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
17
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
18
|
+
CONSTRAINT "Scenario_pkey" PRIMARY KEY ("id")
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE INDEX IF NOT EXISTS "Scenario_tenantId_projectId_idx" ON "Scenario"("tenantId", "projectId");
|
|
22
|
+
CREATE INDEX IF NOT EXISTS "Scenario_requirementId_idx" ON "Scenario"("requirementId");
|
|
23
|
+
|
|
24
|
+
ALTER TABLE "Scenario" ADD CONSTRAINT "Scenario_requirementId_fkey"
|
|
25
|
+
FOREIGN KEY ("requirementId") REFERENCES "Requirement"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
26
|
+
|
|
27
|
+
-- Add scenario + suspect fields to TestCase
|
|
28
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "scenarioId" TEXT;
|
|
29
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "suspect" BOOLEAN NOT NULL DEFAULT false;
|
|
30
|
+
ALTER TABLE "TestCase" ADD COLUMN IF NOT EXISTS "suspectReason" TEXT;
|
|
31
|
+
|
|
32
|
+
CREATE INDEX IF NOT EXISTS "TestCase_scenarioId_idx" ON "TestCase"("scenarioId");
|
|
33
|
+
|
|
34
|
+
ALTER TABLE "TestCase" ADD CONSTRAINT "TestCase_scenarioId_fkey"
|
|
35
|
+
FOREIGN KEY ("scenarioId") REFERENCES "Scenario"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- RLS FOR Workspace TABLE
|
|
3
|
+
--
|
|
4
|
+
-- Workspace was missing from the initial tenant isolation migration.
|
|
5
|
+
-- Enforces the same pattern: rows only visible when tenantId matches
|
|
6
|
+
-- the app.current_tenant session variable set by withTenant().
|
|
7
|
+
-- ============================================================================
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "Workspace" ENABLE ROW LEVEL SECURITY;
|
|
10
|
+
ALTER TABLE "Workspace" FORCE ROW LEVEL SECURITY;
|
|
11
|
+
|
|
12
|
+
DO $$
|
|
13
|
+
BEGIN
|
|
14
|
+
CREATE POLICY tenant_isolation ON "Workspace"
|
|
15
|
+
USING ("tenantId" = current_setting('app.current_tenant', true))
|
|
16
|
+
WITH CHECK ("tenantId" = current_setting('app.current_tenant', true));
|
|
17
|
+
EXCEPTION WHEN duplicate_object THEN
|
|
18
|
+
NULL;
|
|
19
|
+
END $$;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
-- Add ON DELETE CASCADE to Project relations that were missing it.
|
|
2
|
+
-- Without these, deleting a Project fails with FK constraint violation.
|
|
3
|
+
|
|
4
|
+
-- Clean up orphaned rows (projectId references non-existent Project) before adding FK constraints.
|
|
5
|
+
DELETE FROM "TestData" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
6
|
+
DELETE FROM "TestScript" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
7
|
+
DELETE FROM "PlatformJob" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
8
|
+
DELETE FROM "SkillFile" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
9
|
+
DELETE FROM "ProjectArtifact" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
10
|
+
DELETE FROM "Flow" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
11
|
+
DELETE FROM "ScreenGroup" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
12
|
+
DELETE FROM "ElementFingerprint" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
13
|
+
DELETE FROM "UserSession" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
14
|
+
DELETE FROM "VisualBaseline" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
15
|
+
DELETE FROM "HumanReviewItem" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
16
|
+
DELETE FROM "TestRun" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
17
|
+
DELETE FROM "Webhook" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
18
|
+
DELETE FROM "AgentToken" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
19
|
+
DELETE FROM "ProbeObservation" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
20
|
+
DELETE FROM "ScreenDiff" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
21
|
+
DELETE FROM "ChangeLog" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
22
|
+
DELETE FROM "Connector" WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
23
|
+
-- Tables with nullable projectId → SET NULL orphaned refs instead of DELETE
|
|
24
|
+
UPDATE "LLMCallLog" SET "projectId" = NULL WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
25
|
+
UPDATE "KnowledgeChunk" SET "projectId" = NULL WHERE "projectId" IS NOT NULL AND "projectId" NOT IN (SELECT "id" FROM "Project");
|
|
26
|
+
|
|
27
|
+
-- ScreenGroup
|
|
28
|
+
ALTER TABLE "ScreenGroup" DROP CONSTRAINT IF EXISTS "ScreenGroup_projectId_fkey";
|
|
29
|
+
ALTER TABLE "ScreenGroup" ADD CONSTRAINT "ScreenGroup_projectId_fkey"
|
|
30
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
31
|
+
|
|
32
|
+
-- Flow
|
|
33
|
+
ALTER TABLE "Flow" DROP CONSTRAINT IF EXISTS "Flow_projectId_fkey";
|
|
34
|
+
ALTER TABLE "Flow" ADD CONSTRAINT "Flow_projectId_fkey"
|
|
35
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
36
|
+
|
|
37
|
+
-- SkillFile
|
|
38
|
+
ALTER TABLE "SkillFile" DROP CONSTRAINT IF EXISTS "SkillFile_projectId_fkey";
|
|
39
|
+
ALTER TABLE "SkillFile" ADD CONSTRAINT "SkillFile_projectId_fkey"
|
|
40
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
41
|
+
|
|
42
|
+
-- ProjectArtifact
|
|
43
|
+
ALTER TABLE "ProjectArtifact" DROP CONSTRAINT IF EXISTS "ProjectArtifact_projectId_fkey";
|
|
44
|
+
ALTER TABLE "ProjectArtifact" ADD CONSTRAINT "ProjectArtifact_projectId_fkey"
|
|
45
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
46
|
+
|
|
47
|
+
-- TestData
|
|
48
|
+
ALTER TABLE "TestData" DROP CONSTRAINT IF EXISTS "TestData_projectId_fkey";
|
|
49
|
+
ALTER TABLE "TestData" ADD CONSTRAINT "TestData_projectId_fkey"
|
|
50
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
51
|
+
|
|
52
|
+
-- TestScript
|
|
53
|
+
ALTER TABLE "TestScript" DROP CONSTRAINT IF EXISTS "TestScript_projectId_fkey";
|
|
54
|
+
ALTER TABLE "TestScript" ADD CONSTRAINT "TestScript_projectId_fkey"
|
|
55
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
56
|
+
|
|
57
|
+
-- PlatformJob
|
|
58
|
+
ALTER TABLE "PlatformJob" DROP CONSTRAINT IF EXISTS "PlatformJob_projectId_fkey";
|
|
59
|
+
ALTER TABLE "PlatformJob" ADD CONSTRAINT "PlatformJob_projectId_fkey"
|
|
60
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
61
|
+
|
|
62
|
+
-- ElementFingerprint
|
|
63
|
+
ALTER TABLE "ElementFingerprint" DROP CONSTRAINT IF EXISTS "ElementFingerprint_projectId_fkey";
|
|
64
|
+
ALTER TABLE "ElementFingerprint" ADD CONSTRAINT "ElementFingerprint_projectId_fkey"
|
|
65
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
66
|
+
|
|
67
|
+
-- UserSession
|
|
68
|
+
ALTER TABLE "UserSession" DROP CONSTRAINT IF EXISTS "UserSession_projectId_fkey";
|
|
69
|
+
ALTER TABLE "UserSession" ADD CONSTRAINT "UserSession_projectId_fkey"
|
|
70
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
71
|
+
|
|
72
|
+
-- VisualBaseline
|
|
73
|
+
ALTER TABLE "VisualBaseline" DROP CONSTRAINT IF EXISTS "VisualBaseline_projectId_fkey";
|
|
74
|
+
ALTER TABLE "VisualBaseline" ADD CONSTRAINT "VisualBaseline_projectId_fkey"
|
|
75
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
76
|
+
|
|
77
|
+
-- HumanReviewItem
|
|
78
|
+
ALTER TABLE "HumanReviewItem" DROP CONSTRAINT IF EXISTS "HumanReviewItem_projectId_fkey";
|
|
79
|
+
ALTER TABLE "HumanReviewItem" ADD CONSTRAINT "HumanReviewItem_projectId_fkey"
|
|
80
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
81
|
+
|
|
82
|
+
-- TestRun
|
|
83
|
+
ALTER TABLE "TestRun" DROP CONSTRAINT IF EXISTS "TestRun_projectId_fkey";
|
|
84
|
+
ALTER TABLE "TestRun" ADD CONSTRAINT "TestRun_projectId_fkey"
|
|
85
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
86
|
+
|
|
87
|
+
-- Webhook
|
|
88
|
+
ALTER TABLE "Webhook" DROP CONSTRAINT IF EXISTS "Webhook_projectId_fkey";
|
|
89
|
+
ALTER TABLE "Webhook" ADD CONSTRAINT "Webhook_projectId_fkey"
|
|
90
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
91
|
+
|
|
92
|
+
-- AgentToken
|
|
93
|
+
ALTER TABLE "AgentToken" DROP CONSTRAINT IF EXISTS "AgentToken_projectId_fkey";
|
|
94
|
+
ALTER TABLE "AgentToken" ADD CONSTRAINT "AgentToken_projectId_fkey"
|
|
95
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
96
|
+
|
|
97
|
+
-- ProbeObservation
|
|
98
|
+
ALTER TABLE "ProbeObservation" DROP CONSTRAINT IF EXISTS "ProbeObservation_projectId_fkey";
|
|
99
|
+
ALTER TABLE "ProbeObservation" ADD CONSTRAINT "ProbeObservation_projectId_fkey"
|
|
100
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
101
|
+
|
|
102
|
+
-- ScreenDiff (has screenId FK, but also projectId)
|
|
103
|
+
ALTER TABLE "ScreenDiff" DROP CONSTRAINT IF EXISTS "ScreenDiff_projectId_fkey";
|
|
104
|
+
ALTER TABLE "ScreenDiff" ADD CONSTRAINT "ScreenDiff_projectId_fkey"
|
|
105
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
106
|
+
|
|
107
|
+
-- ChangeLog
|
|
108
|
+
ALTER TABLE "ChangeLog" DROP CONSTRAINT IF EXISTS "ChangeLog_projectId_fkey";
|
|
109
|
+
ALTER TABLE "ChangeLog" ADD CONSTRAINT "ChangeLog_projectId_fkey"
|
|
110
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
111
|
+
|
|
112
|
+
-- KnowledgeChunk (nullable projectId → SetNull)
|
|
113
|
+
ALTER TABLE "KnowledgeChunk" DROP CONSTRAINT IF EXISTS "KnowledgeChunk_projectId_fkey";
|
|
114
|
+
ALTER TABLE "KnowledgeChunk" ADD CONSTRAINT "KnowledgeChunk_projectId_fkey"
|
|
115
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
116
|
+
|
|
117
|
+
-- LLMCallLog (nullable projectId → SetNull)
|
|
118
|
+
ALTER TABLE "LLMCallLog" DROP CONSTRAINT IF EXISTS "LLMCallLog_projectId_fkey";
|
|
119
|
+
ALTER TABLE "LLMCallLog" ADD CONSTRAINT "LLMCallLog_projectId_fkey"
|
|
120
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
121
|
+
|
|
122
|
+
-- Connector
|
|
123
|
+
ALTER TABLE "Connector" DROP CONSTRAINT IF EXISTS "Connector_projectId_fkey";
|
|
124
|
+
ALTER TABLE "Connector" ADD CONSTRAINT "Connector_projectId_fkey"
|
|
125
|
+
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- Adds workerId + heartbeatAt to PlatformJob: identifies which worker process
|
|
2
|
+
-- (host:pid) claimed a job, and lets the stale-job recovery sweep compare a
|
|
3
|
+
-- liveness heartbeat (bumped on every progress update) instead of startedAt,
|
|
4
|
+
-- so a slow-but-alive job isn't requeued and double-processed by another
|
|
5
|
+
-- worker just for taking a long time.
|
|
6
|
+
ALTER TABLE "PlatformJob" ADD COLUMN IF NOT EXISTS "workerId" TEXT;
|
|
7
|
+
ALTER TABLE "PlatformJob" ADD COLUMN IF NOT EXISTS "heartbeatAt" TIMESTAMP(3);
|
|
8
|
+
|
|
9
|
+
-- Speeds up the atomic claim query's `ORDER BY "queuedAt" WHERE status = 'QUEUED'`
|
|
10
|
+
-- scan and the stale-job sweep's `WHERE status = 'RUNNING' AND "heartbeatAt" < ...`.
|
|
11
|
+
CREATE INDEX IF NOT EXISTS "PlatformJob_status_queuedAt_idx" ON "PlatformJob"("status", "queuedAt");
|
|
12
|
+
CREATE INDEX IF NOT EXISTS "PlatformJob_status_heartbeatAt_idx" ON "PlatformJob"("status", "heartbeatAt");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Adds discoveryMethod to Screen: how the screen was first found during a crawl
|
|
2
|
+
-- (ENTRY_POINT | LINK_FOLLOW | SEED_URL | SKYVERN_AI). Set once at creation, never
|
|
3
|
+
-- changed on re-crawl. Powers orphan-page detection — see repository.ts's
|
|
4
|
+
-- getOrphanScreens().
|
|
5
|
+
ALTER TABLE "Screen" ADD COLUMN IF NOT EXISTS "discoveryMethod" TEXT NOT NULL DEFAULT 'LINK_FOLLOW';
|
|
6
|
+
|
|
7
|
+
CREATE INDEX IF NOT EXISTS "Screen_tenantId_projectId_discoveryMethod_idx" ON "Screen"("tenantId", "projectId", "discoveryMethod");
|