@nextsparkjs/ai-workflow 0.1.0-beta.100
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.
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
# /how-to:set-scheduled-actions
|
|
2
|
+
|
|
3
|
+
Interactive guide to configure background tasks and scheduled actions in NextSpark.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Required Skills
|
|
8
|
+
|
|
9
|
+
Before executing, these skills provide deeper context:
|
|
10
|
+
- `.claude/skills/scheduled-actions/SKILL.md` - Background task processing patterns
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Syntax
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
/how-to:set-scheduled-actions
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Behavior
|
|
23
|
+
|
|
24
|
+
Guides the user through creating scheduled actions for background task processing, cron jobs, and webhooks.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Tutorial Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
STEPS OVERVIEW (5 steps)
|
|
32
|
+
|
|
33
|
+
Step 1: Understanding Scheduled Actions
|
|
34
|
+
└── How background tasks work
|
|
35
|
+
|
|
36
|
+
Step 2: Create an Action Handler
|
|
37
|
+
└── Define the task logic
|
|
38
|
+
|
|
39
|
+
Step 3: Schedule the Action
|
|
40
|
+
└── One-time or recurring
|
|
41
|
+
|
|
42
|
+
Step 4: Configure Webhooks
|
|
43
|
+
└── External trigger endpoint
|
|
44
|
+
|
|
45
|
+
Step 5: Monitor and Debug
|
|
46
|
+
└── Logs and execution status
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 1: Understanding Scheduled Actions
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
55
|
+
📚 HOW TO: SET SCHEDULED ACTIONS
|
|
56
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
57
|
+
|
|
58
|
+
STEP 1 OF 5: Understanding Scheduled Actions
|
|
59
|
+
|
|
60
|
+
Scheduled Actions let you run tasks in the background:
|
|
61
|
+
|
|
62
|
+
┌─────────────────────────────────────────────┐
|
|
63
|
+
│ SCHEDULED ACTIONS SYSTEM │
|
|
64
|
+
│ ───────────────────────────────────────── │
|
|
65
|
+
│ │
|
|
66
|
+
│ • One-time tasks (run at specific time) │
|
|
67
|
+
│ • Recurring tasks (cron expressions) │
|
|
68
|
+
│ • Webhook-triggered tasks │
|
|
69
|
+
│ • Queue-based processing │
|
|
70
|
+
│ │
|
|
71
|
+
└─────────────────────────────────────────────┘
|
|
72
|
+
|
|
73
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
74
|
+
|
|
75
|
+
📂 Architecture:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Scheduler
|
|
79
|
+
│
|
|
80
|
+
├──→ Database Queue (scheduled_actions table)
|
|
81
|
+
│ │
|
|
82
|
+
│ ├── Pending actions
|
|
83
|
+
│ ├── Running actions
|
|
84
|
+
│ └── Completed/Failed actions
|
|
85
|
+
│
|
|
86
|
+
├──→ Webhook Endpoint (/api/v1/cron)
|
|
87
|
+
│
|
|
88
|
+
└──→ Action Handlers (core/lib/actions/)
|
|
89
|
+
│
|
|
90
|
+
├── email.handler.ts
|
|
91
|
+
├── cleanup.handler.ts
|
|
92
|
+
└── custom.handler.ts
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
96
|
+
|
|
97
|
+
📋 Use Cases:
|
|
98
|
+
|
|
99
|
+
• Send reminder emails
|
|
100
|
+
• Clean up expired data
|
|
101
|
+
• Generate reports
|
|
102
|
+
• Sync with external services
|
|
103
|
+
• Process queued jobs
|
|
104
|
+
• Recurring maintenance tasks
|
|
105
|
+
|
|
106
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
107
|
+
|
|
108
|
+
What would you like to do?
|
|
109
|
+
|
|
110
|
+
[1] Continue to Step 2 (Create Handler)
|
|
111
|
+
[2] How does the queue work?
|
|
112
|
+
[3] Show me the database schema
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Step 2: Create an Action Handler
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
121
|
+
STEP 2 OF 5: Create an Action Handler
|
|
122
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
123
|
+
|
|
124
|
+
Create a handler to define what the action does:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// core/lib/actions/handlers/send-reminder-email.handler.ts
|
|
128
|
+
import type { ActionHandler, ActionResult } from '@/core/types/actions'
|
|
129
|
+
import { z } from 'zod'
|
|
130
|
+
import { EmailService } from '@/core/lib/services/email.service'
|
|
131
|
+
|
|
132
|
+
// Define payload schema
|
|
133
|
+
const SendReminderPayloadSchema = z.object({
|
|
134
|
+
userId: z.string().uuid(),
|
|
135
|
+
taskId: z.string().uuid(),
|
|
136
|
+
taskName: z.string(),
|
|
137
|
+
dueDate: z.string().datetime(),
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
type SendReminderPayload = z.infer<typeof SendReminderPayloadSchema>
|
|
141
|
+
|
|
142
|
+
export const sendReminderEmailHandler: ActionHandler<SendReminderPayload> = {
|
|
143
|
+
// Unique identifier
|
|
144
|
+
type: 'send-reminder-email',
|
|
145
|
+
|
|
146
|
+
// Display name for logs
|
|
147
|
+
name: 'Send Reminder Email',
|
|
148
|
+
|
|
149
|
+
// Payload validation
|
|
150
|
+
schema: SendReminderPayloadSchema,
|
|
151
|
+
|
|
152
|
+
// Execution logic
|
|
153
|
+
async execute(payload, context): Promise<ActionResult> {
|
|
154
|
+
const { userId, taskId, taskName, dueDate } = payload
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
// Get user email
|
|
158
|
+
const user = await UserService.getById(userId)
|
|
159
|
+
if (!user?.email) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: 'User not found or no email',
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Send the email
|
|
167
|
+
await EmailService.send({
|
|
168
|
+
to: user.email,
|
|
169
|
+
template: 'task-reminder',
|
|
170
|
+
data: {
|
|
171
|
+
userName: user.name,
|
|
172
|
+
taskName,
|
|
173
|
+
dueDate: new Date(dueDate).toLocaleDateString(),
|
|
174
|
+
taskUrl: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard/tasks/${taskId}`,
|
|
175
|
+
},
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
success: true,
|
|
180
|
+
message: `Reminder sent to ${user.email}`,
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
186
|
+
retryable: true, // Allow retry on failure
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
// Optional: Retry configuration
|
|
192
|
+
retry: {
|
|
193
|
+
maxAttempts: 3,
|
|
194
|
+
backoffMs: 5000, // 5 seconds between retries
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export default sendReminderEmailHandler
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
202
|
+
|
|
203
|
+
📋 Handler Structure:
|
|
204
|
+
|
|
205
|
+
• type: Unique identifier for the action
|
|
206
|
+
• name: Human-readable name
|
|
207
|
+
• schema: Zod schema for payload validation
|
|
208
|
+
• execute: Async function with the logic
|
|
209
|
+
• retry: Optional retry configuration
|
|
210
|
+
|
|
211
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
212
|
+
|
|
213
|
+
2️⃣ Register the handler:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// core/lib/actions/registry.ts
|
|
217
|
+
import { sendReminderEmailHandler } from './handlers/send-reminder-email.handler'
|
|
218
|
+
|
|
219
|
+
export const ACTION_HANDLERS = {
|
|
220
|
+
'send-reminder-email': sendReminderEmailHandler,
|
|
221
|
+
// ... other handlers
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
226
|
+
|
|
227
|
+
What would you like to do?
|
|
228
|
+
|
|
229
|
+
[1] Continue to Step 3 (Schedule Action)
|
|
230
|
+
[2] Show me more handler examples
|
|
231
|
+
[3] How do I handle errors?
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Step 3: Schedule the Action
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
240
|
+
STEP 3 OF 5: Schedule the Action
|
|
241
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
242
|
+
|
|
243
|
+
Schedule actions programmatically:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// core/lib/services/scheduled-action.service.ts
|
|
247
|
+
import { ScheduledActionService } from '@/core/lib/services/scheduled-action.service'
|
|
248
|
+
|
|
249
|
+
// 1. Schedule a one-time action
|
|
250
|
+
await ScheduledActionService.schedule({
|
|
251
|
+
type: 'send-reminder-email',
|
|
252
|
+
payload: {
|
|
253
|
+
userId: 'user-123',
|
|
254
|
+
taskId: 'task-456',
|
|
255
|
+
taskName: 'Complete project proposal',
|
|
256
|
+
dueDate: '2024-01-15T09:00:00Z',
|
|
257
|
+
},
|
|
258
|
+
scheduledFor: new Date('2024-01-14T09:00:00Z'), // 1 day before
|
|
259
|
+
teamId: 'team-789', // For team context
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// 2. Schedule a recurring action (cron)
|
|
263
|
+
await ScheduledActionService.scheduleRecurring({
|
|
264
|
+
type: 'cleanup-expired-sessions',
|
|
265
|
+
payload: {},
|
|
266
|
+
cron: '0 2 * * *', // Every day at 2 AM
|
|
267
|
+
name: 'Daily Session Cleanup',
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
// 3. Schedule relative to an event
|
|
271
|
+
await ScheduledActionService.scheduleRelative({
|
|
272
|
+
type: 'send-follow-up',
|
|
273
|
+
payload: { invoiceId: 'inv-123' },
|
|
274
|
+
delayMs: 7 * 24 * 60 * 60 * 1000, // 7 days from now
|
|
275
|
+
})
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
279
|
+
|
|
280
|
+
📋 Cron Expression Examples:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
* * * * *
|
|
284
|
+
│ │ │ │ │
|
|
285
|
+
│ │ │ │ └── Day of week (0-6, Sunday=0)
|
|
286
|
+
│ │ │ └──── Month (1-12)
|
|
287
|
+
│ │ └────── Day of month (1-31)
|
|
288
|
+
│ └──────── Hour (0-23)
|
|
289
|
+
└────────── Minute (0-59)
|
|
290
|
+
|
|
291
|
+
Common patterns:
|
|
292
|
+
• '0 * * * *' - Every hour
|
|
293
|
+
• '0 0 * * *' - Every day at midnight
|
|
294
|
+
• '0 9 * * 1' - Every Monday at 9 AM
|
|
295
|
+
• '0 0 1 * *' - First day of month
|
|
296
|
+
• '*/15 * * * *' - Every 15 minutes
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
300
|
+
|
|
301
|
+
📋 In Your Code (e.g., when creating a task):
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// app/api/v1/entities/tasks/route.ts
|
|
305
|
+
export async function POST(request: NextRequest) {
|
|
306
|
+
// ... create task ...
|
|
307
|
+
|
|
308
|
+
// Schedule reminder if task has due date
|
|
309
|
+
if (task.dueDate && task.assignedTo) {
|
|
310
|
+
const reminderDate = new Date(task.dueDate)
|
|
311
|
+
reminderDate.setDate(reminderDate.getDate() - 1) // 1 day before
|
|
312
|
+
|
|
313
|
+
await ScheduledActionService.schedule({
|
|
314
|
+
type: 'send-reminder-email',
|
|
315
|
+
payload: {
|
|
316
|
+
userId: task.assignedTo,
|
|
317
|
+
taskId: task.id,
|
|
318
|
+
taskName: task.name,
|
|
319
|
+
dueDate: task.dueDate,
|
|
320
|
+
},
|
|
321
|
+
scheduledFor: reminderDate,
|
|
322
|
+
teamId,
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return Response.json({ success: true, data: task })
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
331
|
+
|
|
332
|
+
What would you like to do?
|
|
333
|
+
|
|
334
|
+
[1] Continue to Step 4 (Webhooks)
|
|
335
|
+
[2] How do I cancel a scheduled action?
|
|
336
|
+
[3] Show me the database schema
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Step 4: Configure Webhooks
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
345
|
+
STEP 4 OF 5: Configure Webhooks
|
|
346
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
347
|
+
|
|
348
|
+
The cron endpoint processes scheduled actions:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// app/api/v1/cron/route.ts
|
|
352
|
+
import { processScheduledActions } from '@/core/lib/actions/processor'
|
|
353
|
+
import { verifyCronSecret } from '@/core/lib/auth/cron'
|
|
354
|
+
|
|
355
|
+
export async function POST(request: NextRequest) {
|
|
356
|
+
// Verify the request is from authorized source
|
|
357
|
+
const authHeader = request.headers.get('authorization')
|
|
358
|
+
if (!verifyCronSecret(authHeader)) {
|
|
359
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401 })
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Process pending actions
|
|
363
|
+
const result = await processScheduledActions({
|
|
364
|
+
maxActions: 100, // Process up to 100 actions per call
|
|
365
|
+
timeout: 55000, // 55 second timeout (for 60s cron)
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
return Response.json({
|
|
369
|
+
success: true,
|
|
370
|
+
processed: result.processed,
|
|
371
|
+
failed: result.failed,
|
|
372
|
+
remaining: result.remaining,
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
378
|
+
|
|
379
|
+
📋 Configure External Cron Service:
|
|
380
|
+
|
|
381
|
+
**Option 1: Vercel Cron Jobs**
|
|
382
|
+
|
|
383
|
+
```json
|
|
384
|
+
// vercel.json
|
|
385
|
+
{
|
|
386
|
+
"crons": [
|
|
387
|
+
{
|
|
388
|
+
"path": "/api/v1/cron",
|
|
389
|
+
"schedule": "* * * * *"
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Option 2: External Cron Service (cron-job.org)**
|
|
396
|
+
|
|
397
|
+
URL: `https://your-domain.com/api/v1/cron`
|
|
398
|
+
Method: POST
|
|
399
|
+
Headers: `Authorization: Bearer YOUR_CRON_SECRET`
|
|
400
|
+
Schedule: Every minute
|
|
401
|
+
|
|
402
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
403
|
+
|
|
404
|
+
📋 Environment Variables:
|
|
405
|
+
|
|
406
|
+
```env
|
|
407
|
+
# .env
|
|
408
|
+
CRON_SECRET=your-secure-random-string
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
412
|
+
|
|
413
|
+
📋 Manual Trigger (development):
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
curl -X POST http://localhost:3000/api/v1/cron \
|
|
417
|
+
-H "Authorization: Bearer your-cron-secret"
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
421
|
+
|
|
422
|
+
What would you like to do?
|
|
423
|
+
|
|
424
|
+
[1] Continue to Step 5 (Monitor)
|
|
425
|
+
[2] How do I secure the webhook?
|
|
426
|
+
[3] Show me Vercel cron setup
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Step 5: Monitor and Debug
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
435
|
+
STEP 5 OF 5: Monitor and Debug
|
|
436
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
437
|
+
|
|
438
|
+
📋 View Action Status:
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
// Get scheduled actions for a team
|
|
442
|
+
const actions = await ScheduledActionService.list({
|
|
443
|
+
teamId: 'team-123',
|
|
444
|
+
status: 'pending', // pending | running | completed | failed
|
|
445
|
+
type: 'send-reminder-email', // optional filter
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
// Get action by ID
|
|
449
|
+
const action = await ScheduledActionService.getById('action-123')
|
|
450
|
+
console.log(action.status) // 'completed'
|
|
451
|
+
console.log(action.result) // { success: true, message: '...' }
|
|
452
|
+
console.log(action.executedAt) // '2024-01-14T09:00:15Z'
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
456
|
+
|
|
457
|
+
📋 Action Statuses:
|
|
458
|
+
|
|
459
|
+
• pending - Waiting to be executed
|
|
460
|
+
• running - Currently executing
|
|
461
|
+
• completed - Successfully finished
|
|
462
|
+
• failed - Execution failed
|
|
463
|
+
• cancelled - Manually cancelled
|
|
464
|
+
|
|
465
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
466
|
+
|
|
467
|
+
📋 Dashboard Integration:
|
|
468
|
+
|
|
469
|
+
Access the scheduled actions dashboard:
|
|
470
|
+
`/superadmin/scheduled-actions`
|
|
471
|
+
|
|
472
|
+
Features:
|
|
473
|
+
• View all scheduled actions
|
|
474
|
+
• Filter by status, type, team
|
|
475
|
+
• Manually retry failed actions
|
|
476
|
+
• Cancel pending actions
|
|
477
|
+
• View execution logs
|
|
478
|
+
|
|
479
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
480
|
+
|
|
481
|
+
📋 Debug Logging:
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
// In your handler
|
|
485
|
+
export const myHandler: ActionHandler = {
|
|
486
|
+
async execute(payload, context) {
|
|
487
|
+
// Access logger from context
|
|
488
|
+
context.log.info('Starting action', { payload })
|
|
489
|
+
|
|
490
|
+
try {
|
|
491
|
+
// ... logic ...
|
|
492
|
+
context.log.info('Action completed', { result })
|
|
493
|
+
return { success: true }
|
|
494
|
+
} catch (error) {
|
|
495
|
+
context.log.error('Action failed', { error })
|
|
496
|
+
return { success: false, error: error.message }
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
503
|
+
|
|
504
|
+
✅ TUTORIAL STORY!
|
|
505
|
+
|
|
506
|
+
You've learned:
|
|
507
|
+
• How scheduled actions work
|
|
508
|
+
• Creating action handlers
|
|
509
|
+
• Scheduling one-time and recurring tasks
|
|
510
|
+
• Webhook configuration
|
|
511
|
+
• Monitoring and debugging
|
|
512
|
+
|
|
513
|
+
📚 Related tutorials:
|
|
514
|
+
• /how-to:create-api - Custom API endpoints
|
|
515
|
+
• /how-to:create-plugin - Add actions in plugins
|
|
516
|
+
|
|
517
|
+
🔙 Back to menu: /how-to:start
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## Related Commands
|
|
523
|
+
|
|
524
|
+
| Command | Action |
|
|
525
|
+
|---------|--------|
|
|
526
|
+
| `/how-to:create-api` | Custom API endpoints |
|
|
527
|
+
| `/how-to:create-plugin` | Plugin with scheduled actions |
|