motia 0.5.11-beta.120-011950 → 0.5.11-beta.120-356715

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 (24) hide show
  1. package/dist/cjs/create/templates/python/steps/api_step.py.txt +1 -1
  2. package/dist/cjs/create/templates/python/tutorial.tsx.txt +1 -1
  3. package/dist/cjs/create/templates/typescript/steps/api.step.ts.txt +2 -2
  4. package/dist/cjs/create/templates/typescript/tutorial.tsx.txt +1 -1
  5. package/dist/dot-files/.cursor/rules/ai-agent-patterns.mdc +725 -0
  6. package/dist/dot-files/.cursor/rules/api-design-patterns.mdc +740 -0
  7. package/dist/dot-files/.cursor/rules/api-steps.mdc +125 -64
  8. package/dist/dot-files/.cursor/rules/authentication-patterns.mdc +620 -0
  9. package/dist/dot-files/.cursor/rules/background-job-patterns.mdc +628 -0
  10. package/dist/dot-files/.cursor/rules/complete-application-patterns.mdc +433 -0
  11. package/dist/dot-files/.cursor/rules/complete-backend-generator.mdc +415 -0
  12. package/dist/dot-files/.cursor/rules/event-steps.mdc +271 -133
  13. package/dist/dot-files/.cursor/rules/multi-language-workflows.mdc +1059 -0
  14. package/dist/dot-files/.cursor/rules/production-deployment.mdc +668 -0
  15. package/dist/dot-files/.cursor/rules/realtime-streaming.mdc +656 -0
  16. package/dist/dot-files/.cursor/rules/state-management.mdc +133 -87
  17. package/dist/dot-files/.cursor/rules/steps.mdc +68 -12
  18. package/dist/dot-files/.cursor/rules/workflow-patterns.mdc +938 -0
  19. package/dist/dot-files/CLAUDE.md +334 -129
  20. package/dist/esm/create/templates/python/steps/api_step.py.txt +1 -1
  21. package/dist/esm/create/templates/python/tutorial.tsx.txt +1 -1
  22. package/dist/esm/create/templates/typescript/steps/api.step.ts.txt +2 -2
  23. package/dist/esm/create/templates/typescript/tutorial.tsx.txt +1 -1
  24. package/package.json +4 -4
