create-chaaskit 0.1.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 (122) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +25 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/add-infra.d.ts +6 -0
  6. package/dist/commands/add-infra.d.ts.map +1 -0
  7. package/dist/commands/add-infra.js +160 -0
  8. package/dist/commands/add-infra.js.map +1 -0
  9. package/dist/commands/build.d.ts +2 -0
  10. package/dist/commands/build.d.ts.map +1 -0
  11. package/dist/commands/build.js +63 -0
  12. package/dist/commands/build.js.map +1 -0
  13. package/dist/commands/db-sync.d.ts +13 -0
  14. package/dist/commands/db-sync.d.ts.map +1 -0
  15. package/dist/commands/db-sync.js +108 -0
  16. package/dist/commands/db-sync.js.map +1 -0
  17. package/dist/commands/dev.d.ts +7 -0
  18. package/dist/commands/dev.d.ts.map +1 -0
  19. package/dist/commands/dev.js +61 -0
  20. package/dist/commands/dev.js.map +1 -0
  21. package/dist/commands/init.d.ts +9 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +214 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +57 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/templates/.env.example +24 -0
  30. package/dist/templates/README.md +81 -0
  31. package/dist/templates/app/components/AcceptInviteClient.tsx +10 -0
  32. package/dist/templates/app/components/AdminDashboardClient.tsx +10 -0
  33. package/dist/templates/app/components/AdminTeamClient.tsx +10 -0
  34. package/dist/templates/app/components/AdminTeamsClient.tsx +10 -0
  35. package/dist/templates/app/components/AdminUsersClient.tsx +10 -0
  36. package/dist/templates/app/components/ApiKeysClient.tsx +10 -0
  37. package/dist/templates/app/components/AutomationsClient.tsx +10 -0
  38. package/dist/templates/app/components/ChatClient.tsx +13 -0
  39. package/dist/templates/app/components/ClientOnly.tsx +6 -0
  40. package/dist/templates/app/components/DocumentsClient.tsx +10 -0
  41. package/dist/templates/app/components/OAuthConsentClient.tsx +10 -0
  42. package/dist/templates/app/components/PricingClient.tsx +10 -0
  43. package/dist/templates/app/components/TeamSettingsClient.tsx +10 -0
  44. package/dist/templates/app/components/VerifyEmailClient.tsx +10 -0
  45. package/dist/templates/app/entry.client.tsx +12 -0
  46. package/dist/templates/app/entry.server.tsx +67 -0
  47. package/dist/templates/app/root.tsx +91 -0
  48. package/dist/templates/app/routes/_index.tsx +82 -0
  49. package/dist/templates/app/routes/admin._index.tsx +57 -0
  50. package/dist/templates/app/routes/admin.teams.$teamId.tsx +57 -0
  51. package/dist/templates/app/routes/admin.teams._index.tsx +57 -0
  52. package/dist/templates/app/routes/admin.users.tsx +57 -0
  53. package/dist/templates/app/routes/api-keys.tsx +57 -0
  54. package/dist/templates/app/routes/automations.tsx +57 -0
  55. package/dist/templates/app/routes/chat._index.tsx +11 -0
  56. package/dist/templates/app/routes/chat.admin._index.tsx +10 -0
  57. package/dist/templates/app/routes/chat.admin.teams.$teamId.tsx +10 -0
  58. package/dist/templates/app/routes/chat.admin.teams._index.tsx +10 -0
  59. package/dist/templates/app/routes/chat.admin.users.tsx +10 -0
  60. package/dist/templates/app/routes/chat.api-keys.tsx +10 -0
  61. package/dist/templates/app/routes/chat.automations.tsx +10 -0
  62. package/dist/templates/app/routes/chat.documents.tsx +10 -0
  63. package/dist/templates/app/routes/chat.team.$teamId.settings.tsx +10 -0
  64. package/dist/templates/app/routes/chat.thread.$threadId.tsx +11 -0
  65. package/dist/templates/app/routes/chat.tsx +39 -0
  66. package/dist/templates/app/routes/documents.tsx +57 -0
  67. package/dist/templates/app/routes/invite.$token.tsx +10 -0
  68. package/dist/templates/app/routes/login.tsx +334 -0
  69. package/dist/templates/app/routes/oauth.consent.tsx +10 -0
  70. package/dist/templates/app/routes/pricing.tsx +10 -0
  71. package/dist/templates/app/routes/privacy.tsx +197 -0
  72. package/dist/templates/app/routes/register.tsx +398 -0
  73. package/dist/templates/app/routes/shared.$shareId.tsx +226 -0
  74. package/dist/templates/app/routes/team.$teamId.settings.tsx +57 -0
  75. package/dist/templates/app/routes/terms.tsx +173 -0
  76. package/dist/templates/app/routes/thread.$threadId.tsx +102 -0
  77. package/dist/templates/app/routes/verify-email.tsx +10 -0
  78. package/dist/templates/app/routes.ts +47 -0
  79. package/dist/templates/config/app.config.ts +216 -0
  80. package/dist/templates/docs/admin.md +257 -0
  81. package/dist/templates/docs/api-keys.md +403 -0
  82. package/dist/templates/docs/authentication.md +247 -0
  83. package/dist/templates/docs/configuration.md +1212 -0
  84. package/dist/templates/docs/custom-pages.md +466 -0
  85. package/dist/templates/docs/deployment.md +362 -0
  86. package/dist/templates/docs/development.md +411 -0
  87. package/dist/templates/docs/documents.md +293 -0
  88. package/dist/templates/docs/extensions.md +639 -0
  89. package/dist/templates/docs/index.md +139 -0
  90. package/dist/templates/docs/installation.md +286 -0
  91. package/dist/templates/docs/mcp.md +952 -0
  92. package/dist/templates/docs/native-tools.md +688 -0
  93. package/dist/templates/docs/queue.md +514 -0
  94. package/dist/templates/docs/scheduled-prompts.md +279 -0
  95. package/dist/templates/docs/settings.md +415 -0
  96. package/dist/templates/docs/slack.md +318 -0
  97. package/dist/templates/docs/styling.md +288 -0
  98. package/dist/templates/extensions/agents/.gitkeep +0 -0
  99. package/dist/templates/extensions/pages/.gitkeep +0 -0
  100. package/dist/templates/extensions/payment-plans/.gitkeep +0 -0
  101. package/dist/templates/index.html +16 -0
  102. package/dist/templates/infra-aws/.github/workflows/deploy.yml +95 -0
  103. package/dist/templates/infra-aws/README.md +207 -0
  104. package/dist/templates/infra-aws/bin/cdk.ts +18 -0
  105. package/dist/templates/infra-aws/cdk.json +43 -0
  106. package/dist/templates/infra-aws/config/deployment.ts +156 -0
  107. package/dist/templates/infra-aws/lib/chaaskit-stack.ts +419 -0
  108. package/dist/templates/infra-aws/package.json +27 -0
  109. package/dist/templates/infra-aws/scripts/build-app.sh +63 -0
  110. package/dist/templates/infra-aws/tsconfig.json +25 -0
  111. package/dist/templates/package.json +46 -0
  112. package/dist/templates/prisma/schema/base.prisma +584 -0
  113. package/dist/templates/prisma/schema/custom.prisma +24 -0
  114. package/dist/templates/prisma/schema.prisma +271 -0
  115. package/dist/templates/public/favicon.svg +4 -0
  116. package/dist/templates/public/logo.svg +4 -0
  117. package/dist/templates/react-router.config.ts +11 -0
  118. package/dist/templates/server.js +52 -0
  119. package/dist/templates/src/main.tsx +8 -0
  120. package/dist/templates/tsconfig.json +26 -0
  121. package/dist/templates/vite.config.ts +26 -0
  122. package/package.json +46 -0
