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,514 @@
1
+ # Job Queue
2
+
3
+ The job queue system provides background job processing with support for multiple backends, scheduled jobs, recurring jobs, and flexible worker deployment.
4
+
5
+ ## Overview
6
+
7
+ The queue system consists of:
8
+
9
+ - **Queue Providers**: Pluggable backends (memory for dev, SQS for production)
10
+ - **Workers**: Process jobs with configurable concurrency
11
+ - **Scheduler**: Database-backed scheduling for delayed and recurring jobs
12
+ - **Handler Registry**: Register functions to process specific job types
13
+
14
+ ## Quick Start
15
+
16
+ ### 1. Enable the Queue
17
+
18
+ ```typescript
19
+ // config/app.config.ts
20
+ export const config: AppConfig = {
21
+ // ... other config
22
+ queue: {
23
+ enabled: true,
24
+ providerConfig: { type: 'memory' },
25
+ worker: { mode: 'in-process', concurrency: 5 },
26
+ scheduler: { enabled: true },
27
+ },
28
+ };
29
+ ```
30
+
31
+ ### 2. Register Job Handlers
32
+
33
+ ```typescript
34
+ // extensions/jobs/email.ts
35
+ import { registerJobHandler } from '@chaaskit/server';
36
+
37
+ registerJobHandler('email:send', async (job, ctx) => {
38
+ ctx.log('Sending email to', job.payload.to);
39
+ await sendEmail(job.payload);
40
+ });
41
+
42
+ registerJobHandler('report:generate', async (job, ctx) => {
43
+ ctx.log('Generating report', job.payload.reportId);
44
+ ctx.progress(50); // Report progress
45
+ const report = await generateReport(job.payload);
46
+ ctx.progress(100);
47
+ return report;
48
+ });
49
+ ```
50
+
51
+ ### 3. Enqueue Jobs
52
+
53
+ ```typescript
54
+ import { getQueueProvider } from '@chaaskit/server';
55
+
56
+ const queue = getQueueProvider();
57
+
58
+ // Immediate job
59
+ await queue.enqueue('email:send', {
60
+ to: 'user@example.com',
61
+ subject: 'Welcome!'
62
+ });
63
+
64
+ // Delayed job (up to 15 min for SQS)
65
+ await queue.enqueue('reminder:send', { userId: '123' }, {
66
+ delay: 60000 // 1 minute
67
+ });
68
+
69
+ // Job with retry configuration
70
+ await queue.enqueue('webhook:send', { url: '...' }, {
71
+ maxRetries: 5,
72
+ timeout: 30000,
73
+ });
74
+ ```
75
+
76
+ ### 4. Push Schema Changes
77
+
78
+ ```bash
79
+ pnpm db:push
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ ### Full Config Options
85
+
86
+ ```typescript
87
+ queue: {
88
+ enabled: boolean;
89
+
90
+ // Provider configuration (discriminated union)
91
+ providerConfig:
92
+ | { type: 'memory'; maxHistorySize?: number }
93
+ | {
94
+ type: 'sqs';
95
+ region: string;
96
+ queueUrl: string;
97
+ deadLetterQueueUrl?: string;
98
+ visibilityTimeout?: number; // Default: 30s
99
+ };
100
+
101
+ // Worker configuration
102
+ worker?: {
103
+ mode: 'in-process' | 'standalone'; // Default: 'in-process'
104
+ concurrency?: number; // Default: 5
105
+ pollInterval?: number; // Default: 1000ms
106
+ shutdownTimeout?: number; // Default: 30000ms
107
+ };
108
+
109
+ // Scheduler configuration
110
+ scheduler?: {
111
+ enabled: boolean; // Default: false
112
+ pollInterval?: number; // Default: 60000ms (1 min)
113
+ };
114
+ }
115
+ ```
116
+
117
+ ### Development Config
118
+
119
+ ```typescript
120
+ queue: {
121
+ enabled: true,
122
+ providerConfig: { type: 'memory', maxHistorySize: 1000 },
123
+ worker: { mode: 'in-process', concurrency: 2 },
124
+ scheduler: { enabled: true },
125
+ }
126
+ ```
127
+
128
+ ### Production Config (SQS)
129
+
130
+ ```typescript
131
+ queue: {
132
+ enabled: true,
133
+ providerConfig: {
134
+ type: 'sqs',
135
+ region: 'us-east-1',
136
+ queueUrl: process.env.SQS_QUEUE_URL!,
137
+ deadLetterQueueUrl: process.env.SQS_DLQ_URL,
138
+ visibilityTimeout: 60,
139
+ },
140
+ worker: { mode: 'in-process', concurrency: 10 },
141
+ scheduler: { enabled: true, pollInterval: 30000 },
142
+ }
143
+ ```
144
+
145
+ ## Queue Providers
146
+
147
+ ### Memory Provider
148
+
149
+ In-memory queue for development and testing. Uses EventEmitter for instant job notification (no polling).
150
+
151
+ ```typescript
152
+ providerConfig: {
153
+ type: 'memory',
154
+ maxHistorySize: 1000 // Keep last N completed jobs
155
+ }
156
+ ```
157
+
158
+ **Features:**
159
+ - Instant job processing (EventEmitter-based)
160
+ - Job history for debugging
161
+ - Deduplication support
162
+ - Priority queues
163
+
164
+ ### SQS Provider
165
+
166
+ AWS SQS for production deployments. Requires `@aws-sdk/client-sqs`:
167
+
168
+ ```bash
169
+ pnpm add @aws-sdk/client-sqs
170
+ ```
171
+
172
+ ```typescript
173
+ providerConfig: {
174
+ type: 'sqs',
175
+ region: 'us-east-1',
176
+ queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue',
177
+ deadLetterQueueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-dlq',
178
+ visibilityTimeout: 30,
179
+ }
180
+ ```
181
+
182
+ **Environment Variables:**
183
+ ```bash
184
+ AWS_ACCESS_KEY_ID=your-key
185
+ AWS_SECRET_ACCESS_KEY=your-secret
186
+ SQS_QUEUE_URL=https://sqs...
187
+ ```
188
+
189
+ **Features:**
190
+ - Long polling (efficient, no wasted requests)
191
+ - Visibility timeout for at-least-once delivery
192
+ - Dead letter queue support
193
+ - FIFO queue support with deduplication
194
+
195
+ **Limitations:**
196
+ - Max delay: 15 minutes (use scheduler for longer delays)
197
+ - Max message size: 256 KB
198
+
199
+ ## Job Handlers
200
+
201
+ ### Registering Handlers
202
+
203
+ ```typescript
204
+ import { registerJobHandler } from '@chaaskit/server';
205
+
206
+ registerJobHandler<PayloadType, ResultType>(
207
+ 'job:type',
208
+ async (job, ctx) => {
209
+ // job.id - Unique job ID
210
+ // job.type - Job type string
211
+ // job.payload - Your typed payload
212
+ // job.attempts - Current attempt number
213
+ // job.options - Job options (maxRetries, timeout, etc.)
214
+
215
+ // ctx.jobId - Same as job.id
216
+ // ctx.attempt - Current attempt (1-based)
217
+ // ctx.log() - Job-specific logging
218
+ // ctx.progress() - Report progress (0-100)
219
+ // ctx.signal - AbortSignal for cancellation
220
+
221
+ return result;
222
+ },
223
+ 'Optional description for debugging'
224
+ );
225
+ ```
226
+
227
+ ### Error Handling & Retries
228
+
229
+ Jobs automatically retry on failure:
230
+
231
+ ```typescript
232
+ registerJobHandler('flaky:job', async (job, ctx) => {
233
+ if (Math.random() < 0.5) {
234
+ throw new Error('Random failure');
235
+ // Job will be retried up to maxRetries times
236
+ }
237
+ return 'success';
238
+ });
239
+
240
+ // Configure retries per job
241
+ await queue.enqueue('flaky:job', {}, {
242
+ maxRetries: 5, // Default: 3
243
+ timeout: 60000, // Job timeout in ms
244
+ });
245
+ ```
246
+
247
+ ### Timeout Handling
248
+
249
+ ```typescript
250
+ registerJobHandler('long:task', async (job, ctx) => {
251
+ // Check if job was cancelled/timed out
252
+ if (ctx.signal.aborted) {
253
+ throw new Error('Job cancelled');
254
+ }
255
+
256
+ // For long operations, periodically check the signal
257
+ for (const item of items) {
258
+ if (ctx.signal.aborted) break;
259
+ await processItem(item);
260
+ }
261
+ });
262
+ ```
263
+
264
+ ## Scheduler
265
+
266
+ The scheduler enables delayed execution and recurring jobs using database storage.
267
+
268
+ ### One-Time Scheduled Jobs
269
+
270
+ For delays longer than provider limits (e.g., > 15 min for SQS):
271
+
272
+ ```typescript
273
+ import { getScheduler } from '@chaaskit/server';
274
+
275
+ const scheduler = getScheduler();
276
+
277
+ // Schedule for a specific time
278
+ await scheduler.schedule(
279
+ 'report:send',
280
+ { reportId: '123', recipients: ['user@example.com'] },
281
+ new Date('2024-12-25T09:00:00Z')
282
+ );
283
+
284
+ // Cancel a scheduled job
285
+ await scheduler.cancelScheduledJob(jobId);
286
+ ```
287
+
288
+ ### Recurring Jobs
289
+
290
+ ```typescript
291
+ // Cron expression (daily at 9am)
292
+ await scheduler.registerRecurring({
293
+ name: 'daily-digest',
294
+ type: 'email:digest',
295
+ payload: { digestType: 'daily' },
296
+ schedule: '0 9 * * *',
297
+ timezone: 'America/New_York',
298
+ });
299
+
300
+ // Interval syntax
301
+ await scheduler.registerRecurring({
302
+ name: 'cache-cleanup',
303
+ type: 'maintenance:cleanup',
304
+ payload: {},
305
+ schedule: 'every 1 hour',
306
+ });
307
+
308
+ // Manage recurring jobs
309
+ await scheduler.disableRecurring('daily-digest');
310
+ await scheduler.enableRecurring('daily-digest');
311
+ await scheduler.deleteRecurring('daily-digest');
312
+
313
+ // List all recurring jobs
314
+ const jobs = await scheduler.listRecurring();
315
+ ```
316
+
317
+ **Supported Schedule Formats:**
318
+ - Cron: `"0 9 * * *"` (daily at 9am), `"*/15 * * * *"` (every 15 min)
319
+ - Intervals: `"every 1 hour"`, `"every 30 minutes"`, `"every 1 day"`
320
+
321
+ ## Worker Modes
322
+
323
+ ### In-Process Mode (Default)
324
+
325
+ Worker runs within the main server process:
326
+
327
+ ```typescript
328
+ worker: {
329
+ mode: 'in-process',
330
+ concurrency: 5
331
+ }
332
+ ```
333
+
334
+ **Pros:** Simple setup, no extra processes
335
+ **Cons:** Shares resources with web server
336
+
337
+ ### Standalone Mode
338
+
339
+ Run workers as separate processes for better scaling:
340
+
341
+ ```typescript
342
+ // config/app.config.ts
343
+ worker: {
344
+ mode: 'standalone' // Server won't start workers
345
+ }
346
+ ```
347
+
348
+ Then run workers separately:
349
+
350
+ ```bash
351
+ # Using the CLI
352
+ pnpm queue-worker
353
+
354
+ # Or with environment overrides
355
+ QUEUE_CONCURRENCY=10 pnpm queue-worker
356
+ SCHEDULER_ENABLED=true pnpm queue-worker
357
+ ```
358
+
359
+ **Environment Variables for Standalone Workers:**
360
+ ```bash
361
+ QUEUE_CONCURRENCY=5 # Number of concurrent jobs
362
+ QUEUE_POLL_INTERVAL=1000 # Poll interval (ms)
363
+ QUEUE_SHUTDOWN_TIMEOUT=30000 # Graceful shutdown timeout (ms)
364
+ SCHEDULER_ENABLED=false # Enable scheduler in this worker
365
+ SCHEDULER_POLL_INTERVAL=60000 # Scheduler poll interval (ms)
366
+ ```
367
+
368
+ ## API Reference
369
+
370
+ ### Queue Provider
371
+
372
+ ```typescript
373
+ interface QueueProvider {
374
+ readonly name: string;
375
+
376
+ // Enqueue a job
377
+ enqueue<T>(type: string, payload: T, options?: EnqueueOptions): Promise<Job<T>>;
378
+
379
+ // Receive jobs (long polling)
380
+ receive(maxMessages?: number, waitTimeSeconds?: number): Promise<ReceivedJob[]>;
381
+
382
+ // Acknowledge successful completion
383
+ acknowledge(receiptHandle: string): Promise<void>;
384
+
385
+ // Mark job as failed (will retry if attempts remain)
386
+ fail(receiptHandle: string, error: Error): Promise<void>;
387
+
388
+ // Get job by ID
389
+ getJob(jobId: string): Promise<Job | null>;
390
+
391
+ // Get queue statistics
392
+ getStats(): Promise<QueueStats>;
393
+
394
+ // Close provider
395
+ close(): Promise<void>;
396
+ }
397
+ ```
398
+
399
+ ### Enqueue Options
400
+
401
+ ```typescript
402
+ interface EnqueueOptions {
403
+ delay?: number; // Delay in ms
404
+ scheduledFor?: Date; // Specific execution time
405
+ maxRetries?: number; // Default: 3
406
+ timeout?: number; // Job timeout in ms (default: 30000)
407
+ deduplicationKey?: string; // Prevent duplicate jobs
408
+ priority?: number; // Lower = higher priority (default: 0)
409
+ }
410
+ ```
411
+
412
+ ### Job Context
413
+
414
+ ```typescript
415
+ interface JobContext {
416
+ jobId: string;
417
+ attempt: number; // 1-based attempt number
418
+ log: (msg: string, ...args) => void; // Job-specific logging
419
+ progress: (percent: number) => void; // Report progress 0-100
420
+ signal: AbortSignal; // Check for cancellation
421
+ }
422
+ ```
423
+
424
+ ## Database Models
425
+
426
+ The scheduler uses two database tables:
427
+
428
+ ```prisma
429
+ model ScheduledJob {
430
+ id String @id
431
+ type String
432
+ payload String @db.Text
433
+ options String @db.Text
434
+ scheduledFor DateTime
435
+ status String // scheduled | enqueued | cancelled
436
+ error String?
437
+ createdAt DateTime
438
+ updatedAt DateTime
439
+ }
440
+
441
+ model RecurringJob {
442
+ id String @id
443
+ name String @unique
444
+ type String
445
+ payload String @db.Text
446
+ options String @db.Text
447
+ schedule String // Cron or interval
448
+ timezone String
449
+ enabled Boolean
450
+ nextRunAt DateTime?
451
+ lastRunAt DateTime?
452
+ lastError String?
453
+ createdAt DateTime
454
+ updatedAt DateTime
455
+ }
456
+ ```
457
+
458
+ ## Best Practices
459
+
460
+ ### Job Design
461
+
462
+ 1. **Keep jobs idempotent** - Jobs may run more than once
463
+ 2. **Store minimal data** - Put IDs in payload, not full objects
464
+ 3. **Handle timeouts gracefully** - Check `ctx.signal.aborted`
465
+ 4. **Use meaningful job types** - `email:welcome`, `report:daily`, `webhook:send`
466
+
467
+ ### Production Setup
468
+
469
+ 1. **Use SQS with DLQ** - Failed jobs go to dead letter queue for inspection
470
+ 2. **Run standalone workers** - Scale workers independently from web servers
471
+ 3. **Monitor queue depth** - Alert when jobs back up
472
+ 4. **Set appropriate timeouts** - Match job execution time
473
+
474
+ ### Error Handling
475
+
476
+ ```typescript
477
+ registerJobHandler('critical:job', async (job, ctx) => {
478
+ try {
479
+ await riskyOperation();
480
+ } catch (error) {
481
+ // Log with context
482
+ ctx.log('Operation failed', { error: error.message, attempt: ctx.attempt });
483
+
484
+ // Re-throw to trigger retry
485
+ throw error;
486
+
487
+ // Or handle gracefully and don't retry
488
+ // return { status: 'failed', reason: error.message };
489
+ }
490
+ });
491
+ ```
492
+
493
+ ## Troubleshooting
494
+
495
+ ### Jobs Not Processing
496
+
497
+ 1. Check queue is enabled: `queue.enabled: true`
498
+ 2. Check worker mode matches your setup
499
+ 3. Verify handler is registered for job type
500
+ 4. Check server logs for errors
501
+
502
+ ### SQS Connection Issues
503
+
504
+ 1. Verify AWS credentials are set
505
+ 2. Check queue URL is correct
506
+ 3. Ensure IAM permissions include SQS actions
507
+ 4. Test with AWS CLI: `aws sqs get-queue-attributes --queue-url ...`
508
+
509
+ ### Scheduler Not Running
510
+
511
+ 1. Enable scheduler: `scheduler.enabled: true`
512
+ 2. Run `pnpm db:push` to create tables
513
+ 3. Check database connectivity
514
+ 4. Verify recurring job schedules are valid