@@ -0,0 +1,668 @@
1
+ ---
2
+ description: Production deployment patterns and DevOps best practices for Motia applications
3
+ globs:
4
+ alwaysApply: false
5
+ ---
6
+ # Production Deployment Patterns
7
+
8
+ Deploy robust, scalable Motia applications to production environments with confidence.
9
+
10
+ ## Environment Configuration
11
+
12
+ ### Environment Variables
13
+
14
+ ```bash
15
+ # .env.example
16
+ # Application
17
+ NODE_ENV=production
18
+ PORT=3000
19
+ APP_NAME=my-motia-app
20
+
21
+ # Authentication
22
+ JWT_SECRET=your-super-secure-jwt-secret-here
23
+ JWT_EXPIRES_IN=15m
24
+ REFRESH_TOKEN_EXPIRES_IN=30d
25
+ BCRYPT_ROUNDS=12
26
+
27
+ # Database
28
+ DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
29
+ REDIS_URL=redis://localhost:6379
30
+
31
+ # External Services
32
+ OPENAI_API_KEY=sk-...
33
+ SENDGRID_API_KEY=SG...
34
+ AWS_ACCESS_KEY_ID=AKIA...
35
+ AWS_SECRET_ACCESS_KEY=...
36
+ AWS_S3_BUCKET=my-app-storage
37
+ AWS_REGION=us-east-1
38
+
39
+ # Monitoring
40
+ SENTRY_DSN=https://...@sentry.io/...
41
+ LOG_LEVEL=info
42
+
43
+ # Rate Limiting
44
+ RATE_LIMIT_WINDOW_MS=900000
45
+ RATE_LIMIT_MAX_REQUESTS=100
46
+ ```
47
+
48
+ ### Configuration Management
49
+
50
+ ```typescript
51
+ // config/environment.ts
52
+ import { z } from 'zod'
53
+
54
+ const envSchema = z.object({
55
+ NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
56
+ PORT: z.coerce.number().default(3000),
57
+ APP_NAME: z.string().default('motia-app'),
58
+
59
+ // Authentication
60
+ JWT_SECRET: z.string().min(32),
61
+ JWT_EXPIRES_IN: z.string().default('15m'),
62
+ REFRESH_TOKEN_EXPIRES_IN: z.string().default('30d'),
63
+ BCRYPT_ROUNDS: z.coerce.number().default(12),
64
+
65
+ // Database
66
+ DATABASE_URL: z.string().url().optional(),
67
+ REDIS_URL: z.string().url().optional(),
68
+
69
+ // External Services
70
+ OPENAI_API_KEY: z.string().optional(),
71
+ SENDGRID_API_KEY: z.string().optional(),
72
+
73
+ // AWS
74
+ AWS_ACCESS_KEY_ID: z.string().optional(),
75
+ AWS_SECRET_ACCESS_KEY: z.string().optional(),
76
+ AWS_S3_BUCKET: z.string().optional(),
77
+ AWS_REGION: z.string().default('us-east-1'),
78
+
79
+ // Monitoring
80
+ SENTRY_DSN: z.string().url().optional(),
81
+ LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
82
+
83
+ // Rate Limiting
84
+ RATE_LIMIT_WINDOW_MS: z.coerce.number().default(900000),
85
+ RATE_LIMIT_MAX_REQUESTS: z.coerce.number().default(100)
86
+ })
87
+
88
+ export type Environment = z.infer<typeof envSchema>
89
+
90
+ export const env = envSchema.parse(process.env)
91
+
92
+ export const isDevelopment = env.NODE_ENV === 'development'
93
+ export const isProduction = env.NODE_ENV === 'production'
94
+ export const isStaging = env.NODE_ENV === 'staging'
95
+ ```
96
+
97
+ ## Docker Configuration
98
+
99
+ ```dockerfile
100
+ # Dockerfile
101
+ FROM node:18-alpine AS base
102
+
103
+ # Install Python for multi-language support
104
+ RUN apk add --no-cache python3 py3-pip build-base
105
+
106
+ # Install pnpm
107
+ RUN npm install -g pnpm
108
+
109
+ WORKDIR /app
110
+
111
+ # Copy package files
112
+ COPY package.json pnpm-lock.yaml ./
113
+ COPY requirements.txt ./
114
+
115
+ # Install dependencies
116
+ RUN pnpm install --frozen-lockfile --production
117
+ RUN pip3 install -r requirements.txt
118
+
119
+ # Copy source code
120
+ COPY . .
121
+
122
+ # Build if necessary
123
+ RUN pnpm build || true
124
+
125
+ # Create non-root user
126
+ RUN addgroup -g 1001 -S nodejs
127
+ RUN adduser -S motia -u 1001
128
+
129
+ # Change ownership
130
+ RUN chown -R motia:nodejs /app
131
+ USER motia
132
+
133
+ # Expose port
134
+ EXPOSE 3000
135
+
136
+ # Health check
137
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
138
+ CMD curl -f http://localhost:3000/health || exit 1
139
+
140
+ # Start application
141
+ CMD ["pnpm", "start"]
142
+ ```
143
+
144
+ ```yaml
145
+ # docker-compose.yml
146
+ version: '3.8'
147
+
148
+ services:
149
+ app:
150
+ build: .
151
+ ports:
152
+ - "3000:3000"
153
+ environment:
154
+ - NODE_ENV=production
155
+ - DATABASE_URL=postgresql://postgres:password@db:5432/motia_prod
156
+ - REDIS_URL=redis://redis:6379
157
+ depends_on:
158
+ - db
159
+ - redis
160
+ restart: unless-stopped
161
+ healthcheck:
162
+ test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
163
+ interval: 30s
164
+ timeout: 10s
165
+ retries: 3
166
+
167
+ db:
168
+ image: postgres:15-alpine
169
+ environment:
170
+ POSTGRES_DB: motia_prod
171
+ POSTGRES_USER: postgres
172
+ POSTGRES_PASSWORD: password
173
+ volumes:
174
+ - postgres_data:/var/lib/postgresql/data
175
+ ports:
176
+ - "5432:5432"
177
+ restart: unless-stopped
178
+ healthcheck:
179
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
180
+ interval: 10s
181
+ timeout: 5s
182
+ retries: 5
183
+
184
+ redis:
185
+ image: redis:7-alpine
186
+ command: redis-server --appendonly yes
187
+ volumes:
188
+ - redis_data:/data
189
+ ports:
190
+ - "6379:6379"
191
+ restart: unless-stopped
192
+ healthcheck:
193
+ test: ["CMD", "redis-cli", "ping"]
194
+ interval: 10s
195
+ timeout: 5s
196
+ retries: 3
197
+
198
+ volumes:
199
+ postgres_data:
200
+ redis_data:
201
+ ```
202
+
203
+ ## Health Checks & Monitoring
204
+
205
+ ```typescript
206
+ // steps/monitoring/health-check.step.ts
207
+ import { ApiRouteConfig, Handlers } from 'motia'
208
+ import { z } from 'zod'
209
+
210
+ export const config: ApiRouteConfig = {
211
+ type: 'api',
212
+ name: 'HealthCheck',
213
+ description: 'Application health check endpoint',
214
+ method: 'GET',
215
+ path: '/health',
216
+ responseSchema: {
217
+ 200: z.object({
218
+ status: z.string(),
219
+ timestamp: z.string(),
220
+ uptime: z.number(),
221
+ version: z.string(),
222
+ environment: z.string(),
223
+ services: z.record(z.object({
224
+ status: z.enum(['healthy', 'unhealthy', 'degraded']),
225
+ responseTime: z.number().optional(),
226
+ error: z.string().optional()
227
+ }))
228
+ }),
229
+ 503: z.object({
230
+ status: z.string(),
231
+ error: z.string()
232
+ })
233
+ },
234
+ emits: [],
235
+ flows: ['monitoring']
236
+ }
237
+
238
+ export const handler: Handlers['HealthCheck'] = async (req, { logger, state }) => {
239
+ try {
240
+ const startTime = Date.now()
241
+ const services: Record<string, any> = {}
242
+
243
+ // Check database connectivity
244
+ try {
245
+ const dbStart = Date.now()
246
+ await state.get('health', 'db-check')
247
+ services.database = {
248
+ status: 'healthy',
249
+ responseTime: Date.now() - dbStart
250
+ }
251
+ } catch (error) {
252
+ services.database = {
253
+ status: 'unhealthy',
254
+ error: error.message
255
+ }
256
+ }
257
+
258
+ // Check Redis connectivity
259
+ try {
260
+ const redisStart = Date.now()
261
+ await checkRedisHealth()
262
+ services.redis = {
263
+ status: 'healthy',
264
+ responseTime: Date.now() - redisStart
265
+ }
266
+ } catch (error) {
267
+ services.redis = {
268
+ status: 'unhealthy',
269
+ error: error.message
270
+ }
271
+ }
272
+
273
+ // Check external services
274
+ services.openai = await checkOpenAIHealth()
275
+ services.email = await checkEmailServiceHealth()
276
+
277
+ const allHealthy = Object.values(services).every(
278
+ (service: any) => service.status === 'healthy'
279
+ )
280
+
281
+ const healthStatus = {
282
+ status: allHealthy ? 'healthy' : 'degraded',
283
+ timestamp: new Date().toISOString(),
284
+ uptime: process.uptime(),
285
+ version: process.env.npm_package_version || '1.0.0',
286
+ environment: process.env.NODE_ENV || 'unknown',
287
+ services
288
+ }
289
+
290
+ if (!allHealthy) {
291
+ logger.warn('Health check showing degraded status', { services })
292
+ }
293
+
294
+ return {
295
+ status: allHealthy ? 200 : 503,
296
+ body: healthStatus
297
+ }
298
+ } catch (error) {
299
+ logger.error('Health check failed', { error: error.message })
300
+ return {
301
+ status: 503,
302
+ body: {
303
+ status: 'unhealthy',
304
+ error: error.message
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ async function checkRedisHealth(): Promise<void> {
311
+ // Implement Redis health check
312
+ // Could use ioredis client to ping Redis
313
+ }
314
+
315
+ async function checkOpenAIHealth() {
316
+ try {
317
+ // Simple OpenAI API check
318
+ const response = await fetch('https://api.openai.com/v1/models', {
319
+ method: 'GET',
320
+ headers: {
321
+ 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
322
+ },
323
+ signal: AbortSignal.timeout(5000)
324
+ })
325
+
326
+ return {
327
+ status: response.ok ? 'healthy' : 'unhealthy',
328
+ responseTime: Date.now()
329
+ }
330
+ } catch {
331
+ return { status: 'unhealthy', error: 'OpenAI API unavailable' }
332
+ }
333
+ }
334
+
335
+ async function checkEmailServiceHealth() {
336
+ // Implement email service health check
337
+ return { status: 'healthy' }
338
+ }
339
+ ```
340
+
341
+ ## Production State Configuration
342
+
343
+ ```yaml
344
+ # config.yml
345
+ state:
346
+ adapter: redis
347
+ host: ${REDIS_HOST:-localhost}
348
+ port: ${REDIS_PORT:-6379}
349
+ password: ${REDIS_PASSWORD}
350
+ db: ${REDIS_DB:-0}
351
+ ttl: ${STATE_TTL:-3600}
352
+ keyPrefix: ${APP_NAME:-motia}:state:
353
+
354
+ # Logging configuration
355
+ logging:
356
+ level: ${LOG_LEVEL:-info}
357
+ format: json
358
+ destination: stdout
359
+
360
+ # Security settings
361
+ security:
362
+ rateLimit:
363
+ windowMs: ${RATE_LIMIT_WINDOW_MS:-900000}
364
+ max: ${RATE_LIMIT_MAX_REQUESTS:-100}
365
+ cors:
366
+ origin: ${CORS_ORIGIN:-*}
367
+ credentials: true
368
+ helmet:
369
+ contentSecurityPolicy: true
370
+ hsts: true
371
+ ```
372
+
373
+ ## CI/CD Pipeline
374
+
375
+ ```yaml
376
+ # .github/workflows/deploy.yml
377
+ name: Deploy to Production
378
+
379
+ on:
380
+ push:
381
+ branches: [main]
382
+ pull_request:
383
+ branches: [main]
384
+
385
+ env:
386
+ NODE_VERSION: '18'
387
+ PYTHON_VERSION: '3.11'
388
+
389
+ jobs:
390
+ test:
391
+ runs-on: ubuntu-latest
392
+
393
+ services:
394
+ postgres:
395
+ image: postgres:15
396
+ env:
397
+ POSTGRES_PASSWORD: postgres
398
+ POSTGRES_DB: test_db
399
+ options: >-
400
+ --health-cmd pg_isready
401
+ --health-interval 10s
402
+ --health-timeout 5s
403
+ --health-retries 5
404
+
405
+ redis:
406
+ image: redis:7
407
+ options: >-
408
+ --health-cmd "redis-cli ping"
409
+ --health-interval 10s
410
+ --health-timeout 5s
411
+ --health-retries 5
412
+
413
+ steps:
414
+ - uses: actions/checkout@v4
415
+
416
+ - uses: actions/setup-node@v4
417
+ with:
418
+ node-version: ${{ env.NODE_VERSION }}
419
+ cache: 'pnpm'
420
+
421
+ - uses: actions/setup-python@v4
422
+ with:
423
+ python-version: ${{ env.PYTHON_VERSION }}
424
+ cache: 'pip'
425
+
426
+ - name: Install dependencies
427
+ run: |
428
+ npm install -g pnpm
429
+ pnpm install
430
+ pip install -r requirements.txt
431
+
432
+ - name: Run linting
433
+ run: |
434
+ pnpm lint
435
+
436
+ - name: Run tests
437
+ env:
438
+ DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
439
+ REDIS_URL: redis://localhost:6379
440
+ JWT_SECRET: test-secret-key-for-testing-only
441
+ run: |
442
+ pnpm test
443
+
444
+ - name: Build application
445
+ run: |
446
+ pnpm build
447
+
448
+ deploy:
449
+ if: github.ref == 'refs/heads/main'
450
+ needs: test
451
+ runs-on: ubuntu-latest
452
+
453
+ steps:
454
+ - uses: actions/checkout@v4
455
+
456
+ - name: Deploy to production
457
+ env:
458
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
459
+ PRODUCTION_HOST: ${{ secrets.PRODUCTION_HOST }}
460
+ run: |
461
+ # Deploy using your preferred method
462
+ # This could be Docker deployment, Kubernetes, or cloud services
463
+ echo "Deploying to production..."
464
+ ```
465
+
466
+ ## Performance Optimization
467
+
468
+ ```typescript
469
+ // steps/middleware/performance.ts
470
+ import { ApiMiddleware } from 'motia'
471
+ import compression from 'compression'
472
+ import helmet from 'helmet'
473
+
474
+ // Compression middleware
475
+ export const compressionMiddleware: ApiMiddleware = async (req, ctx, next) => {
476
+ // Add compression for responses > 1KB
477
+ const response = await next()
478
+
479
+ if (response.body && typeof response.body === 'object') {
480
+ const bodySize = JSON.stringify(response.body).length
481
+ if (bodySize > 1024) {
482
+ response.headers = {
483
+ ...response.headers,
484
+ 'Content-Encoding': 'gzip'
485
+ }
486
+ }
487
+ }
488
+
489
+ return response
490
+ }
491
+
492
+ // Security headers middleware
493
+ export const securityMiddleware: ApiMiddleware = async (req, ctx, next) => {
494
+ const response = await next()
495
+
496
+ return {
497
+ ...response,
498
+ headers: {
499
+ ...response.headers,
500
+ 'X-Content-Type-Options': 'nosniff',
501
+ 'X-Frame-Options': 'DENY',
502
+ 'X-XSS-Protection': '1; mode=block',
503
+ 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
504
+ 'Referrer-Policy': 'strict-origin-when-cross-origin'
505
+ }
506
+ }
507
+ }
508
+
509
+ // Request timing middleware
510
+ export const timingMiddleware: ApiMiddleware = async (req, ctx, next) => {
511
+ const start = Date.now()
512
+
513
+ const response = await next()
514
+
515
+ const duration = Date.now() - start
516
+
517
+ ctx.logger.info('Request completed', {
518
+ method: req.method || 'unknown',
519
+ path: req.path,
520
+ duration,
521
+ status: response.status
522
+ })
523
+
524
+ return {
525
+ ...response,
526
+ headers: {
527
+ ...response.headers,
528
+ 'X-Response-Time': `${duration}ms`
529
+ }
530
+ }
531
+ }
532
+ ```
533
+
534
+ ## Error Handling & Logging
535
+
536
+ ```typescript
537
+ // steps/middleware/error-handling.ts
538
+ import { ApiMiddleware } from 'motia'
539
+ import { env } from '../config/environment'
540
+
541
+ export const errorHandlingMiddleware: ApiMiddleware = async (req, ctx, next) => {
542
+ try {
543
+ return await next()
544
+ } catch (error) {
545
+ ctx.logger.error('Unhandled error in API route', {
546
+ error: error.message,
547
+ stack: error.stack,
548
+ method: req.method,
549
+ path: req.path,
550
+ userId: req.user?.userId
551
+ })
552
+
553
+ // Don't expose internal errors in production
554
+ const message = env.NODE_ENV === 'production'
555
+ ? 'Internal server error'
556
+ : error.message
557
+
558
+ return {
559
+ status: 500,
560
+ body: { error: message }
561
+ }
562
+ }
563
+ }
564
+ ```
565
+
566
+ ## Monitoring & Alerting
567
+
568
+ ```typescript
569
+ // steps/cron/system-monitoring.step.ts
570
+ import { CronConfig, Handlers } from 'motia'
571
+
572
+ export const config: CronConfig = {
573
+ type: 'cron',
574
+ name: 'SystemMonitoring',
575
+ description: 'Monitor system metrics and send alerts',
576
+ cron: '*/5 * * * *', // Every 5 minutes
577
+ emits: ['alert.system', 'metrics.collected'],
578
+ flows: ['monitoring']
579
+ }
580
+
581
+ export const handler: Handlers['SystemMonitoring'] = async ({ emit, logger, state }) => {
582
+ try {
583
+ const metrics = await collectSystemMetrics()
584
+
585
+ // Store metrics
586
+ await state.set('metrics', new Date().toISOString(), metrics)
587
+
588
+ // Check thresholds and send alerts
589
+ const alerts = checkAlertThresholds(metrics)
590
+
591
+ for (const alert of alerts) {
592
+ await emit({
593
+ topic: 'alert.system',
594
+ data: {
595
+ severity: alert.severity,
596
+ metric: alert.metric,
597
+ value: alert.value,
598
+ threshold: alert.threshold,
599
+ timestamp: new Date().toISOString()
600
+ }
601
+ })
602
+ }
603
+
604
+ await emit({
605
+ topic: 'metrics.collected',
606
+ data: metrics
607
+ })
608
+
609
+ logger.info('System metrics collected', {
610
+ alertCount: alerts.length,
611
+ metrics: Object.keys(metrics)
612
+ })
613
+
614
+ } catch (error) {
615
+ logger.error('System monitoring failed', { error: error.message })
616
+ }
617
+ }
618
+
619
+ async function collectSystemMetrics() {
620
+ return {
621
+ memory: {
622
+ used: process.memoryUsage().heapUsed,
623
+ total: process.memoryUsage().heapTotal,
624
+ percentage: (process.memoryUsage().heapUsed / process.memoryUsage().heapTotal) * 100
625
+ },
626
+ cpu: {
627
+ usage: process.cpuUsage()
628
+ },
629
+ uptime: process.uptime(),
630
+ activeConnections: await getActiveConnectionCount(),
631
+ responseTime: await measureAverageResponseTime()
632
+ }
633
+ }
634
+
635
+ function checkAlertThresholds(metrics: any) {
636
+ const alerts = []
637
+
638
+ if (metrics.memory.percentage > 85) {
639
+ alerts.push({
640
+ severity: 'warning',
641
+ metric: 'memory_usage',
642
+ value: metrics.memory.percentage,
643
+ threshold: 85
644
+ })
645
+ }
646
+
647
+ if (metrics.memory.percentage > 95) {
648
+ alerts.push({
649
+ severity: 'critical',
650
+ metric: 'memory_usage',
651
+ value: metrics.memory.percentage,
652
+ threshold: 95
653
+ })
654
+ }
655
+
656
+ return alerts
657
+ }
658
+ ```
659
+
660
+ This production deployment setup provides:
661
+ - Comprehensive environment configuration
662
+ - Docker containerization
663
+ - Health checks and monitoring
664
+ - CI/CD pipeline
665
+ - Performance optimization
666
+ - Security best practices
667
+ - Error handling and logging
668
+ - System monitoring and alerting