@@ -0,0 +1,584 @@
1
+ // =============================================================================
2
+ // Base Schema - @chat-saas/db
3
+ // =============================================================================
4
+ // This file contains the core models provided by @chat-saas/db.
5
+ // DO NOT MODIFY THIS FILE - it will be overwritten by `chat-saas-server db:sync`.
6
+ //
7
+ // For custom models, create or edit `custom.prisma` in this same directory.
8
+ // =============================================================================
9
+
10
+ generator client {
11
+ provider = "prisma-client-js"
12
+ }
13
+
14
+ datasource db {
15
+ provider = "postgresql"
16
+ url = env("DATABASE_URL")
17
+ }
18
+
19
+ model User {
20
+ id String @id @default(cuid())
21
+ email String @unique
22
+ passwordHash String?
23
+ name String?
24
+ avatarUrl String?
25
+
26
+ // Auth
27
+ emailVerified Boolean @default(false)
28
+ oauthProvider String?
29
+ oauthId String?
30
+
31
+ // Admin flag
32
+ isAdmin Boolean @default(false)
33
+
34
+ // Subscription
35
+ plan String @default("free")
36
+ stripeCustomerId String? @unique
37
+ credits Int @default(0)
38
+ messagesThisMonth Int @default(0)
39
+
40
+ // User settings/context (JSON)
41
+ settings Json @default("{}")
42
+ themePreference String?
43
+
44
+ // Relations
45
+ threads Thread[]
46
+ projects Project[]
47
+ teamMemberships TeamMember[]
48
+ feedback MessageFeedback[]
49
+ templates PromptTemplate[]
50
+ magicLinks MagicLink[]
51
+ mcpCredentials MCPCredential[]
52
+ apiKeys ApiKey[]
53
+ documents Document[]
54
+
55
+ // OAuth relations
56
+ oauthClients OAuthClient[]
57
+ oauthAuthCodes OAuthAuthorizationCode[]
58
+ oauthTokens OAuthToken[]
59
+
60
+ // Scheduled prompts
61
+ scheduledPrompts ScheduledPrompt[]
62
+
63
+ // Email verification
64
+ emailVerifications EmailVerification[]
65
+
66
+ createdAt DateTime @default(now())
67
+ updatedAt DateTime @updatedAt
68
+
69
+ @@index([email])
70
+ @@index([stripeCustomerId])
71
+ }
72
+
73
+ model Thread {
74
+ id String @id @default(cuid())
75
+ title String @default("New Chat")
76
+ userId String?
77
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
78
+
79
+ // Agent used for this thread (null = default agent)
80
+ agentId String?
81
+
82
+ // For team threads
83
+ teamId String?
84
+ team Team? @relation(fields: [teamId], references: [id], onDelete: SetNull)
85
+
86
+ // For project threads
87
+ projectId String?
88
+ project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
89
+
90
+ // Branching support
91
+ parentThreadId String?
92
+ parentMessageId String?
93
+ parentThread Thread? @relation("ThreadBranches", fields: [parentThreadId], references: [id], onDelete: SetNull)
94
+ branches Thread[] @relation("ThreadBranches")
95
+
96
+ // Archived threads (hidden but preserved)
97
+ archivedAt DateTime?
98
+
99
+ // Relations
100
+ messages Message[]
101
+ sharedLinks SharedThread[]
102
+ slackEvents SlackMessageEvent[]
103
+ scheduledPrompts ScheduledPrompt[]
104
+
105
+ createdAt DateTime @default(now())
106
+ updatedAt DateTime @updatedAt
107
+
108
+ @@index([userId])
109
+ @@index([teamId])
110
+ @@index([projectId])
111
+ @@index([parentThreadId])
112
+ @@index([agentId])
113
+ }
114
+
115
+ model Message {
116
+ id String @id @default(cuid())
117
+ threadId String
118
+ thread Thread @relation(fields: [threadId], references: [id], onDelete: Cascade)
119
+ role String // 'user' | 'assistant' | 'system'
120
+ content String
121
+
122
+ // File attachments (JSON array)
123
+ files Json?
124
+
125
+ // Tool calls and results (JSON)
126
+ toolCalls Json?
127
+ toolResults Json?
128
+
129
+ // Token usage
130
+ inputTokens Int?
131
+ outputTokens Int?
132
+
133
+ // Relations
134
+ feedback MessageFeedback[]
135
+
136
+ createdAt DateTime @default(now())
137
+
138
+ @@index([threadId])
139
+ @@index([createdAt])
140
+ }
141
+
142
+ model MessageFeedback {
143
+ id String @id @default(cuid())
144
+ messageId String
145
+ message Message @relation(fields: [messageId], references: [id], onDelete: Cascade)
146
+ userId String
147
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
148
+ type String // 'up' | 'down'
149
+ comment String?
150
+ createdAt DateTime @default(now())
151
+
152
+ @@unique([messageId, userId])
153
+ @@index([messageId])
154
+ }
155
+
156
+ model SharedThread {
157
+ id String @id @default(cuid())
158
+ shareId String @unique @default(cuid())
159
+ threadId String
160
+ thread Thread @relation(fields: [threadId], references: [id], onDelete: Cascade)
161
+ expiresAt DateTime?
162
+ createdAt DateTime @default(now())
163
+
164
+ @@index([shareId])
165
+ @@index([threadId])
166
+ }
167
+
168
+ model PromptTemplate {
169
+ id String @id @default(cuid())
170
+ userId String
171
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
172
+ name String
173
+ prompt String
174
+ variables Json @default("[]")
175
+ createdAt DateTime @default(now())
176
+ updatedAt DateTime @updatedAt
177
+
178
+ @@index([userId])
179
+ }
180
+
181
+ model MagicLink {
182
+ id String @id @default(cuid())
183
+ token String @unique
184
+ userId String
185
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
186
+ expiresAt DateTime
187
+ usedAt DateTime?
188
+ createdAt DateTime @default(now())
189
+
190
+ @@index([token])
191
+ @@index([userId])
192
+ }
193
+
194
+ model PasswordReset {
195
+ id String @id @default(cuid())
196
+ token String @unique
197
+ email String
198
+ expiresAt DateTime
199
+ usedAt DateTime?
200
+ createdAt DateTime @default(now())
201
+
202
+ @@index([token])
203
+ @@index([email])
204
+ }
205
+
206
+ // Projects - organizational folders for threads with AI context
207
+ model Project {
208
+ id String @id @default(cuid())
209
+ name String
210
+ context String? // AI context for project threads
211
+ color String // hex color from preset list
212
+ sharing String @default("private") // 'private' | 'team'
213
+ userId String // creator
214
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
215
+ teamId String? // optional team association
216
+ team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
217
+ threads Thread[]
218
+ documents Document[]
219
+ archivedAt DateTime? // null = active, set = archived
220
+ createdAt DateTime @default(now())
221
+ updatedAt DateTime @updatedAt
222
+
223
+ @@index([userId])
224
+ @@index([teamId])
225
+ }
226
+
227
+ // Team workspaces
228
+ model Team {
229
+ id String @id @default(cuid())
230
+ name String
231
+ context String? // Additional context passed to AI agent for team threads
232
+ archivedAt DateTime? // null = active, set = archived
233
+
234
+ // Billing fields
235
+ plan String @default("free")
236
+ stripeCustomerId String? @unique
237
+ credits Int @default(0)
238
+ messagesThisMonth Int @default(0)
239
+
240
+ members TeamMember[]
241
+ threads Thread[]
242
+ projects Project[]
243
+ invites TeamInvite[]
244
+ apiKeys ApiKey[]
245
+ documents Document[]
246
+ slackIntegration SlackIntegration?
247
+ scheduledPrompts ScheduledPrompt[]
248
+ createdAt DateTime @default(now())
249
+ updatedAt DateTime @updatedAt
250
+
251
+ @@index([stripeCustomerId])
252
+ }
253
+
254
+ model TeamMember {
255
+ id String @id @default(cuid())
256
+ teamId String
257
+ team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
258
+ userId String
259
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
260
+ role String // 'owner' | 'admin' | 'member' | 'viewer'
261
+
262
+ createdAt DateTime @default(now())
263
+
264
+ @@unique([teamId, userId])
265
+ @@index([teamId])
266
+ @@index([userId])
267
+ }
268
+
269
+ model TeamInvite {
270
+ id String @id @default(cuid())
271
+ teamId String
272
+ team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
273
+ email String
274
+ role String // 'admin' | 'member' | 'viewer'
275
+ token String @unique
276
+ invitedBy String
277
+ expiresAt DateTime
278
+ acceptedAt DateTime?
279
+ createdAt DateTime @default(now())
280
+
281
+ @@unique([teamId, email])
282
+ @@index([token])
283
+ }
284
+
285
+ // MCP Server Credentials
286
+ model MCPCredential {
287
+ id String @id @default(cuid())
288
+ userId String
289
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
290
+ serverId String
291
+ credentialType String // 'api_key' | 'oauth'
292
+ encryptedData String // Encrypted JSON: {apiKey} or {accessToken, refreshToken, expiresAt}
293
+ oauthState String? // Temporary state during OAuth flow
294
+ codeVerifier String? // PKCE verifier (encrypted)
295
+ createdAt DateTime @default(now())
296
+ updatedAt DateTime @updatedAt
297
+
298
+ @@unique([userId, serverId])
299
+ @@index([userId])
300
+ }
301
+
302
+ // API Keys for programmatic access
303
+ model ApiKey {
304
+ id String @id @default(cuid())
305
+ userId String
306
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
307
+ teamId String? // Optional: if set, key operates in team context
308
+ team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
309
+ name String // User-provided label, e.g. "My CLI Tool"
310
+ keyPrefix String // First 10 chars for display: "sk-abc123..."
311
+ keyHash String // bcrypt hash of full key
312
+ lastUsedAt DateTime?
313
+ expiresAt DateTime? // Optional expiration
314
+ createdAt DateTime @default(now())
315
+
316
+ @@index([userId])
317
+ @@index([teamId])
318
+ @@index([keyPrefix]) // For lookup during auth
319
+ }
320
+
321
+ // OAuth Client Registration for MCP Server (RFC 7591)
322
+ model OAuthClient {
323
+ id String @id @default(cuid())
324
+ clientId String @unique // Public client ID
325
+ clientSecretHash String? // bcrypt hash (for confidential clients)
326
+ clientName String
327
+ clientUri String?
328
+ redirectUris String // JSON array of allowed redirect URIs
329
+ grantTypes String @default("[\"authorization_code\",\"refresh_token\"]")
330
+ responseTypes String @default("[\"code\"]")
331
+ tokenEndpointAuth String @default("none") // "none", "client_secret_basic", "client_secret_post"
332
+ isActive Boolean @default(true)
333
+
334
+ // For user-registered clients (null = dynamic registration)
335
+ userId String?
336
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
337
+
338
+ createdAt DateTime @default(now())
339
+ updatedAt DateTime @updatedAt
340
+
341
+ // Relations
342
+ tokens OAuthToken[]
343
+ authCodes OAuthAuthorizationCode[]
344
+
345
+ @@index([clientId])
346
+ @@index([userId])
347
+ }
348
+
349
+ // OAuth Authorization Codes (short-lived, for auth code flow)
350
+ model OAuthAuthorizationCode {
351
+ id String @id @default(cuid())
352
+ code String @unique
353
+ clientId String
354
+ client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
355
+ userId String
356
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
357
+ redirectUri String
358
+ scope String?
359
+ codeChallenge String // PKCE code challenge
360
+ codeChallengeMethod String @default("S256")
361
+ expiresAt DateTime
362
+ usedAt DateTime?
363
+ createdAt DateTime @default(now())
364
+
365
+ @@index([code])
366
+ @@index([clientId])
367
+ @@index([userId])
368
+ }
369
+
370
+ // OAuth Access/Refresh Tokens
371
+ model OAuthToken {
372
+ id String @id @default(cuid())
373
+ tokenHash String @unique // Hash of access token
374
+ refreshTokenHash String? @unique // Hash of refresh token
375
+ clientId String
376
+ client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
377
+ userId String
378
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
379
+ scope String?
380
+ expiresAt DateTime
381
+ refreshExpiresAt DateTime?
382
+ revokedAt DateTime?
383
+ createdAt DateTime @default(now())
384
+
385
+ @@index([tokenHash])
386
+ @@index([refreshTokenHash])
387
+ @@index([clientId])
388
+ @@index([userId])
389
+ }
390
+
391
+ // Document storage for @-mentionable resources
392
+ model Document {
393
+ id String @id @default(cuid())
394
+ name String // Unique within scope
395
+ content String? @db.Text // For small text docs (stored in DB)
396
+ storageKey String? // For file storage provider (filesystem/S3)
397
+ mimeType String @default("text/plain")
398
+ fileSize Int @default(0)
399
+ charCount Int @default(0) // For hybrid threshold
400
+
401
+ userId String
402
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
403
+ teamId String?
404
+ team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
405
+ projectId String?
406
+ project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
407
+
408
+ createdAt DateTime @default(now())
409
+ updatedAt DateTime @updatedAt
410
+ archivedAt DateTime?
411
+
412
+ @@unique([userId, name, teamId, projectId]) // Unique name per scope
413
+ @@index([userId])
414
+ @@index([teamId])
415
+ @@index([projectId])
416
+ }
417
+
418
+ // Slack Integration - connects a team to their Slack workspace
419
+ model SlackIntegration {
420
+ id String @id @default(cuid())
421
+
422
+ // Team relationship (one-to-one)
423
+ teamId String @unique
424
+ team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
425
+
426
+ // Slack workspace info
427
+ slackWorkspaceId String @unique // Slack's team/workspace ID (T01234567)
428
+ slackWorkspaceName String // Human-readable workspace name
429
+ slackBotUserId String // Bot's user ID for @mention detection
430
+
431
+ // Encrypted credentials
432
+ encryptedTokens String // AES-encrypted JSON: {botToken, accessToken?}
433
+
434
+ // Per-team settings
435
+ notificationChannel String? // Default channel for notifications (#general)
436
+ aiChatEnabled Boolean @default(true)
437
+
438
+ // Status tracking
439
+ status String @default("active") // 'active' | 'disconnected' | 'error'
440
+ statusMessage String? // Error details if status='error'
441
+
442
+ // Audit
443
+ installedBy String // User ID who installed
444
+ installedAt DateTime @default(now())
445
+ updatedAt DateTime @updatedAt
446
+
447
+ // Relations
448
+ messageEvents SlackMessageEvent[]
449
+
450
+ @@index([teamId])
451
+ @@index([slackWorkspaceId])
452
+ }
453
+
454
+ // Slack Message Events - tracks incoming events for deduplication and retry
455
+ model SlackMessageEvent {
456
+ id String @id @default(cuid())
457
+
458
+ // Integration relationship
459
+ integrationId String
460
+ integration SlackIntegration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
461
+
462
+ // Slack message identifiers
463
+ slackEventId String @unique // Slack's event_id for deduplication
464
+ slackChannelId String // Channel ID (C01234567)
465
+ slackThreadTs String? // Parent message timestamp (for threads)
466
+ slackMessageTs String // This message's timestamp
467
+ slackUserId String // User who sent the message
468
+ messageText String? // Original message text (for debugging)
469
+
470
+ // Processing state
471
+ status String @default("pending") // pending|processing|completed|failed
472
+ retryCount Int @default(0)
473
+ lastError String? // Error message if failed
474
+
475
+ // Internal thread linkage (for context continuity)
476
+ internalThreadId String?
477
+ internalThread Thread? @relation(fields: [internalThreadId], references: [id], onDelete: SetNull)
478
+
479
+ // Response tracking
480
+ responseTs String? // Timestamp of bot's response message
481
+
482
+ // Timing
483
+ createdAt DateTime @default(now())
484
+ updatedAt DateTime @updatedAt
485
+ processedAt DateTime?
486
+
487
+ @@index([integrationId])
488
+ @@index([slackEventId])
489
+ @@index([status, updatedAt]) // For retry queries
490
+ @@index([slackChannelId, slackThreadTs]) // For thread context lookup
491
+ }
492
+
493
+ // One-time scheduled jobs (delayed execution)
494
+ // Used by the queue scheduler for jobs that need to run at a specific time
495
+ model ScheduledJob {
496
+ id String @id @default(cuid())
497
+ type String // Job type (e.g., 'email:send')
498
+ payload String @db.Text // JSON job payload
499
+ options String @db.Text // JSON EnqueueOptions
500
+ scheduledFor DateTime // When to enqueue to the queue
501
+ status String @default("scheduled") // scheduled | enqueued | cancelled
502
+ error String? // Error message if failed to enqueue
503
+ createdAt DateTime @default(now())
504
+ updatedAt DateTime @updatedAt
505
+
506
+ @@index([status, scheduledFor])
507
+ @@index([type])
508
+ }
509
+
510
+ // Recurring jobs (cron-style)
511
+ // Scheduler polls these and enqueues jobs according to schedule
512
+ model RecurringJob {
513
+ id String @id @default(cuid())
514
+ name String @unique // Unique job name: "daily-report", "hourly-cleanup"
515
+ type String // Job type to enqueue (e.g., 'report:generate')
516
+ payload String @db.Text // JSON payload for each job
517
+ options String @db.Text // JSON EnqueueOptions (minus scheduling)
518
+ schedule String // Cron: "0 9 * * *" or interval: "every 1 hour"
519
+ timezone String @default("UTC")
520
+ enabled Boolean @default(true)
521
+ nextRunAt DateTime? // Calculated next run time
522
+ lastRunAt DateTime? // Last successful run
523
+ lastError String? // Last error (if any)
524
+ createdAt DateTime @default(now())
525
+ updatedAt DateTime @updatedAt
526
+
527
+ @@index([enabled, nextRunAt])
528
+ }
529
+
530
+ // Scheduled Prompts (Automations)
531
+ // User or team-configurable prompts that run on a schedule
532
+ model ScheduledPrompt {
533
+ id String @id @default(cuid())
534
+ name String // "Daily Summary", "Weekly Report"
535
+ prompt String @db.Text // The prompt text to run
536
+ agentId String? // Agent to use (null = default)
537
+
538
+ // Schedule
539
+ schedule String // Cron: "0 9 * * 1-5" or interval: "every 1 day"
540
+ timezone String @default("UTC")
541
+ enabled Boolean @default(true)
542
+
543
+ // Notification settings
544
+ notifySlack Boolean @default(true)
545
+ notifyEmail Boolean @default(false)
546
+ emailRecipients String? @db.Text // JSON array of emails
547
+
548
+ // Results storage
549
+ threadId String? // Dedicated thread for results (created on first run)
550
+ thread Thread? @relation(fields: [threadId], references: [id], onDelete: SetNull)
551
+
552
+ // Ownership (one of these must be set)
553
+ userId String?
554
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
555
+ teamId String?
556
+ team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
557
+
558
+ // Tracking
559
+ lastRunAt DateTime?
560
+ lastRunStatus String? // "success" | "failed"
561
+ lastError String?
562
+ runCount Int @default(0)
563
+
564
+ createdAt DateTime @default(now())
565
+ updatedAt DateTime @updatedAt
566
+
567
+ @@index([userId])
568
+ @@index([teamId])
569
+ @@index([enabled])
570
+ }
571
+
572
+ // Email Verification Codes
573
+ model EmailVerification {
574
+ id String @id @default(cuid())
575
+ code String // 6-digit code (hashed)
576
+ userId String
577
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
578
+ expiresAt DateTime
579
+ usedAt DateTime?
580
+ attempts Int @default(0) // Brute force protection
581
+ createdAt DateTime @default(now())
582
+
583
+ @@index([userId])
584
+ }
@@ -0,0 +1,24 @@
1
+ // =============================================================================
2
+ // Custom Schema - Your Application Models
3
+ // =============================================================================
4
+ // Add your custom models here. This file is preserved during `chat-saas-server db:sync`.
5
+ //
6
+ // You can:
7
+ // - Add new models
8
+ // - Add relations to core models (use the model name, Prisma will find it in base.prisma)
9
+ //
10
+ // Example:
11
+ //
12
+ // model BlogPost {
13
+ // id String @id @default(cuid())
14
+ // title String
15
+ // content String
16
+ // authorId String
17
+ // author User @relation(fields: [authorId], references: [id])
18
+ // createdAt DateTime @default(now())
19
+ // }
20
+ //
21
+ // Note: If you add a relation to a core model (like User above), you may need to
22
+ // add the opposite relation field to that model in base.prisma. After running
23
+ // db:sync, check for validation errors and add any missing relation fields.
24
+ // =============================================================================