Skip to content

Commit 93826cb

Browse files
committed
migration readded
1 parent 7092c88 commit 93826cb

3 files changed

Lines changed: 11860 additions & 0 deletions

File tree

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
CREATE TYPE "public"."credential_member_role" AS ENUM('admin', 'member');--> statement-breakpoint
2+
CREATE TYPE "public"."credential_member_status" AS ENUM('active', 'pending', 'revoked');--> statement-breakpoint
3+
CREATE TYPE "public"."credential_type" AS ENUM('oauth', 'env_workspace', 'env_personal');--> statement-breakpoint
4+
CREATE TABLE "credential" (
5+
"id" text PRIMARY KEY NOT NULL,
6+
"workspace_id" text NOT NULL,
7+
"type" "credential_type" NOT NULL,
8+
"display_name" text NOT NULL,
9+
"description" text,
10+
"provider_id" text,
11+
"account_id" text,
12+
"env_key" text,
13+
"env_owner_user_id" text,
14+
"created_by" text NOT NULL,
15+
"created_at" timestamp DEFAULT now() NOT NULL,
16+
"updated_at" timestamp DEFAULT now() NOT NULL,
17+
CONSTRAINT "credential_oauth_source_check" CHECK ((type <> 'oauth') OR (account_id IS NOT NULL AND provider_id IS NOT NULL)),
18+
CONSTRAINT "credential_workspace_env_source_check" CHECK ((type <> 'env_workspace') OR (env_key IS NOT NULL AND env_owner_user_id IS NULL)),
19+
CONSTRAINT "credential_personal_env_source_check" CHECK ((type <> 'env_personal') OR (env_key IS NOT NULL AND env_owner_user_id IS NOT NULL))
20+
);
21+
--> statement-breakpoint
22+
CREATE TABLE "credential_member" (
23+
"id" text PRIMARY KEY NOT NULL,
24+
"credential_id" text NOT NULL,
25+
"user_id" text NOT NULL,
26+
"role" "credential_member_role" DEFAULT 'member' NOT NULL,
27+
"status" "credential_member_status" DEFAULT 'active' NOT NULL,
28+
"joined_at" timestamp,
29+
"invited_by" text,
30+
"created_at" timestamp DEFAULT now() NOT NULL,
31+
"updated_at" timestamp DEFAULT now() NOT NULL
32+
);
33+
--> statement-breakpoint
34+
CREATE TABLE "pending_credential_draft" (
35+
"id" text PRIMARY KEY NOT NULL,
36+
"user_id" text NOT NULL,
37+
"workspace_id" text NOT NULL,
38+
"provider_id" text NOT NULL,
39+
"display_name" text NOT NULL,
40+
"description" text,
41+
"credential_id" text,
42+
"expires_at" timestamp NOT NULL,
43+
"created_at" timestamp DEFAULT now() NOT NULL
44+
);
45+
--> statement-breakpoint
46+
DROP INDEX "account_user_provider_unique";--> statement-breakpoint
47+
ALTER TABLE "credential" ADD CONSTRAINT "credential_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
48+
ALTER TABLE "credential" ADD CONSTRAINT "credential_account_id_account_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."account"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
49+
ALTER TABLE "credential" ADD CONSTRAINT "credential_env_owner_user_id_user_id_fk" FOREIGN KEY ("env_owner_user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
50+
ALTER TABLE "credential" ADD CONSTRAINT "credential_created_by_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
51+
ALTER TABLE "credential_member" ADD CONSTRAINT "credential_member_credential_id_credential_id_fk" FOREIGN KEY ("credential_id") REFERENCES "public"."credential"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
52+
ALTER TABLE "credential_member" ADD CONSTRAINT "credential_member_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
53+
ALTER TABLE "credential_member" ADD CONSTRAINT "credential_member_invited_by_user_id_fk" FOREIGN KEY ("invited_by") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
54+
ALTER TABLE "pending_credential_draft" ADD CONSTRAINT "pending_credential_draft_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
55+
ALTER TABLE "pending_credential_draft" ADD CONSTRAINT "pending_credential_draft_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
56+
ALTER TABLE "pending_credential_draft" ADD CONSTRAINT "pending_credential_draft_credential_id_credential_id_fk" FOREIGN KEY ("credential_id") REFERENCES "public"."credential"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
57+
CREATE INDEX "credential_workspace_id_idx" ON "credential" USING btree ("workspace_id");--> statement-breakpoint
58+
CREATE INDEX "credential_type_idx" ON "credential" USING btree ("type");--> statement-breakpoint
59+
CREATE INDEX "credential_provider_id_idx" ON "credential" USING btree ("provider_id");--> statement-breakpoint
60+
CREATE INDEX "credential_account_id_idx" ON "credential" USING btree ("account_id");--> statement-breakpoint
61+
CREATE INDEX "credential_env_owner_user_id_idx" ON "credential" USING btree ("env_owner_user_id");--> statement-breakpoint
62+
CREATE UNIQUE INDEX "credential_workspace_account_unique" ON "credential" USING btree ("workspace_id","account_id") WHERE account_id IS NOT NULL;--> statement-breakpoint
63+
CREATE UNIQUE INDEX "credential_workspace_env_unique" ON "credential" USING btree ("workspace_id","type","env_key") WHERE type = 'env_workspace';--> statement-breakpoint
64+
CREATE UNIQUE INDEX "credential_workspace_personal_env_unique" ON "credential" USING btree ("workspace_id","type","env_key","env_owner_user_id") WHERE type = 'env_personal';--> statement-breakpoint
65+
CREATE INDEX "credential_member_credential_id_idx" ON "credential_member" USING btree ("credential_id");--> statement-breakpoint
66+
CREATE INDEX "credential_member_user_id_idx" ON "credential_member" USING btree ("user_id");--> statement-breakpoint
67+
CREATE INDEX "credential_member_role_idx" ON "credential_member" USING btree ("role");--> statement-breakpoint
68+
CREATE INDEX "credential_member_status_idx" ON "credential_member" USING btree ("status");--> statement-breakpoint
69+
CREATE UNIQUE INDEX "credential_member_unique" ON "credential_member" USING btree ("credential_id","user_id");--> statement-breakpoint
70+
CREATE UNIQUE INDEX "pending_draft_user_provider_ws" ON "pending_credential_draft" USING btree ("user_id","provider_id","workspace_id");
71+
--> statement-breakpoint
72+
-- ============================================================
73+
-- BACKFILL: Create credentials and members from existing data
74+
-- ============================================================
75+
76+
-- Helper CTE: all workspace members (from permissions + workspace owners)
77+
-- Used by all three backfill sections below.
78+
79+
-- ----------------------------------------------------------
80+
-- 1. OAuth credentials
81+
-- ----------------------------------------------------------
82+
-- For each (account, workspace) where account owner has workspace access,
83+
-- create a "Default <Service Name> Credential".
84+
-- Account owner = admin, other workspace members = member.
85+
86+
WITH provider_names(pid, sname) AS (
87+
VALUES
88+
('google-email', 'Gmail'),
89+
('google-drive', 'Google Drive'),
90+
('google-docs', 'Google Docs'),
91+
('google-sheets', 'Google Sheets'),
92+
('google-forms', 'Google Forms'),
93+
('google-calendar', 'Google Calendar'),
94+
('google-vault', 'Google Vault'),
95+
('google-slides', 'Google Slides'),
96+
('google-groups', 'Google Groups'),
97+
('slack', 'Slack'),
98+
('notion', 'Notion'),
99+
('confluence', 'Confluence'),
100+
('jira', 'Jira'),
101+
('jira-service-management', 'Jira Service Management'),
102+
('linear', 'Linear'),
103+
('airtable', 'Airtable'),
104+
('asana', 'Asana'),
105+
('hubspot', 'HubSpot'),
106+
('salesforce', 'Salesforce'),
107+
('pipedrive', 'Pipedrive'),
108+
('microsoft-teams', 'Microsoft Teams'),
109+
('microsoft-planner', 'Microsoft Planner'),
110+
('microsoft-excel', 'Microsoft Excel'),
111+
('outlook', 'Outlook'),
112+
('onedrive', 'OneDrive'),
113+
('sharepoint', 'SharePoint'),
114+
('dropbox', 'Dropbox'),
115+
('wordpress', 'WordPress'),
116+
('webflow', 'Webflow'),
117+
('wealthbox', 'Wealthbox'),
118+
('spotify', 'Spotify'),
119+
('x', 'X'),
120+
('reddit', 'Reddit'),
121+
('linkedin', 'LinkedIn'),
122+
('trello', 'Trello'),
123+
('shopify', 'Shopify'),
124+
('zoom', 'Zoom'),
125+
('calcom', 'Cal.com'),
126+
('discord', 'Discord'),
127+
('box', 'Box'),
128+
('github', 'GitHub')
129+
),
130+
workspace_user_access AS (
131+
SELECT DISTINCT w.id AS workspace_id, p.user_id, p.permission_type
132+
FROM "permissions" p
133+
INNER JOIN "workspace" w ON w.id = p.entity_id
134+
WHERE p.entity_type = 'workspace'
135+
UNION
136+
SELECT w.id, w.owner_id, 'admin'::"permission_type"
137+
FROM "workspace" w
138+
),
139+
oauth_creds AS (
140+
INSERT INTO "credential" (
141+
"id", "workspace_id", "type", "display_name", "provider_id", "account_id",
142+
"created_by", "created_at", "updated_at"
143+
)
144+
SELECT
145+
'cred_' || md5(wua.workspace_id || ':' || a.id) AS id,
146+
wua.workspace_id,
147+
'oauth'::"credential_type",
148+
'Default ' || COALESCE(pn.sname, a.provider_id) || ' Credential',
149+
a.provider_id,
150+
a.id,
151+
a.user_id,
152+
now(),
153+
now()
154+
FROM "account" a
155+
INNER JOIN workspace_user_access wua ON wua.user_id = a.user_id
156+
LEFT JOIN provider_names pn ON pn.pid = a.provider_id
157+
WHERE a.provider_id != 'credential'
158+
ON CONFLICT DO NOTHING
159+
RETURNING id, workspace_id, account_id
160+
)
161+
INSERT INTO "credential_member" (
162+
"id", "credential_id", "user_id", "role", "status", "joined_at", "invited_by", "created_at", "updated_at"
163+
)
164+
SELECT
165+
'credm_' || md5(oc.id || ':' || wua.user_id),
166+
oc.id,
167+
wua.user_id,
168+
CASE WHEN a.user_id = wua.user_id THEN 'admin'::"credential_member_role" ELSE 'member'::"credential_member_role" END,
169+
'active'::"credential_member_status",
170+
now(),
171+
a.user_id,
172+
now(),
173+
now()
174+
FROM oauth_creds oc
175+
INNER JOIN "account" a ON a.id = oc.account_id
176+
INNER JOIN workspace_user_access wua ON wua.workspace_id = oc.workspace_id
177+
ON CONFLICT DO NOTHING;
178+
179+
--> statement-breakpoint
180+
-- ----------------------------------------------------------
181+
-- 2. Workspace environment variable credentials
182+
-- ----------------------------------------------------------
183+
-- For each key in workspace_environment.variables JSON,
184+
-- create a credential. Workspace admins = admin, others = member.
185+
186+
WITH workspace_user_access AS (
187+
SELECT DISTINCT w.id AS workspace_id, p.user_id, p.permission_type
188+
FROM "permissions" p
189+
INNER JOIN "workspace" w ON w.id = p.entity_id
190+
WHERE p.entity_type = 'workspace'
191+
UNION
192+
SELECT w.id, w.owner_id, 'admin'::"permission_type"
193+
FROM "workspace" w
194+
),
195+
ws_env_keys AS (
196+
SELECT
197+
we.workspace_id,
198+
key AS env_key,
199+
w.owner_id
200+
FROM "workspace_environment" we
201+
INNER JOIN "workspace" w ON w.id = we.workspace_id
202+
CROSS JOIN LATERAL json_object_keys(we.variables::json) AS key
203+
),
204+
ws_env_creds AS (
205+
INSERT INTO "credential" (
206+
"id", "workspace_id", "type", "display_name", "env_key",
207+
"created_by", "created_at", "updated_at"
208+
)
209+
SELECT
210+
'cred_' || md5(wek.workspace_id || ':env_workspace:' || wek.env_key),
211+
wek.workspace_id,
212+
'env_workspace'::"credential_type",
213+
wek.env_key,
214+
wek.env_key,
215+
wek.owner_id,
216+
now(),
217+
now()
218+
FROM ws_env_keys wek
219+
ON CONFLICT DO NOTHING
220+
RETURNING id, workspace_id
221+
)
222+
INSERT INTO "credential_member" (
223+
"id", "credential_id", "user_id", "role", "status", "joined_at", "invited_by", "created_at", "updated_at"
224+
)
225+
SELECT
226+
'credm_' || md5(wec.id || ':' || wua.user_id),
227+
wec.id,
228+
wua.user_id,
229+
CASE WHEN wua.permission_type = 'admin' THEN 'admin'::"credential_member_role" ELSE 'member'::"credential_member_role" END,
230+
'active'::"credential_member_status",
231+
now(),
232+
(SELECT w.owner_id FROM "workspace" w WHERE w.id = wec.workspace_id LIMIT 1),
233+
now(),
234+
now()
235+
FROM ws_env_creds wec
236+
INNER JOIN workspace_user_access wua ON wua.workspace_id = wec.workspace_id
237+
ON CONFLICT DO NOTHING;
238+
239+
--> statement-breakpoint
240+
-- ----------------------------------------------------------
241+
-- 3. Personal environment variable credentials
242+
-- ----------------------------------------------------------
243+
-- For each key in environment.variables JSON, for each workspace
244+
-- the user belongs to, create a credential with the user as admin.
245+
246+
WITH workspace_user_access AS (
247+
SELECT DISTINCT w.id AS workspace_id, p.user_id
248+
FROM "permissions" p
249+
INNER JOIN "workspace" w ON w.id = p.entity_id
250+
WHERE p.entity_type = 'workspace'
251+
UNION
252+
SELECT w.id, w.owner_id
253+
FROM "workspace" w
254+
),
255+
personal_env_keys AS (
256+
SELECT
257+
e.user_id,
258+
key AS env_key
259+
FROM "environment" e
260+
CROSS JOIN LATERAL json_object_keys(e.variables::json) AS key
261+
),
262+
personal_env_creds AS (
263+
INSERT INTO "credential" (
264+
"id", "workspace_id", "type", "display_name", "env_key", "env_owner_user_id",
265+
"created_by", "created_at", "updated_at"
266+
)
267+
SELECT
268+
'cred_' || md5(wua.workspace_id || ':env_personal:' || pek.env_key || ':' || pek.user_id),
269+
wua.workspace_id,
270+
'env_personal'::"credential_type",
271+
pek.env_key,
272+
pek.env_key,
273+
pek.user_id,
274+
pek.user_id,
275+
now(),
276+
now()
277+
FROM personal_env_keys pek
278+
INNER JOIN workspace_user_access wua ON wua.user_id = pek.user_id
279+
ON CONFLICT DO NOTHING
280+
RETURNING id, workspace_id
281+
)
282+
INSERT INTO "credential_member" (
283+
"id", "credential_id", "user_id", "role", "status", "joined_at", "invited_by", "created_at", "updated_at"
284+
)
285+
SELECT
286+
'credm_' || md5(pec.id || ':' || c.env_owner_user_id),
287+
pec.id,
288+
c.env_owner_user_id,
289+
'admin'::"credential_member_role",
290+
'active'::"credential_member_status",
291+
now(),
292+
c.env_owner_user_id,
293+
now(),
294+
now()
295+
FROM personal_env_creds pec
296+
INNER JOIN "credential" c ON c.id = pec.id
297+
ON CONFLICT DO NOTHING;

0 commit comments

Comments
 (0)