@actuate-media/cms-core 0.51.0 → 0.51.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.
@@ -1,39 +0,0 @@
1
- -- CreateTable
2
- CREATE TABLE "actuate_folders" (
3
- "id" TEXT NOT NULL,
4
- "name" TEXT NOT NULL,
5
- "scope" TEXT NOT NULL,
6
- "parentId" TEXT,
7
- "position" INTEGER NOT NULL DEFAULT 0,
8
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
- "updatedAt" TIMESTAMP(3) NOT NULL,
10
-
11
- CONSTRAINT "actuate_folders_pkey" PRIMARY KEY ("id")
12
- );
13
-
14
- -- CreateIndex
15
- CREATE INDEX "actuate_folders_scope_idx" ON "actuate_folders"("scope");
16
-
17
- -- CreateIndex
18
- CREATE INDEX "actuate_folders_parentId_idx" ON "actuate_folders"("parentId");
19
-
20
- -- AddForeignKey (self-relation for nesting)
21
- ALTER TABLE "actuate_folders" ADD CONSTRAINT "actuate_folders_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "actuate_folders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
22
-
23
- -- AlterTable: add folderId to documents
24
- ALTER TABLE "actuate_documents" ADD COLUMN "folderId" TEXT;
25
-
26
- -- CreateIndex
27
- CREATE INDEX "actuate_documents_folderId_idx" ON "actuate_documents"("folderId");
28
-
29
- -- AddForeignKey
30
- ALTER TABLE "actuate_documents" ADD CONSTRAINT "actuate_documents_folderId_fkey" FOREIGN KEY ("folderId") REFERENCES "actuate_folders"("id") ON DELETE SET NULL ON UPDATE CASCADE;
31
-
32
- -- AlterTable: add folderId to media
33
- ALTER TABLE "actuate_media" ADD COLUMN "folderId" TEXT;
34
-
35
- -- CreateIndex
36
- CREATE INDEX "actuate_media_folderId_idx" ON "actuate_media"("folderId");
37
-
38
- -- AddForeignKey
39
- ALTER TABLE "actuate_media" ADD CONSTRAINT "actuate_media_folderId_fkey" FOREIGN KEY ("folderId") REFERENCES "actuate_folders"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -1,50 +0,0 @@
1
- -- Full-text search: GIN index on documents for fast ts_vector queries
2
- CREATE INDEX IF NOT EXISTS "idx_actuate_documents_fts"
3
- ON "actuate_documents"
4
- USING GIN (to_tsvector('english', COALESCE("title", '') || ' ' || COALESCE("plainText", '')));
5
-
6
- -- Webhook endpoints table
7
- CREATE TABLE IF NOT EXISTS "actuate_webhook_endpoints" (
8
- "id" TEXT NOT NULL,
9
- "url" TEXT NOT NULL,
10
- "events" JSONB NOT NULL,
11
- "secret" TEXT NOT NULL,
12
- "active" BOOLEAN NOT NULL DEFAULT true,
13
- "name" TEXT,
14
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
15
- "updatedAt" TIMESTAMP(3) NOT NULL,
16
-
17
- CONSTRAINT "actuate_webhook_endpoints_pkey" PRIMARY KEY ("id")
18
- );
19
-
20
- -- Webhook delivery log table
21
- CREATE TABLE IF NOT EXISTS "actuate_webhook_deliveries" (
22
- "id" TEXT NOT NULL,
23
- "endpointId" TEXT NOT NULL,
24
- "event" TEXT NOT NULL,
25
- "payload" JSONB NOT NULL,
26
- "status" TEXT NOT NULL DEFAULT 'pending',
27
- "attempts" INTEGER NOT NULL DEFAULT 0,
28
- "maxAttempts" INTEGER NOT NULL DEFAULT 3,
29
- "lastAttemptAt" TIMESTAMP(3),
30
- "nextRetryAt" TIMESTAMP(3),
31
- "responseStatus" INTEGER,
32
- "responseBody" TEXT,
33
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
34
-
35
- CONSTRAINT "actuate_webhook_deliveries_pkey" PRIMARY KEY ("id")
36
- );
37
-
38
- CREATE INDEX IF NOT EXISTS "actuate_webhook_deliveries_endpointId_idx"
39
- ON "actuate_webhook_deliveries"("endpointId");
40
-
41
- CREATE INDEX IF NOT EXISTS "actuate_webhook_deliveries_status_idx"
42
- ON "actuate_webhook_deliveries"("status");
43
-
44
- CREATE INDEX IF NOT EXISTS "actuate_webhook_deliveries_nextRetryAt_idx"
45
- ON "actuate_webhook_deliveries"("nextRetryAt");
46
-
47
- ALTER TABLE "actuate_webhook_deliveries"
48
- ADD CONSTRAINT "actuate_webhook_deliveries_endpointId_fkey"
49
- FOREIGN KEY ("endpointId") REFERENCES "actuate_webhook_endpoints"("id")
50
- ON DELETE CASCADE ON UPDATE CASCADE;
@@ -1,21 +0,0 @@
1
- -- CreateTable
2
- CREATE TABLE "actuate_script_tags" (
3
- "id" TEXT NOT NULL,
4
- "name" TEXT NOT NULL,
5
- "code" TEXT NOT NULL,
6
- "placement" TEXT NOT NULL,
7
- "scope" TEXT NOT NULL,
8
- "targetPaths" TEXT[],
9
- "priority" INTEGER NOT NULL DEFAULT 100,
10
- "enabled" BOOLEAN NOT NULL DEFAULT true,
11
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
- "updatedAt" TIMESTAMP(3) NOT NULL,
13
-
14
- CONSTRAINT "actuate_script_tags_pkey" PRIMARY KEY ("id")
15
- );
16
-
17
- -- CreateIndex
18
- CREATE INDEX "actuate_script_tags_enabled_idx" ON "actuate_script_tags"("enabled");
19
-
20
- -- CreateIndex
21
- CREATE INDEX "actuate_script_tags_placement_idx" ON "actuate_script_tags"("placement");
@@ -1,20 +0,0 @@
1
- -- CreateTable
2
- CREATE TABLE "actuate_password_reset_tokens" (
3
- "id" TEXT NOT NULL,
4
- "userId" TEXT NOT NULL,
5
- "tokenHash" TEXT NOT NULL,
6
- "expiresAt" TIMESTAMP(3) NOT NULL,
7
- "usedAt" TIMESTAMP(3),
8
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
-
10
- CONSTRAINT "actuate_password_reset_tokens_pkey" PRIMARY KEY ("id")
11
- );
12
-
13
- -- CreateIndex
14
- CREATE INDEX "actuate_password_reset_tokens_tokenHash_idx" ON "actuate_password_reset_tokens"("tokenHash");
15
-
16
- -- CreateIndex
17
- CREATE INDEX "actuate_password_reset_tokens_userId_idx" ON "actuate_password_reset_tokens"("userId");
18
-
19
- -- AddForeignKey
20
- ALTER TABLE "actuate_password_reset_tokens" ADD CONSTRAINT "actuate_password_reset_tokens_userId_fkey" FOREIGN KEY ("userId") REFERENCES "actuate_users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -1,38 +0,0 @@
1
- -- CreateTable
2
- CREATE TABLE "actuate_page_templates" (
3
- "id" TEXT NOT NULL,
4
- "name" TEXT NOT NULL,
5
- "description" TEXT,
6
- "category" TEXT NOT NULL DEFAULT 'content',
7
- "tree" JSONB NOT NULL,
8
- "thumbnail" TEXT,
9
- "builtIn" BOOLEAN NOT NULL DEFAULT false,
10
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
11
- "updatedAt" TIMESTAMP(3) NOT NULL,
12
-
13
- CONSTRAINT "actuate_page_templates_pkey" PRIMARY KEY ("id")
14
- );
15
-
16
- -- CreateTable
17
- CREATE TABLE "actuate_saved_sections" (
18
- "id" TEXT NOT NULL,
19
- "name" TEXT NOT NULL,
20
- "description" TEXT,
21
- "category" TEXT NOT NULL DEFAULT 'content',
22
- "tree" JSONB NOT NULL,
23
- "thumbnail" TEXT,
24
- "usageCount" INTEGER NOT NULL DEFAULT 0,
25
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
26
- "updatedAt" TIMESTAMP(3) NOT NULL,
27
-
28
- CONSTRAINT "actuate_saved_sections_pkey" PRIMARY KEY ("id")
29
- );
30
-
31
- -- CreateIndex
32
- CREATE INDEX "actuate_page_templates_category_idx" ON "actuate_page_templates"("category");
33
-
34
- -- CreateIndex
35
- CREATE INDEX "actuate_page_templates_builtIn_idx" ON "actuate_page_templates"("builtIn");
36
-
37
- -- CreateIndex
38
- CREATE INDEX "actuate_saved_sections_category_idx" ON "actuate_saved_sections"("category");
@@ -1,74 +0,0 @@
1
- -- Dashboard metrics & content health
2
- --
3
- -- Adds two tables that back the redesigned admin Dashboard:
4
- -- * actuate_api_request_metrics — per-minute pre-aggregated request
5
- -- counters with a fixed log-scale latency histogram, sized to keep
6
- -- a week of traffic in O(minutes × routes × status-buckets) rows.
7
- -- * actuate_content_issues — persisted content-quality issues
8
- -- produced by the nightly content-health scanner. Upserted by
9
- -- (documentId, type) so the scanner is idempotent.
10
- --
11
- -- Both tables are safe to add to a populated database: they have no
12
- -- backfill dependency and no constraints that touch existing rows.
13
-
14
- -- ---------------------------------------------------------------------------
15
- -- ContentIssueType enum
16
- -- ---------------------------------------------------------------------------
17
- CREATE TYPE "ContentIssueType" AS ENUM (
18
- 'MISSING_META_DESCRIPTION',
19
- 'MISSING_ALT_TEXT',
20
- 'BROKEN_INTERNAL_LINK',
21
- 'OUTDATED_CONTENT'
22
- );
23
-
24
- -- ---------------------------------------------------------------------------
25
- -- actuate_api_request_metrics
26
- -- ---------------------------------------------------------------------------
27
- CREATE TABLE "actuate_api_request_metrics" (
28
- "id" TEXT NOT NULL,
29
- "bucketStart" TIMESTAMP(3) NOT NULL,
30
- "route" TEXT NOT NULL,
31
- "statusBucket" TEXT NOT NULL,
32
- "count" INTEGER NOT NULL DEFAULT 0,
33
- "sumLatencyMs" DOUBLE PRECISION NOT NULL DEFAULT 0,
34
- "maxLatencyMs" DOUBLE PRECISION NOT NULL DEFAULT 0,
35
- "latencyHistogram" JSONB NOT NULL,
36
- "updatedAt" TIMESTAMP(3) NOT NULL,
37
-
38
- CONSTRAINT "actuate_api_request_metrics_pkey" PRIMARY KEY ("id")
39
- );
40
-
41
- CREATE UNIQUE INDEX "actuate_api_request_metrics_bucketStart_route_statusBucket_key"
42
- ON "actuate_api_request_metrics" ("bucketStart", "route", "statusBucket");
43
-
44
- CREATE INDEX "actuate_api_request_metrics_bucketStart_idx"
45
- ON "actuate_api_request_metrics" ("bucketStart");
46
-
47
- -- ---------------------------------------------------------------------------
48
- -- actuate_content_issues
49
- -- ---------------------------------------------------------------------------
50
- CREATE TABLE "actuate_content_issues" (
51
- "id" TEXT NOT NULL,
52
- "documentId" TEXT NOT NULL,
53
- "type" "ContentIssueType" NOT NULL,
54
- "count" INTEGER NOT NULL DEFAULT 1,
55
- "details" JSONB,
56
- "firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
57
- "lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
58
-
59
- CONSTRAINT "actuate_content_issues_pkey" PRIMARY KEY ("id"),
60
- CONSTRAINT "actuate_content_issues_documentId_fkey"
61
- FOREIGN KEY ("documentId")
62
- REFERENCES "actuate_documents"("id")
63
- ON DELETE CASCADE
64
- ON UPDATE CASCADE
65
- );
66
-
67
- CREATE UNIQUE INDEX "actuate_content_issues_documentId_type_key"
68
- ON "actuate_content_issues" ("documentId", "type");
69
-
70
- CREATE INDEX "actuate_content_issues_type_idx"
71
- ON "actuate_content_issues" ("type");
72
-
73
- CREATE INDEX "actuate_content_issues_documentId_idx"
74
- ON "actuate_content_issues" ("documentId");
@@ -1,47 +0,0 @@
1
- -- Media Center
2
- --
3
- -- Extends actuate_media with the metadata the Media Center needs: SEO fields
4
- -- (caption / description / focusKeyword), provenance (originalFileName), a
5
- -- normalised storage split (publicUrl / storageProvider), media processing
6
- -- artefacts (thumbnailUrl / responsiveVariants / durationSeconds), a tags
7
- -- bag, soft-delete (deletedAt), and a processing status.
8
- --
9
- -- SEO score and issues are deliberately NOT persisted — they are derived on
10
- -- read by `calculateMediaSeoScore()` so they never drift from the metadata.
11
- --
12
- -- Safe to apply to a populated database:
13
- -- * Every new column is nullable or has a default — no backfill required.
14
- -- * `status` defaults to READY so existing rows are immediately valid.
15
- -- * No existing column is dropped or retyped.
16
-
17
- -- ---------------------------------------------------------------------------
18
- -- MediaStatus enum
19
- -- ---------------------------------------------------------------------------
20
- CREATE TYPE "MediaStatus" AS ENUM (
21
- 'PROCESSING',
22
- 'READY',
23
- 'FAILED'
24
- );
25
-
26
- -- ---------------------------------------------------------------------------
27
- -- actuate_media new columns
28
- -- ---------------------------------------------------------------------------
29
- ALTER TABLE "actuate_media"
30
- ADD COLUMN "originalFileName" TEXT,
31
- ADD COLUMN "caption" TEXT,
32
- ADD COLUMN "description" TEXT,
33
- ADD COLUMN "focusKeyword" TEXT,
34
- ADD COLUMN "tags" JSONB,
35
- ADD COLUMN "publicUrl" TEXT,
36
- ADD COLUMN "storageProvider" TEXT,
37
- ADD COLUMN "durationSeconds" DOUBLE PRECISION,
38
- ADD COLUMN "thumbnailUrl" TEXT,
39
- ADD COLUMN "responsiveVariants" JSONB,
40
- ADD COLUMN "status" "MediaStatus" NOT NULL DEFAULT 'READY',
41
- ADD COLUMN "deletedAt" TIMESTAMP(3);
42
-
43
- -- ---------------------------------------------------------------------------
44
- -- Indexes backing the new query filters (soft-delete + type filtering)
45
- -- ---------------------------------------------------------------------------
46
- CREATE INDEX "actuate_media_deletedAt_idx" ON "actuate_media" ("deletedAt");
47
- CREATE INDEX "actuate_media_mimeType_idx" ON "actuate_media" ("mimeType");
@@ -1,143 +0,0 @@
1
- -- SEO Operations Center
2
- --
3
- -- Adds the persistence layer for the SEO module:
4
- -- * Redirect: runtime + management columns (enabled, priority, preserveQuery,
5
- -- source_kind, hits, lastHitAt, createdById).
6
- -- * SeoAuditRun: one row per audit execution (score + issue-count snapshot).
7
- -- * SeoIssue: detected SEO problems, status carried across runs via issueKey.
8
- -- * Redirect404Hit: aggregated 404 traffic observed by the middleware.
9
- -- * RedirectSuggestion: confidence-scored 404 recovery / chain suggestions.
10
- --
11
- -- Safe to apply to a populated database:
12
- -- * Every new Redirect column is nullable or has a default — no backfill.
13
- -- * New tables/enums are additive; no existing column is dropped or retyped.
14
-
15
- -- ---------------------------------------------------------------------------
16
- -- Enums
17
- -- ---------------------------------------------------------------------------
18
- CREATE TYPE "SeoAuditStatus" AS ENUM ('RUNNING', 'COMPLETED', 'FAILED');
19
- CREATE TYPE "SeoIssueSeverity" AS ENUM ('critical', 'warning', 'info');
20
- CREATE TYPE "SeoIssueStatus" AS ENUM ('open', 'ignored', 'resolved', 'recurring');
21
- CREATE TYPE "SeoIssueCategory" AS ENUM (
22
- 'content', 'technical', 'redirects', 'media',
23
- 'performance', 'schema', 'social', 'indexing'
24
- );
25
-
26
- -- ---------------------------------------------------------------------------
27
- -- actuate_redirects new columns
28
- -- ---------------------------------------------------------------------------
29
- ALTER TABLE "actuate_redirects"
30
- ADD COLUMN "enabled" BOOLEAN NOT NULL DEFAULT true,
31
- ADD COLUMN "priority" INTEGER NOT NULL DEFAULT 0,
32
- ADD COLUMN "preserveQuery" BOOLEAN NOT NULL DEFAULT false,
33
- ADD COLUMN "source_kind" TEXT NOT NULL DEFAULT 'manual',
34
- ADD COLUMN "hits" INTEGER NOT NULL DEFAULT 0,
35
- ADD COLUMN "lastHitAt" TIMESTAMP(3),
36
- ADD COLUMN "createdById" TEXT;
37
-
38
- CREATE INDEX "actuate_redirects_enabled_idx" ON "actuate_redirects" ("enabled");
39
- CREATE INDEX "actuate_redirects_lastHitAt_idx" ON "actuate_redirects" ("lastHitAt");
40
-
41
- -- ---------------------------------------------------------------------------
42
- -- actuate_seo_audit_runs
43
- -- ---------------------------------------------------------------------------
44
- CREATE TABLE "actuate_seo_audit_runs" (
45
- "id" TEXT NOT NULL,
46
- "status" "SeoAuditStatus" NOT NULL DEFAULT 'RUNNING',
47
- "scope" TEXT NOT NULL DEFAULT 'full',
48
- "startedById" TEXT,
49
- "startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
50
- "finishedAt" TIMESTAMP(3),
51
- "siteScoreBefore" INTEGER,
52
- "siteScoreAfter" INTEGER,
53
- "pagesScanned" INTEGER NOT NULL DEFAULT 0,
54
- "issuesFound" INTEGER NOT NULL DEFAULT 0,
55
- "criticalCount" INTEGER NOT NULL DEFAULT 0,
56
- "warningCount" INTEGER NOT NULL DEFAULT 0,
57
- "infoCount" INTEGER NOT NULL DEFAULT 0,
58
- "errorMessage" TEXT,
59
- "metadata" JSONB,
60
- CONSTRAINT "actuate_seo_audit_runs_pkey" PRIMARY KEY ("id")
61
- );
62
-
63
- CREATE INDEX "actuate_seo_audit_runs_status_idx" ON "actuate_seo_audit_runs" ("status");
64
- CREATE INDEX "actuate_seo_audit_runs_startedAt_idx" ON "actuate_seo_audit_runs" ("startedAt");
65
-
66
- -- ---------------------------------------------------------------------------
67
- -- actuate_seo_issues
68
- -- ---------------------------------------------------------------------------
69
- CREATE TABLE "actuate_seo_issues" (
70
- "id" TEXT NOT NULL,
71
- "auditRunId" TEXT,
72
- "issueKey" TEXT NOT NULL,
73
- "entityType" TEXT,
74
- "entityId" TEXT,
75
- "entityTitle" TEXT,
76
- "url" TEXT,
77
- "severity" "SeoIssueSeverity" NOT NULL,
78
- "category" "SeoIssueCategory" NOT NULL,
79
- "type" TEXT NOT NULL,
80
- "title" TEXT NOT NULL,
81
- "description" TEXT,
82
- "impact" TEXT,
83
- "recommendation" TEXT,
84
- "status" "SeoIssueStatus" NOT NULL DEFAULT 'open',
85
- "fixable" BOOLEAN NOT NULL DEFAULT false,
86
- "fixActionType" TEXT,
87
- "relatedEntityIds" JSONB,
88
- "source" TEXT NOT NULL DEFAULT 'audit',
89
- "firstDetectedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
90
- "lastDetectedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
91
- "resolvedAt" TIMESTAMP(3),
92
- "resolvedById" TEXT,
93
- "metadata" JSONB,
94
- CONSTRAINT "actuate_seo_issues_pkey" PRIMARY KEY ("id")
95
- );
96
-
97
- CREATE INDEX "actuate_seo_issues_auditRunId_idx" ON "actuate_seo_issues" ("auditRunId");
98
- CREATE INDEX "actuate_seo_issues_status_idx" ON "actuate_seo_issues" ("status");
99
- CREATE INDEX "actuate_seo_issues_severity_idx" ON "actuate_seo_issues" ("severity");
100
- CREATE INDEX "actuate_seo_issues_category_idx" ON "actuate_seo_issues" ("category");
101
- CREATE INDEX "actuate_seo_issues_issueKey_idx" ON "actuate_seo_issues" ("issueKey");
102
-
103
- ALTER TABLE "actuate_seo_issues"
104
- ADD CONSTRAINT "actuate_seo_issues_auditRunId_fkey"
105
- FOREIGN KEY ("auditRunId") REFERENCES "actuate_seo_audit_runs"("id")
106
- ON DELETE SET NULL ON UPDATE CASCADE;
107
-
108
- -- ---------------------------------------------------------------------------
109
- -- actuate_redirect_404_hits
110
- -- ---------------------------------------------------------------------------
111
- CREATE TABLE "actuate_redirect_404_hits" (
112
- "id" TEXT NOT NULL,
113
- "path" TEXT NOT NULL,
114
- "hits" INTEGER NOT NULL DEFAULT 1,
115
- "referrer" TEXT,
116
- "resolvedAt" TIMESTAMP(3),
117
- "firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
118
- "lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
119
- CONSTRAINT "actuate_redirect_404_hits_pkey" PRIMARY KEY ("id")
120
- );
121
-
122
- CREATE UNIQUE INDEX "actuate_redirect_404_hits_path_key" ON "actuate_redirect_404_hits" ("path");
123
- CREATE INDEX "actuate_redirect_404_hits_lastSeenAt_idx" ON "actuate_redirect_404_hits" ("lastSeenAt");
124
-
125
- -- ---------------------------------------------------------------------------
126
- -- actuate_redirect_suggestions
127
- -- ---------------------------------------------------------------------------
128
- CREATE TABLE "actuate_redirect_suggestions" (
129
- "id" TEXT NOT NULL,
130
- "fromPath" TEXT NOT NULL,
131
- "toPath" TEXT NOT NULL,
132
- "confidence" INTEGER NOT NULL DEFAULT 0,
133
- "reason" TEXT,
134
- "status" TEXT NOT NULL DEFAULT 'open',
135
- "source" TEXT NOT NULL DEFAULT 'ai-404-recovery',
136
- "metadata" JSONB,
137
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
138
- "updatedAt" TIMESTAMP(3) NOT NULL,
139
- CONSTRAINT "actuate_redirect_suggestions_pkey" PRIMARY KEY ("id")
140
- );
141
-
142
- CREATE INDEX "actuate_redirect_suggestions_status_idx" ON "actuate_redirect_suggestions" ("status");
143
- CREATE INDEX "actuate_redirect_suggestions_fromPath_idx" ON "actuate_redirect_suggestions" ("fromPath");
@@ -1,130 +0,0 @@
1
- -- Forms system
2
- --
3
- -- Expands the Forms feature from a single flat submissions table into a real
4
- -- submission workflow with schema versioning, per-submission file attachments,
5
- -- and per-form webhooks.
6
- --
7
- -- * actuate_form_submissions: new workflow columns (entryNumber, sender*,
8
- -- unread/starred/archived, spamStatus, attribution metadata, schema version
9
- -- link, normalizedData, read/archived timestamps, updatedAt).
10
- -- * actuate_form_schema_versions: versioned field-schema snapshots so old
11
- -- submissions always render against the schema they were captured with.
12
- -- * actuate_form_submission_files: file-upload metadata (storage keys, not
13
- -- blobs) with cascade delete from its submission.
14
- -- * actuate_form_webhooks: per-form signed outbound webhooks.
15
- --
16
- -- Safe to apply to a populated database:
17
- -- * Every new column on actuate_form_submissions is nullable or has a default.
18
- -- * updatedAt is backfilled from createdAt for existing rows before the NOT
19
- -- NULL default takes over for new rows.
20
- -- * No existing column is dropped or retyped. formId stays a loose string
21
- -- (no new FK) so historical rows with orphaned formIds are not rejected.
22
-
23
- -- ---------------------------------------------------------------------------
24
- -- actuate_form_submissions new columns
25
- -- ---------------------------------------------------------------------------
26
- ALTER TABLE "actuate_form_submissions"
27
- ADD COLUMN "entryNumber" INTEGER,
28
- ADD COLUMN "schemaVersionId" TEXT,
29
- ADD COLUMN "normalizedData" JSONB,
30
- ADD COLUMN "senderName" TEXT,
31
- ADD COLUMN "senderEmail" TEXT,
32
- ADD COLUMN "senderPhone" TEXT,
33
- ADD COLUMN "preview" TEXT,
34
- ADD COLUMN "unread" BOOLEAN NOT NULL DEFAULT true,
35
- ADD COLUMN "starred" BOOLEAN NOT NULL DEFAULT false,
36
- ADD COLUMN "archived" BOOLEAN NOT NULL DEFAULT false,
37
- ADD COLUMN "spamStatus" TEXT NOT NULL DEFAULT 'clean',
38
- ADD COLUMN "ipAddressHash" TEXT,
39
- ADD COLUMN "userAgent" TEXT,
40
- ADD COLUMN "referrer" TEXT,
41
- ADD COLUMN "pageUrl" TEXT,
42
- ADD COLUMN "utmSource" TEXT,
43
- ADD COLUMN "utmMedium" TEXT,
44
- ADD COLUMN "utmCampaign" TEXT,
45
- ADD COLUMN "readAt" TIMESTAMP(3),
46
- ADD COLUMN "archivedAt" TIMESTAMP(3),
47
- ADD COLUMN "updatedAt" TIMESTAMP(3);
48
-
49
- -- Backfill updatedAt for existing rows, then enforce NOT NULL with a default
50
- -- so new inserts (and Prisma's @updatedAt) always have a value.
51
- UPDATE "actuate_form_submissions" SET "updatedAt" = "createdAt" WHERE "updatedAt" IS NULL;
52
- ALTER TABLE "actuate_form_submissions"
53
- ALTER COLUMN "updatedAt" SET NOT NULL,
54
- ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP;
55
-
56
- -- Existing rows predate the read/unread workflow; treat them as already read so
57
- -- they don't all light up as unread in the new inbox.
58
- UPDATE "actuate_form_submissions" SET "unread" = false WHERE "status" <> 'new';
59
-
60
- CREATE INDEX "actuate_form_submissions_unread_idx" ON "actuate_form_submissions" ("unread");
61
- CREATE INDEX "actuate_form_submissions_starred_idx" ON "actuate_form_submissions" ("starred");
62
- CREATE INDEX "actuate_form_submissions_archived_idx" ON "actuate_form_submissions" ("archived");
63
- CREATE INDEX "actuate_form_submissions_spamStatus_idx" ON "actuate_form_submissions" ("spamStatus");
64
- CREATE INDEX "actuate_form_submissions_submittedAt_idx" ON "actuate_form_submissions" ("submittedAt");
65
- CREATE INDEX "actuate_form_submissions_senderEmail_idx" ON "actuate_form_submissions" ("senderEmail");
66
-
67
- -- ---------------------------------------------------------------------------
68
- -- actuate_form_schema_versions
69
- -- ---------------------------------------------------------------------------
70
- CREATE TABLE "actuate_form_schema_versions" (
71
- "id" TEXT NOT NULL,
72
- "formId" TEXT NOT NULL,
73
- "version" INTEGER NOT NULL,
74
- "fields" JSONB NOT NULL,
75
- "notes" TEXT,
76
- "createdById" TEXT,
77
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
78
- CONSTRAINT "actuate_form_schema_versions_pkey" PRIMARY KEY ("id")
79
- );
80
-
81
- CREATE UNIQUE INDEX "actuate_form_schema_versions_formId_version_key"
82
- ON "actuate_form_schema_versions" ("formId", "version");
83
- CREATE INDEX "actuate_form_schema_versions_formId_idx"
84
- ON "actuate_form_schema_versions" ("formId");
85
-
86
- -- ---------------------------------------------------------------------------
87
- -- actuate_form_submission_files
88
- -- ---------------------------------------------------------------------------
89
- CREATE TABLE "actuate_form_submission_files" (
90
- "id" TEXT NOT NULL,
91
- "submissionId" TEXT NOT NULL,
92
- "fieldKey" TEXT NOT NULL,
93
- "mediaAssetId" TEXT,
94
- "fileName" TEXT NOT NULL,
95
- "mimeType" TEXT NOT NULL,
96
- "sizeBytes" INTEGER NOT NULL,
97
- "storageKey" TEXT NOT NULL,
98
- "publicUrl" TEXT,
99
- "secureDownloadUrl" TEXT,
100
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
101
- CONSTRAINT "actuate_form_submission_files_pkey" PRIMARY KEY ("id")
102
- );
103
-
104
- CREATE INDEX "actuate_form_submission_files_submissionId_idx"
105
- ON "actuate_form_submission_files" ("submissionId");
106
-
107
- ALTER TABLE "actuate_form_submission_files"
108
- ADD CONSTRAINT "actuate_form_submission_files_submissionId_fkey"
109
- FOREIGN KEY ("submissionId") REFERENCES "actuate_form_submissions"("id")
110
- ON DELETE CASCADE ON UPDATE CASCADE;
111
-
112
- -- ---------------------------------------------------------------------------
113
- -- actuate_form_webhooks
114
- -- ---------------------------------------------------------------------------
115
- CREATE TABLE "actuate_form_webhooks" (
116
- "id" TEXT NOT NULL,
117
- "formId" TEXT NOT NULL,
118
- "url" TEXT NOT NULL,
119
- "secret" TEXT NOT NULL,
120
- "enabled" BOOLEAN NOT NULL DEFAULT true,
121
- "events" JSONB NOT NULL,
122
- "retryCount" INTEGER NOT NULL DEFAULT 0,
123
- "lastDeliveryAt" TIMESTAMP(3),
124
- "lastDeliveryStatus" TEXT,
125
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
126
- "updatedAt" TIMESTAMP(3) NOT NULL,
127
- CONSTRAINT "actuate_form_webhooks_pkey" PRIMARY KEY ("id")
128
- );
129
-
130
- CREATE INDEX "actuate_form_webhooks_formId_idx" ON "actuate_form_webhooks" ("formId");
@@ -1,6 +0,0 @@
1
- -- AlterEnum
2
- -- Add OWNER and VIEWER to the UserRole enum. These are appended (Postgres
3
- -- ALTER TYPE ... ADD VALUE appends), and must be committed in their own
4
- -- migration before any later statement references the new values.
5
- ALTER TYPE "UserRole" ADD VALUE IF NOT EXISTS 'OWNER';
6
- ALTER TYPE "UserRole" ADD VALUE IF NOT EXISTS 'VIEWER';
@@ -1,40 +0,0 @@
1
- -- CreateEnum
2
- CREATE TYPE "InviteStatus" AS ENUM ('PENDING', 'ACCEPTED', 'EXPIRED', 'CANCELLED');
3
-
4
- -- AlterTable: access-control lifecycle columns (all additive, nullable/defaulted)
5
- ALTER TABLE "actuate_users" ADD COLUMN "suspendedAt" TIMESTAMP(3);
6
- ALTER TABLE "actuate_users" ADD COLUMN "lockedAt" TIMESTAMP(3);
7
- ALTER TABLE "actuate_users" ADD COLUMN "forcePasswordReset" BOOLEAN NOT NULL DEFAULT false;
8
- ALTER TABLE "actuate_users" ADD COLUMN "mfaRequired" BOOLEAN NOT NULL DEFAULT false;
9
- ALTER TABLE "actuate_users" ADD COLUMN "failedLoginCount" INTEGER NOT NULL DEFAULT 0;
10
- ALTER TABLE "actuate_users" ADD COLUMN "lastActiveAt" TIMESTAMP(3);
11
- ALTER TABLE "actuate_users" ADD COLUMN "invitedById" TEXT;
12
- ALTER TABLE "actuate_users" ADD COLUMN "acceptedInviteAt" TIMESTAMP(3);
13
-
14
- -- CreateTable
15
- CREATE TABLE "actuate_invites" (
16
- "id" TEXT NOT NULL,
17
- "email" TEXT NOT NULL,
18
- "role" "UserRole" NOT NULL,
19
- "status" "InviteStatus" NOT NULL DEFAULT 'PENDING',
20
- "tokenHash" TEXT NOT NULL,
21
- "message" TEXT,
22
- "invitedByUserId" TEXT,
23
- "acceptedUserId" TEXT,
24
- "expiresAt" TIMESTAMP(3) NOT NULL,
25
- "acceptedAt" TIMESTAMP(3),
26
- "cancelledAt" TIMESTAMP(3),
27
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
28
- "updatedAt" TIMESTAMP(3) NOT NULL,
29
-
30
- CONSTRAINT "actuate_invites_pkey" PRIMARY KEY ("id")
31
- );
32
-
33
- -- CreateIndex
34
- CREATE INDEX "actuate_invites_email_idx" ON "actuate_invites"("email");
35
-
36
- -- CreateIndex
37
- CREATE INDEX "actuate_invites_tokenHash_idx" ON "actuate_invites"("tokenHash");
38
-
39
- -- CreateIndex
40
- CREATE INDEX "actuate_invites_status_idx" ON "actuate_invites"("status");