@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,577 @@
|
|
|
1
|
+
# /how-to:create-api
|
|
2
|
+
|
|
3
|
+
Interactive guide to create custom API endpoints in NextSpark.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Required Skills
|
|
8
|
+
|
|
9
|
+
Before executing, these skills provide deeper context:
|
|
10
|
+
- `.claude/skills/nextjs-api-development/SKILL.md` - API routes and dual auth
|
|
11
|
+
- `.claude/skills/entity-api/SKILL.md` - Dynamic entity endpoints
|
|
12
|
+
- `.claude/skills/zod-validation/SKILL.md` - Input validation patterns
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Syntax
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
/how-to:create-api
|
|
20
|
+
/how-to:create-api [endpoint-name]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Behavior
|
|
26
|
+
|
|
27
|
+
Guides the user through creating custom API endpoints with dual authentication, validation, and proper error handling.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Tutorial Structure
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
STEPS OVERVIEW (5 steps)
|
|
35
|
+
|
|
36
|
+
Step 1: Understanding API Patterns
|
|
37
|
+
└── Entity vs Custom endpoints
|
|
38
|
+
|
|
39
|
+
Step 2: Create Route Handler
|
|
40
|
+
└── Next.js App Router API
|
|
41
|
+
|
|
42
|
+
Step 3: Implement Dual Authentication
|
|
43
|
+
└── Session + API Key support
|
|
44
|
+
|
|
45
|
+
Step 4: Add Validation & Error Handling
|
|
46
|
+
└── Zod schemas and responses
|
|
47
|
+
|
|
48
|
+
Step 5: Test Your Endpoint
|
|
49
|
+
└── Verify with curl/Postman
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Step 1: Understanding API Patterns
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
58
|
+
📚 HOW TO: CREATE AN API
|
|
59
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
60
|
+
|
|
61
|
+
STEP 1 OF 5: Understanding API Patterns
|
|
62
|
+
|
|
63
|
+
NextSpark has two types of API endpoints:
|
|
64
|
+
|
|
65
|
+
┌─────────────────────────────────────────────┐
|
|
66
|
+
│ ENTITY ENDPOINTS (Automatic) │
|
|
67
|
+
│ ───────────────────────────────────────── │
|
|
68
|
+
│ Path: /api/v1/entities/{entity} │
|
|
69
|
+
│ Auto-generated from entity config │
|
|
70
|
+
│ Standard CRUD operations │
|
|
71
|
+
│ ───────────────────────────────────────── │
|
|
72
|
+
│ GET, POST, PATCH, DELETE │
|
|
73
|
+
└─────────────────────────────────────────────┘
|
|
74
|
+
|
|
75
|
+
┌─────────────────────────────────────────────┐
|
|
76
|
+
│ CUSTOM ENDPOINTS (Manual) │
|
|
77
|
+
│ ───────────────────────────────────────── │
|
|
78
|
+
│ Path: /api/v1/{feature}/{action} │
|
|
79
|
+
│ Custom business logic │
|
|
80
|
+
│ Complex operations │
|
|
81
|
+
│ ───────────────────────────────────────── │
|
|
82
|
+
│ Full control over request/response │
|
|
83
|
+
└─────────────────────────────────────────────┘
|
|
84
|
+
|
|
85
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
86
|
+
|
|
87
|
+
📋 When to Use Custom Endpoints:
|
|
88
|
+
|
|
89
|
+
• Business logic beyond CRUD
|
|
90
|
+
• Aggregations and reports
|
|
91
|
+
• Integration with external services
|
|
92
|
+
• Complex multi-step operations
|
|
93
|
+
• Batch operations
|
|
94
|
+
• Custom authentication flows
|
|
95
|
+
|
|
96
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
97
|
+
|
|
98
|
+
📂 File Structure:
|
|
99
|
+
|
|
100
|
+
app/api/v1/
|
|
101
|
+
├── entities/ # Auto-generated entity APIs
|
|
102
|
+
│ └── [entity]/
|
|
103
|
+
│ └── route.ts
|
|
104
|
+
├── billing/ # Custom: Billing endpoints
|
|
105
|
+
│ ├── checkout/route.ts
|
|
106
|
+
│ └── portal/route.ts
|
|
107
|
+
├── reports/ # Custom: Reporting endpoints
|
|
108
|
+
│ └── sales/route.ts
|
|
109
|
+
└── integrations/ # Custom: External integrations
|
|
110
|
+
└── webhook/route.ts
|
|
111
|
+
|
|
112
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
113
|
+
|
|
114
|
+
What would you like to do?
|
|
115
|
+
|
|
116
|
+
[1] Continue to Step 2 (Create Route Handler)
|
|
117
|
+
[2] Show me entity endpoint examples
|
|
118
|
+
[3] What's the difference in authentication?
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Step 2: Create Route Handler
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
127
|
+
STEP 2 OF 5: Create Route Handler
|
|
128
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
129
|
+
|
|
130
|
+
Create a new API route in Next.js App Router:
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**📋 Route Handler Example:**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// app/api/v1/reports/sales/route.ts
|
|
137
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
138
|
+
import { authenticateRequest } from '@/core/lib/auth/authenticateRequest'
|
|
139
|
+
import { checkPermission } from '@/core/lib/permissions/check'
|
|
140
|
+
import { createApiResponse, createApiError } from '@/core/lib/api/response'
|
|
141
|
+
import { SalesReportService } from '@/core/lib/services/sales-report.service'
|
|
142
|
+
import { z } from 'zod'
|
|
143
|
+
|
|
144
|
+
// Query parameters schema
|
|
145
|
+
const QuerySchema = z.object({
|
|
146
|
+
startDate: z.string().datetime().optional(),
|
|
147
|
+
endDate: z.string().datetime().optional(),
|
|
148
|
+
groupBy: z.enum(['day', 'week', 'month']).default('day'),
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
export async function GET(request: NextRequest) {
|
|
152
|
+
try {
|
|
153
|
+
// 1. Authenticate (supports both session and API key)
|
|
154
|
+
const auth = await authenticateRequest(request)
|
|
155
|
+
if (!auth.isAuthenticated) {
|
|
156
|
+
return createApiError('Unauthorized', 401)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const { userId, teamId } = auth
|
|
160
|
+
|
|
161
|
+
// 2. Check permissions
|
|
162
|
+
const canViewReports = await checkPermission(userId, teamId, 'reports.view')
|
|
163
|
+
if (!canViewReports) {
|
|
164
|
+
return createApiError('Permission denied', 403)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 3. Parse and validate query parameters
|
|
168
|
+
const searchParams = Object.fromEntries(request.nextUrl.searchParams)
|
|
169
|
+
const params = QuerySchema.parse(searchParams)
|
|
170
|
+
|
|
171
|
+
// 4. Execute business logic
|
|
172
|
+
const report = await SalesReportService.generate({
|
|
173
|
+
teamId,
|
|
174
|
+
startDate: params.startDate,
|
|
175
|
+
endDate: params.endDate,
|
|
176
|
+
groupBy: params.groupBy,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// 5. Return success response
|
|
180
|
+
return createApiResponse({
|
|
181
|
+
data: report,
|
|
182
|
+
meta: {
|
|
183
|
+
generatedAt: new Date().toISOString(),
|
|
184
|
+
period: { start: params.startDate, end: params.endDate },
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
} catch (error) {
|
|
188
|
+
// Handle validation errors
|
|
189
|
+
if (error instanceof z.ZodError) {
|
|
190
|
+
return createApiError('Validation error', 400, error.errors)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Log and return generic error
|
|
194
|
+
console.error('[Sales Report API]', error)
|
|
195
|
+
return createApiError('Internal server error', 500)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**📋 Route Handler Pattern:**
|
|
201
|
+
|
|
202
|
+
1. Authenticate request
|
|
203
|
+
2. Check permissions
|
|
204
|
+
3. Validate input (query/body)
|
|
205
|
+
4. Execute business logic
|
|
206
|
+
5. Return standardized response
|
|
207
|
+
6. Handle errors gracefully
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
211
|
+
|
|
212
|
+
What would you like to do?
|
|
213
|
+
|
|
214
|
+
[1] Continue to Step 3 (Dual Authentication)
|
|
215
|
+
[2] Show me POST endpoint example
|
|
216
|
+
[3] How do I handle file uploads?
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Step 3: Implement Dual Authentication
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
225
|
+
STEP 3 OF 5: Implement Dual Authentication
|
|
226
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
227
|
+
|
|
228
|
+
NextSpark supports dual authentication:
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**📋 Auth Result Type:**
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// core/lib/auth/authenticateRequest.ts
|
|
235
|
+
|
|
236
|
+
type AuthResult = {
|
|
237
|
+
isAuthenticated: boolean
|
|
238
|
+
userId?: string
|
|
239
|
+
teamId?: string
|
|
240
|
+
authMethod: 'session' | 'api_key' | null
|
|
241
|
+
apiKeyScopes?: string[] // For API key auth
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export async function authenticateRequest(
|
|
245
|
+
request: NextRequest
|
|
246
|
+
): Promise<AuthResult>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**📋 Authentication Methods:**
|
|
250
|
+
|
|
251
|
+
**1. Session Authentication (Browser)**
|
|
252
|
+
|
|
253
|
+
User is logged in via browser. Session cookie sent automatically.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Request from browser (automatic)
|
|
257
|
+
const auth = await authenticateRequest(request)
|
|
258
|
+
// auth.authMethod === 'session'
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**2. API Key Authentication (External)**
|
|
262
|
+
|
|
263
|
+
For server-to-server or external integrations.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Request with API key header
|
|
267
|
+
// Authorization: Bearer sk_xxx
|
|
268
|
+
const auth = await authenticateRequest(request)
|
|
269
|
+
// auth.authMethod === 'api_key'
|
|
270
|
+
// auth.apiKeyScopes === ['reports:read', 'entities:read']
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**📋 Using Authentication in Your Endpoint:**
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
export async function GET(request: NextRequest) {
|
|
277
|
+
const auth = await authenticateRequest(request)
|
|
278
|
+
|
|
279
|
+
// Check if authenticated
|
|
280
|
+
if (!auth.isAuthenticated) {
|
|
281
|
+
return createApiError('Unauthorized', 401)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Destructure common values
|
|
285
|
+
const { userId, teamId, authMethod } = auth
|
|
286
|
+
|
|
287
|
+
// Optional: Check API key scopes
|
|
288
|
+
if (authMethod === 'api_key') {
|
|
289
|
+
const hasScope = auth.apiKeyScopes?.includes('reports:read')
|
|
290
|
+
if (!hasScope) {
|
|
291
|
+
return createApiError('Insufficient scope', 403)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Continue with authenticated request...
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**📋 API Key Scopes:**
|
|
300
|
+
|
|
301
|
+
Scopes control what an API key can access:
|
|
302
|
+
|
|
303
|
+
- `entities:read` - Read entity data
|
|
304
|
+
- `entities:write` - Create/update entities
|
|
305
|
+
- `entities:delete` - Delete entities
|
|
306
|
+
- `reports:read` - View reports
|
|
307
|
+
- `billing:manage` - Manage subscriptions
|
|
308
|
+
- `team:manage` - Manage team members
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
312
|
+
|
|
313
|
+
What would you like to do?
|
|
314
|
+
|
|
315
|
+
[1] Continue to Step 4 (Validation)
|
|
316
|
+
[2] How do I create API keys?
|
|
317
|
+
[3] Show me scope checking examples
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Step 4: Add Validation & Error Handling
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
326
|
+
STEP 4 OF 5: Add Validation & Error Handling
|
|
327
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**📋 Input Validation with Zod:**
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// Define request body schema
|
|
334
|
+
const CreateOrderSchema = z.object({
|
|
335
|
+
customerId: z.string().uuid(),
|
|
336
|
+
items: z.array(z.object({
|
|
337
|
+
productId: z.string().uuid(),
|
|
338
|
+
quantity: z.number().int().min(1).max(100),
|
|
339
|
+
price: z.number().positive(),
|
|
340
|
+
})).min(1).max(50),
|
|
341
|
+
notes: z.string().max(500).optional(),
|
|
342
|
+
shippingAddress: z.object({
|
|
343
|
+
street: z.string().min(1).max(200),
|
|
344
|
+
city: z.string().min(1).max(100),
|
|
345
|
+
postalCode: z.string().min(1).max(20),
|
|
346
|
+
country: z.string().length(2),
|
|
347
|
+
}),
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
export async function POST(request: NextRequest) {
|
|
351
|
+
// ... authentication ...
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
// Parse and validate body
|
|
355
|
+
const body = await request.json()
|
|
356
|
+
const data = CreateOrderSchema.parse(body)
|
|
357
|
+
|
|
358
|
+
// data is fully typed and validated
|
|
359
|
+
const order = await OrderService.create(data)
|
|
360
|
+
|
|
361
|
+
return createApiResponse({ data: order }, { status: 201 })
|
|
362
|
+
} catch (error) {
|
|
363
|
+
if (error instanceof z.ZodError) {
|
|
364
|
+
return createApiError('Validation error', 400, {
|
|
365
|
+
errors: error.errors.map(e => ({
|
|
366
|
+
field: e.path.join('.'),
|
|
367
|
+
message: e.message,
|
|
368
|
+
})),
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
throw error
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**📋 Standardized API Response Format:**
|
|
377
|
+
|
|
378
|
+
```json
|
|
379
|
+
// Success response
|
|
380
|
+
{
|
|
381
|
+
"success": true,
|
|
382
|
+
"data": { "..." },
|
|
383
|
+
"meta": {
|
|
384
|
+
"page": 1,
|
|
385
|
+
"total": 100
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Error response
|
|
390
|
+
{
|
|
391
|
+
"success": false,
|
|
392
|
+
"error": {
|
|
393
|
+
"code": "VALIDATION_ERROR",
|
|
394
|
+
"message": "Validation error",
|
|
395
|
+
"details": [
|
|
396
|
+
{ "field": "items", "message": "Required" }
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**📋 Response Helpers:**
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { createApiResponse, createApiError } from '@/core/lib/api/response'
|
|
406
|
+
|
|
407
|
+
// Success responses
|
|
408
|
+
createApiResponse({ data: result }) // 200
|
|
409
|
+
createApiResponse({ data: result }, { status: 201 }) // 201 Created
|
|
410
|
+
|
|
411
|
+
// Error responses
|
|
412
|
+
createApiError('Unauthorized', 401)
|
|
413
|
+
createApiError('Not found', 404)
|
|
414
|
+
createApiError('Validation error', 400, { errors: [...] })
|
|
415
|
+
createApiError('Rate limit exceeded', 429, { retryAfter: 60 })
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**📋 Error Handling Best Practices:**
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
export async function POST(request: NextRequest) {
|
|
422
|
+
try {
|
|
423
|
+
// ... your logic ...
|
|
424
|
+
} catch (error) {
|
|
425
|
+
// 1. Validation errors (Zod)
|
|
426
|
+
if (error instanceof z.ZodError) {
|
|
427
|
+
return createApiError('Validation error', 400, error.errors)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// 2. Known business errors
|
|
431
|
+
if (error instanceof InsufficientBalanceError) {
|
|
432
|
+
return createApiError('Insufficient balance', 402, {
|
|
433
|
+
required: error.required,
|
|
434
|
+
available: error.available,
|
|
435
|
+
})
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// 3. Not found errors
|
|
439
|
+
if (error instanceof NotFoundError) {
|
|
440
|
+
return createApiError('Resource not found', 404)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 4. Unknown errors (log and return generic)
|
|
444
|
+
console.error('[API Error]', error)
|
|
445
|
+
return createApiError('Internal server error', 500)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
452
|
+
|
|
453
|
+
What would you like to do?
|
|
454
|
+
|
|
455
|
+
[1] Continue to Step 5 (Testing)
|
|
456
|
+
[2] Show me pagination examples
|
|
457
|
+
[3] How do I handle rate limiting?
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Step 5: Test Your Endpoint
|
|
463
|
+
|
|
464
|
+
```
|
|
465
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
466
|
+
STEP 5 OF 5: Test Your Endpoint
|
|
467
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
**📋 Test with curl:**
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# GET request with session cookie
|
|
474
|
+
curl http://localhost:3000/api/v1/reports/sales \
|
|
475
|
+
-H "Cookie: better-auth.session_token=xxx"
|
|
476
|
+
|
|
477
|
+
# GET request with API key
|
|
478
|
+
curl http://localhost:3000/api/v1/reports/sales \
|
|
479
|
+
-H "Authorization: Bearer sk_xxx"
|
|
480
|
+
|
|
481
|
+
# POST request with body
|
|
482
|
+
curl -X POST http://localhost:3000/api/v1/orders \
|
|
483
|
+
-H "Authorization: Bearer sk_xxx" \
|
|
484
|
+
-H "Content-Type: application/json" \
|
|
485
|
+
-d '{
|
|
486
|
+
"customerId": "cust-123",
|
|
487
|
+
"items": [
|
|
488
|
+
{ "productId": "prod-456", "quantity": 2, "price": 29.99 }
|
|
489
|
+
],
|
|
490
|
+
"shippingAddress": {
|
|
491
|
+
"street": "123 Main St",
|
|
492
|
+
"city": "New York",
|
|
493
|
+
"postalCode": "10001",
|
|
494
|
+
"country": "US"
|
|
495
|
+
}
|
|
496
|
+
}'
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**📋 Test with Cypress (API tests):**
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
// cypress/e2e/api/orders.cy.ts
|
|
503
|
+
describe('Orders API', () => {
|
|
504
|
+
beforeEach(() => {
|
|
505
|
+
cy.getApiKey().as('apiKey')
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
it('should create an order', function() {
|
|
509
|
+
cy.request({
|
|
510
|
+
method: 'POST',
|
|
511
|
+
url: '/api/v1/orders',
|
|
512
|
+
headers: {
|
|
513
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
514
|
+
},
|
|
515
|
+
body: {
|
|
516
|
+
customerId: 'cust-123',
|
|
517
|
+
items: [{ productId: 'prod-456', quantity: 2, price: 29.99 }],
|
|
518
|
+
shippingAddress: {
|
|
519
|
+
street: '123 Main St',
|
|
520
|
+
city: 'New York',
|
|
521
|
+
postalCode: '10001',
|
|
522
|
+
country: 'US',
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
}).then((response) => {
|
|
526
|
+
expect(response.status).to.eq(201)
|
|
527
|
+
expect(response.body.success).to.be.true
|
|
528
|
+
expect(response.body.data.id).to.exist
|
|
529
|
+
})
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
it('should return validation error for invalid input', function() {
|
|
533
|
+
cy.request({
|
|
534
|
+
method: 'POST',
|
|
535
|
+
url: '/api/v1/orders',
|
|
536
|
+
headers: {
|
|
537
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
538
|
+
},
|
|
539
|
+
body: {
|
|
540
|
+
customerId: 'invalid', // Not a UUID
|
|
541
|
+
},
|
|
542
|
+
failOnStatusCode: false,
|
|
543
|
+
}).then((response) => {
|
|
544
|
+
expect(response.status).to.eq(400)
|
|
545
|
+
expect(response.body.success).to.be.false
|
|
546
|
+
})
|
|
547
|
+
})
|
|
548
|
+
})
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
553
|
+
|
|
554
|
+
✅ TUTORIAL STORY!
|
|
555
|
+
|
|
556
|
+
You've learned:
|
|
557
|
+
• Custom API endpoint structure
|
|
558
|
+
• Dual authentication (session + API key)
|
|
559
|
+
• Input validation with Zod
|
|
560
|
+
• Standardized error handling
|
|
561
|
+
• Testing with curl and Cypress
|
|
562
|
+
|
|
563
|
+
📚 Related tutorials:
|
|
564
|
+
• /how-to:create-entity - Auto-generated CRUD APIs
|
|
565
|
+
• /how-to:set-scheduled-actions - Background tasks
|
|
566
|
+
|
|
567
|
+
🔙 Back to menu: /how-to:start
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Related Commands
|
|
573
|
+
|
|
574
|
+
| Command | Action |
|
|
575
|
+
|---------|--------|
|
|
576
|
+
| `/how-to:create-entity` | Auto-generated entity APIs |
|
|
577
|
+
| `/session:test:write` | Write API tests |
|