create-m5kdev 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/src/catalog.cjs +21 -1
  2. package/dist/src/catalog.cjs.map +1 -1
  3. package/dist/src/catalog.d.cts +3 -1
  4. package/dist/src/create.cjs +6 -2
  5. package/dist/src/create.cjs.map +1 -1
  6. package/dist/src/doctor.cjs.map +1 -1
  7. package/dist/src/fs.cjs +10 -5
  8. package/dist/src/fs.cjs.map +1 -1
  9. package/dist/src/prompts.cjs +32 -0
  10. package/dist/src/prompts.cjs.map +1 -1
  11. package/dist/src/prompts.d.cts +7 -1
  12. package/dist/src/template.cjs +23 -4
  13. package/dist/src/template.cjs.map +1 -1
  14. package/dist/src/template.d.cts +17 -3
  15. package/dist/src/types.d.cts +11 -4
  16. package/package.json +4 -1
  17. package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +1 -1
  18. package/templates/minimal-app/.cursor/rules/module-grants-guide.mdc +3 -3
  19. package/templates/minimal-app/.cursor/rules/module-module-guide.mdc +3 -2
  20. package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +1 -1
  21. package/templates/minimal-app/.dockerignore.tpl +31 -0
  22. package/templates/minimal-app/.gitignore.tpl +1 -0
  23. package/templates/minimal-app/AGENTS.md.tpl +13 -10
  24. package/templates/minimal-app/CLAUDE.md.tpl +132 -131
  25. package/templates/minimal-app/README.md.tpl +50 -19
  26. package/templates/minimal-app/apps/e2e/package.json.tpl +23 -23
  27. package/templates/minimal-app/apps/e2e/playwright.config.ts.tpl +51 -39
  28. package/templates/minimal-app/apps/e2e/playwright.expo.config.ts.tpl +38 -38
  29. package/templates/minimal-app/apps/e2e/servers.ts.tpl +136 -112
  30. package/templates/minimal-app/apps/e2e/tests/conversation.spec.ts.tpl +22 -0
  31. package/templates/minimal-app/apps/e2e/tests/email.spec.ts.tpl +47 -47
  32. package/templates/minimal-app/apps/e2e/tests/expo-helpers.ts.tpl +73 -73
  33. package/templates/minimal-app/apps/e2e/tests/expo-standard.spec.ts.tpl +517 -517
  34. package/templates/minimal-app/apps/e2e/tests/expo-waitlist.spec.ts.tpl +94 -94
  35. package/templates/minimal-app/apps/e2e/tests/files.spec.ts.tpl +35 -0
  36. package/templates/minimal-app/apps/e2e/tests/helpers.ts.tpl +289 -289
  37. package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +516 -516
  38. package/templates/minimal-app/apps/e2e/tests/waitlist.spec.ts.tpl +107 -107
  39. package/templates/minimal-app/apps/e2e/tests/workflow.spec.ts.tpl +26 -0
  40. package/templates/minimal-app/apps/e2e/tsconfig.json.tpl +10 -10
  41. package/templates/minimal-app/apps/email/package.json.tpl +34 -34
  42. package/templates/minimal-app/apps/email/src/emails/trialEndingEmail.tsx.tpl +40 -0
  43. package/templates/minimal-app/apps/email/src/index.ts.tpl +7 -0
  44. package/templates/minimal-app/apps/email/src/resources.ts.tpl +72 -65
  45. package/templates/minimal-app/apps/expo/app.json.tpl +36 -36
  46. package/templates/minimal-app/apps/expo/eslint.config.js.tpl +8 -8
  47. package/templates/minimal-app/apps/expo/metro.config.js.tpl +16 -16
  48. package/templates/minimal-app/apps/expo/src/app/_layout.tsx.tpl +31 -31
  49. package/templates/minimal-app/apps/expo/src/app/claim-account.tsx.tpl +151 -151
  50. package/templates/minimal-app/apps/expo/src/app/forgot-password.tsx.tpl +53 -53
  51. package/templates/minimal-app/apps/expo/src/app/index.tsx.tpl +8 -8
  52. package/templates/minimal-app/apps/expo/src/app/login.tsx.tpl +71 -71
  53. package/templates/minimal-app/apps/expo/src/app/logout.tsx.tpl +19 -19
  54. package/templates/minimal-app/apps/expo/src/app/organization/accept-invitation.tsx.tpl +85 -85
  55. package/templates/minimal-app/apps/expo/src/app/posts.tsx.tpl +40 -40
  56. package/templates/minimal-app/apps/expo/src/app/reset-password.tsx.tpl +75 -75
  57. package/templates/minimal-app/apps/expo/src/app/signup.tsx.tpl +193 -193
  58. package/templates/minimal-app/apps/expo/src/components/AuthScaffold.tsx.tpl +34 -34
  59. package/templates/minimal-app/apps/expo/src/components/FormTextField.tsx.tpl +37 -37
  60. package/templates/minimal-app/apps/expo/src/components/LoadingScreen.tsx.tpl +10 -10
  61. package/templates/minimal-app/apps/expo/src/components/StatusText.tsx.tpl +22 -22
  62. package/templates/minimal-app/apps/expo/src/config.ts.tpl +9 -9
  63. package/templates/minimal-app/apps/expo/src/global.css.tpl +11 -11
  64. package/templates/minimal-app/apps/expo/src/lib/trpc.ts.tpl +20 -20
  65. package/templates/minimal-app/apps/expo/tsconfig.json.tpl +11 -11
  66. package/templates/minimal-app/apps/expo/uniwind-env.d.ts.tpl +1 -1
  67. package/templates/minimal-app/apps/landing/.env.production.example.tpl +7 -0
  68. package/templates/minimal-app/apps/landing/Dockerfile.tpl +39 -0
  69. package/templates/minimal-app/apps/landing/fly.toml.tpl +20 -0
  70. package/templates/minimal-app/apps/landing/index.html.tpl +35 -0
  71. package/templates/minimal-app/apps/landing/package.json.tpl +34 -0
  72. package/templates/minimal-app/apps/landing/scripts/fly-deploy.mjs.tpl +75 -0
  73. package/templates/minimal-app/apps/landing/scripts/fly-secrets.mjs.tpl +31 -0
  74. package/templates/minimal-app/apps/landing/src/App.tsx.tpl +12 -0
  75. package/templates/minimal-app/apps/landing/src/LandingPage.tsx.tpl +37 -0
  76. package/templates/minimal-app/apps/landing/src/index.css.tpl +24 -0
  77. package/templates/minimal-app/apps/landing/src/main.tsx.tpl +16 -0
  78. package/templates/minimal-app/apps/landing/src/vite-env.d.ts.tpl +11 -0
  79. package/templates/minimal-app/apps/landing/tsconfig.json.tpl +12 -0
  80. package/templates/minimal-app/apps/landing/vite.config.ts.tpl +25 -0
  81. package/templates/minimal-app/apps/server/AGENTS.md.tpl +54 -46
  82. package/templates/minimal-app/apps/server/{drizzle/seed.e2e.ts.tpl → db.e2e.ts.tpl} +57 -40
  83. package/templates/minimal-app/apps/server/{drizzle/seed.ts.tpl → db.ts.tpl} +27 -20
  84. package/templates/minimal-app/apps/server/drizzle/0003_silly_the_liberteens.sql +27 -0
  85. package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +56 -166
  86. package/templates/minimal-app/apps/server/drizzle/meta/0001_snapshot.json.tpl +1796 -1910
  87. package/templates/minimal-app/apps/server/drizzle/meta/0002_snapshot.json.tpl +1818 -1932
  88. package/templates/minimal-app/apps/server/drizzle/meta/0003_snapshot.json.tpl +2137 -0
  89. package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +8 -1
  90. package/templates/minimal-app/apps/server/drizzle.config.ts.tpl +3 -33
  91. package/templates/minimal-app/apps/server/package.json.tpl +5 -3
  92. package/templates/minimal-app/apps/server/src/app.ts.tpl +36 -0
  93. package/templates/minimal-app/apps/server/src/modules/conversation/conversation.mastra.ts.tpl +26 -0
  94. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.module.ts.tpl +47 -0
  95. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.service.ts.tpl +43 -0
  96. package/templates/minimal-app/apps/server/src/modules/demo-workflow/demo-workflow.trpc.ts.tpl +16 -0
  97. package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +28 -28
  98. package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +28 -28
  99. package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +54 -54
  100. package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +67 -67
  101. package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +116 -116
  102. package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +37 -37
  103. package/templates/minimal-app/apps/server/src/modules/test-harness/test-harness.module.ts.tpl +279 -279
  104. package/templates/minimal-app/apps/server/src/schema.ts.tpl +31 -20
  105. package/templates/minimal-app/apps/server/src/types.ts.tpl +12 -12
  106. package/templates/minimal-app/apps/server/tsconfig.json.tpl +1 -1
  107. package/templates/minimal-app/apps/server/tsup.config.ts.tpl +23 -9
  108. package/templates/minimal-app/apps/shared/.env.example.tpl +5 -0
  109. package/templates/minimal-app/apps/shared/.env.production.example.tpl +23 -0
  110. package/templates/minimal-app/apps/shared/.env.tpl +5 -0
  111. package/templates/minimal-app/apps/shared/Dockerfile.tpl +48 -0
  112. package/templates/minimal-app/apps/shared/fly.toml.tpl +24 -0
  113. package/templates/minimal-app/apps/shared/package.json.tpl +25 -24
  114. package/templates/minimal-app/apps/shared/scripts/fly-deploy.mjs.tpl +75 -0
  115. package/templates/minimal-app/apps/shared/scripts/fly-secrets.mjs.tpl +31 -0
  116. package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +28 -28
  117. package/templates/minimal-app/apps/shared/src/modules/conversation/conversation.constants.ts.tpl +1 -0
  118. package/templates/minimal-app/apps/shared/src/modules/notification/notification.schema.ts.tpl +3 -3
  119. package/templates/minimal-app/apps/shared/src/modules/posts/posts.constants.ts.tpl +5 -5
  120. package/templates/minimal-app/apps/shared/src/modules/posts/posts.schema.ts.tpl +25 -25
  121. package/templates/minimal-app/apps/webapp/package.json.tpl +53 -53
  122. package/templates/minimal-app/apps/webapp/public/push-sw.js.tpl +34 -34
  123. package/templates/minimal-app/apps/webapp/src/App.tsx.tpl +46 -44
  124. package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +96 -65
  125. package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +114 -93
  126. package/templates/minimal-app/apps/webapp/src/index.css.tpl +15 -15
  127. package/templates/minimal-app/apps/webapp/src/main.tsx.tpl +26 -26
  128. package/templates/minimal-app/apps/webapp/src/modules/conversation/ConversationRoute.tsx.tpl +36 -0
  129. package/templates/minimal-app/apps/webapp/src/modules/files/FilesRoute.tsx.tpl +88 -0
  130. package/templates/minimal-app/apps/webapp/src/modules/files/hooks/useFilesRoute.ts.tpl +50 -0
  131. package/templates/minimal-app/apps/webapp/src/modules/workflows/WorkflowsRoute.tsx.tpl +97 -0
  132. package/templates/minimal-app/apps/webapp/src/modules/workflows/hooks/useWorkflowsRoute.ts.tpl +64 -0
  133. package/templates/minimal-app/apps/webapp/src/utils/i18n.ts.tpl +13 -13
  134. package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +10 -10
  135. package/templates/minimal-app/apps/webapp/src/vite-env.d.ts.tpl +1 -1
  136. package/templates/minimal-app/apps/webapp/translations/en/app.json.tpl +7 -7
  137. package/templates/minimal-app/apps/webapp/translations/en/{{APP_SLUG}}.json.tpl +193 -135
  138. package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +17 -17
  139. package/templates/minimal-app/apps/webapp/vite.config.ts.tpl +31 -31
  140. package/templates/minimal-app/biome.json.tpl +17 -12
  141. package/templates/minimal-app/package.json.tpl +6 -2
  142. package/templates/minimal-app/pnpm-workspace.yaml.tpl +14 -7
  143. package/templates/minimal-app/template.manifest.json +92 -2
  144. package/templates/minimal-app/apps/server/drizzle/db.ts.tpl +0 -26
  145. package/templates/minimal-app/apps/server/drizzle/guard.ts.tpl +0 -36
  146. package/templates/minimal-app/apps/server/drizzle/reset.ts.tpl +0 -40
  147. package/templates/minimal-app/apps/server/drizzle/sync.ts.tpl +0 -16
@@ -1,18 +1,39 @@
1
1
  /**
2
2
  * E2E fixture seed — used only by the e2e package's prepare scripts, never by
3
3
  * generated apps (the CLI excludes this file). The user-facing demo seed lives
4
- * in ./seed.ts.
4
+ * in ./db.ts.
5
5
  */
6
+ import { type RunDbSeedContext, runDb } from "@m5kdev/backend/db";
6
7
  import { hashPassword } from "better-auth/crypto";
7
8
  import { eq } from "drizzle-orm";
8
9
  import { v4 as uuidv4 } from "uuid";
9
- import { orm, schema } from "./db";
10
- import { ensureDevServerStopped } from "./guard";
10
+ import * as schema from "./src/schema";
11
11
 
12
12
  const profile = process.env.AUTH_E2E_PROFILE ?? "standard";
13
13
  const ADMIN_EMAIL = `admin.${profile}@auth-e2e.local`;
14
14
  const ADMIN_PASSWORD = "password1234";
15
15
 
16
+ type SeedOrm = RunDbSeedContext<typeof schema>["orm"];
17
+
18
+ void runDb({
19
+ schema,
20
+ seed: async ({ orm }) => {
21
+ const admin = await ensureUser({
22
+ orm,
23
+ id: `auth-e2e-admin-${profile}`,
24
+ name: "Auth E2E Admin",
25
+ email: ADMIN_EMAIL,
26
+ password: ADMIN_PASSWORD,
27
+ role: "admin",
28
+ });
29
+ const { organizationId } = await ensureOrganization({ orm, userId: admin.id });
30
+ await seedPosts({ orm, userId: admin.id, organizationId });
31
+ await seedExpiredWaitlistCode(orm);
32
+ await seedProvisionedClaimUser(orm);
33
+ console.info(`Seeded ${profile}. Admin login: ${ADMIN_EMAIL} / ${ADMIN_PASSWORD}`);
34
+ },
35
+ });
36
+
16
37
  function slugify(value: string): string {
17
38
  return value
18
39
  .trim()
@@ -21,27 +42,24 @@ function slugify(value: string): string {
21
42
  .replace(/^-+|-+$/g, "");
22
43
  }
23
44
 
24
- async function ensureUser({
25
- id,
26
- name,
27
- email,
28
- password,
29
- role = "user",
30
- emailVerified = true,
31
- }: {
45
+ async function ensureUser(input: {
46
+ orm: SeedOrm;
32
47
  id: string;
33
48
  name: string;
34
49
  email: string;
35
50
  password?: string;
36
51
  role?: string;
37
52
  emailVerified?: boolean;
38
- }) {
53
+ }): Promise<typeof schema.users.$inferSelect> {
54
+ const { orm, id, name, email, password, role = "user", emailVerified = true } = input;
39
55
  const [existingUser] = await orm
40
56
  .select()
41
57
  .from(schema.users)
42
58
  .where(eq(schema.users.email, email))
43
59
  .limit(1);
44
- if (existingUser) return existingUser;
60
+ if (existingUser) {
61
+ return existingUser;
62
+ }
45
63
 
46
64
  const [user] = await orm
47
65
  .insert(schema.users)
@@ -56,7 +74,9 @@ async function ensureUser({
56
74
  })
57
75
  .returning();
58
76
 
59
- if (!user) throw new Error(`Failed to seed user ${email}`);
77
+ if (!user) {
78
+ throw new Error(`Failed to seed user ${email}`);
79
+ }
60
80
 
61
81
  if (password) {
62
82
  await orm.insert(schema.accounts).values({
@@ -73,7 +93,11 @@ async function ensureUser({
73
93
  return user;
74
94
  }
75
95
 
76
- async function ensureOrganization(userId: string) {
96
+ async function ensureOrganization(input: {
97
+ orm: SeedOrm;
98
+ userId: string;
99
+ }): Promise<{ organizationId: string; teamId: string }> {
100
+ const { orm, userId } = input;
77
101
  const organizationId = `auth-e2e-enterprise-${profile}`;
78
102
  const teamId = `auth-e2e-team-${profile}`;
79
103
 
@@ -144,9 +168,16 @@ async function ensureOrganization(userId: string) {
144
168
  return { organizationId, teamId };
145
169
  }
146
170
 
147
- async function seedPosts(userId: string, organizationId: string) {
171
+ async function seedPosts(input: {
172
+ orm: SeedOrm;
173
+ userId: string;
174
+ organizationId: string;
175
+ }): Promise<void> {
176
+ const { orm, userId, organizationId } = input;
148
177
  const existingPosts = await orm.select().from(schema.posts).limit(1);
149
- if (existingPosts.length > 0) return;
178
+ if (existingPosts.length > 0) {
179
+ return;
180
+ }
150
181
 
151
182
  const posts = [
152
183
  {
@@ -175,13 +206,15 @@ async function seedPosts(userId: string, organizationId: string) {
175
206
  );
176
207
  }
177
208
 
178
- async function seedExpiredWaitlistCode() {
209
+ async function seedExpiredWaitlistCode(orm: SeedOrm): Promise<void> {
179
210
  const [existing] = await orm
180
211
  .select()
181
212
  .from(schema.waitlist)
182
213
  .where(eq(schema.waitlist.code, "expired-waitlist-code"))
183
214
  .limit(1);
184
- if (existing) return;
215
+ if (existing) {
216
+ return;
217
+ }
185
218
 
186
219
  await orm.insert(schema.waitlist).values({
187
220
  id: uuidv4(),
@@ -196,8 +229,9 @@ async function seedExpiredWaitlistCode() {
196
229
  });
197
230
  }
198
231
 
199
- async function seedProvisionedClaimUser() {
232
+ async function seedProvisionedClaimUser(orm: SeedOrm): Promise<typeof schema.users.$inferSelect> {
200
233
  const user = await ensureUser({
234
+ orm,
201
235
  id: `auth-e2e-claim-user-${profile}`,
202
236
  name: "Provisioned Claim User",
203
237
  email: `claim.${profile}@provisioned.auth-e2e.local`,
@@ -210,7 +244,9 @@ async function seedProvisionedClaimUser() {
210
244
  .from(schema.waitlist)
211
245
  .where(eq(schema.waitlist.claimUserId, user.id))
212
246
  .limit(1);
213
- if (existingClaim) return user;
247
+ if (existingClaim) {
248
+ return user;
249
+ }
214
250
 
215
251
  await orm.insert(schema.waitlist).values({
216
252
  id: `auth-e2e-claim-${profile}`,
@@ -225,22 +261,3 @@ async function seedProvisionedClaimUser() {
225
261
 
226
262
  return user;
227
263
  }
228
-
229
- async function seed() {
230
- await ensureDevServerStopped();
231
- const admin = await ensureUser({
232
- id: `auth-e2e-admin-${profile}`,
233
- name: "Auth E2E Admin",
234
- email: ADMIN_EMAIL,
235
- password: ADMIN_PASSWORD,
236
- role: "admin",
237
- });
238
- const { organizationId } = await ensureOrganization(admin.id);
239
- await seedPosts(admin.id, organizationId);
240
- await seedExpiredWaitlistCode();
241
- await seedProvisionedClaimUser();
242
-
243
- console.info(`Seeded ${profile}. Admin login: ${ADMIN_EMAIL} / ${ADMIN_PASSWORD}`);
244
- }
245
-
246
- void seed();
@@ -1,15 +1,27 @@
1
+ import { type RunDbSeedContext, runDb } from "@m5kdev/backend/db";
1
2
  import { hashPassword } from "better-auth/crypto";
2
3
  import { eq } from "drizzle-orm";
3
4
  import { v4 as uuidv4 } from "uuid";
4
- import { isRemote, orm, schema } from "./db";
5
- import { ensureDevServerStopped } from "./guard";
5
+ import * as schema from "./src/schema";
6
6
 
7
7
  const DEMO_EMAIL = "admin{{PACKAGE_SCOPE}}.local";
8
8
  const DEMO_PASSWORD = "password1234";
9
9
  const ORGANIZATION_ID = "{{APP_SLUG}}-org";
10
10
  const TEAM_ID = "{{APP_SLUG}}-team";
11
11
 
12
- async function ensureDemoUser() {
12
+ void runDb({
13
+ schema,
14
+ seed: async ({ orm }) => {
15
+ const user = await ensureDemoUser(orm);
16
+ const { organizationId, teamId } = await ensureOrganization({ orm, userId: user.id });
17
+ await seedPosts({ orm, userId: user.id, organizationId, teamId });
18
+ console.info(`Seed completed. Demo login: ${DEMO_EMAIL} / ${DEMO_PASSWORD}`);
19
+ },
20
+ });
21
+
22
+ type SeedOrm = RunDbSeedContext<typeof schema>["orm"];
23
+
24
+ async function ensureDemoUser(orm: SeedOrm): Promise<typeof schema.users.$inferSelect> {
13
25
  const [existingUser] = await orm
14
26
  .select()
15
27
  .from(schema.users)
@@ -51,7 +63,11 @@ async function ensureDemoUser() {
51
63
  return user;
52
64
  }
53
65
 
54
- async function ensureOrganization(userId: string) {
66
+ async function ensureOrganization(input: {
67
+ orm: SeedOrm;
68
+ userId: string;
69
+ }): Promise<{ organizationId: string; teamId: string }> {
70
+ const { orm, userId } = input;
55
71
  const [existingOrganization] = await orm
56
72
  .select()
57
73
  .from(schema.organizations)
@@ -119,7 +135,13 @@ async function ensureOrganization(userId: string) {
119
135
  return { organizationId: ORGANIZATION_ID, teamId: TEAM_ID };
120
136
  }
121
137
 
122
- async function seedPosts(userId: string, organizationId: string | null, teamId: string | null) {
138
+ async function seedPosts(input: {
139
+ orm: SeedOrm;
140
+ userId: string;
141
+ organizationId: string | null;
142
+ teamId: string;
143
+ }): Promise<void> {
144
+ const { orm, userId, organizationId, teamId } = input;
123
145
  const existingPosts = await orm.select().from(schema.posts).limit(1);
124
146
  if (existingPosts.length > 0) {
125
147
  return;
@@ -166,18 +188,3 @@ async function seedPosts(userId: string, organizationId: string | null, teamId:
166
188
  },
167
189
  ]);
168
190
  }
169
-
170
- async function seed() {
171
- await ensureDevServerStopped();
172
- if (isRemote) {
173
- await orm.$client.sync();
174
- }
175
- const user = await ensureDemoUser();
176
- const { organizationId, teamId } = await ensureOrganization(user.id);
177
-
178
- await seedPosts(user.id, organizationId, teamId);
179
-
180
- console.info(`Seed completed. Demo login: ${DEMO_EMAIL} / ${DEMO_PASSWORD}`);
181
- }
182
-
183
- void seed();
@@ -0,0 +1,27 @@
1
+ CREATE TABLE `files` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `created_at` integer NOT NULL,
4
+ `updated_at` integer,
5
+ `deleted_at` integer,
6
+ `user_id` text,
7
+ `member_id` text,
8
+ `organization_id` text,
9
+ `team_id` text,
10
+ `bucket` text NOT NULL,
11
+ `key` text NOT NULL,
12
+ `original_name` text NOT NULL,
13
+ `original_extension` text,
14
+ `content_type` text NOT NULL,
15
+ `size_bytes` integer,
16
+ `etag` text,
17
+ `checksum_sha256` text,
18
+ `metadata` text,
19
+ `status` text NOT NULL,
20
+ `uploaded_at` integer,
21
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null,
22
+ FOREIGN KEY (`member_id`) REFERENCES `members`(`id`) ON UPDATE no action ON DELETE set null,
23
+ FOREIGN KEY (`organization_id`) REFERENCES `organizations`(`id`) ON UPDATE no action ON DELETE set null,
24
+ FOREIGN KEY (`team_id`) REFERENCES `teams`(`id`) ON UPDATE no action ON DELETE set null
25
+ );
26
+ --> statement-breakpoint
27
+ CREATE UNIQUE INDEX `files_bucket_key_unique` ON `files` (`bucket`,`key`);