@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.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,481 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Scaffold API Endpoint Script
4
+
5
+ Creates the file structure for a new API endpoint following Next.js 15 App Router patterns.
6
+
7
+ Usage:
8
+ python scaffold-endpoint.py --name ENDPOINT_NAME [--methods METHODS] [--auth AUTH_TYPE]
9
+
10
+ Options:
11
+ --name ENDPOINT_NAME Name of the endpoint (kebab-case)
12
+ --methods METHODS Comma-separated HTTP methods (default: GET,POST)
13
+ --auth AUTH_TYPE Authentication type: required, optional, none (default: required)
14
+ --override Create in (contents)/ folder for custom logic
15
+ --with-id Include [id] route for single resource operations
16
+ """
17
+
18
+ import os
19
+ import sys
20
+ import argparse
21
+ from pathlib import Path
22
+ from datetime import datetime
23
+
24
+
25
+ def to_camel_case(name: str) -> str:
26
+ """Convert kebab-case to camelCase."""
27
+ components = name.split('-')
28
+ return components[0] + ''.join(x.title() for x in components[1:])
29
+
30
+
31
+ def to_pascal_case(name: str) -> str:
32
+ """Convert kebab-case to PascalCase."""
33
+ return ''.join(x.title() for x in name.split('-'))
34
+
35
+
36
+ def to_snake_case(name: str) -> str:
37
+ """Convert kebab-case to snake_case."""
38
+ return name.replace('-', '_')
39
+
40
+
41
+ def generate_list_route(name: str, methods: list, auth_type: str) -> str:
42
+ """Generate list/create route file."""
43
+ pascal = to_pascal_case(name)
44
+ singular = name.rstrip('s')
45
+ methods_str = ', '.join(methods)
46
+
47
+ # Build imports
48
+ imports = [
49
+ "import { NextRequest, NextResponse } from 'next/server'",
50
+ "import { queryWithRLS, mutateWithRLS } from '@/core/lib/db'",
51
+ ]
52
+
53
+ helper_imports = [
54
+ "createApiResponse",
55
+ "createApiError",
56
+ "withApiLogging",
57
+ "handleCorsPreflightRequest",
58
+ "addCorsHeaders",
59
+ ]
60
+ if 'GET' in methods:
61
+ helper_imports.extend(["createPaginationMeta", "parsePaginationParams"])
62
+
63
+ imports.append(f"import {{ {', '.join(helper_imports)} }} from '@/core/lib/api/helpers'")
64
+
65
+ if auth_type == 'required':
66
+ imports.append("import { authenticateRequest } from '@/core/lib/api/auth/dual-auth'")
67
+
68
+ if 'POST' in methods or 'PATCH' in methods:
69
+ imports.append("import { z } from 'zod'")
70
+
71
+ # Build endpoint comments
72
+ endpoint_lines = []
73
+ for m in methods:
74
+ endpoint_lines.append(f" * {m} /api/v1/{name}")
75
+
76
+ code = f'''/**
77
+ * {pascal} API Route
78
+ *
79
+ * Handles list and create operations for {name}.
80
+ *
81
+ * Endpoints:
82
+ {chr(10).join(endpoint_lines)}
83
+ */
84
+
85
+ {chr(10).join(imports)}
86
+ '''
87
+
88
+ # Add schema if POST
89
+ if 'POST' in methods:
90
+ code += f'''
91
+ // Validation schema for creating {singular}
92
+ const Create{pascal}Schema = z.object({{
93
+ title: z.string().min(1).max(255),
94
+ description: z.string().optional(),
95
+ // Add more fields as needed
96
+ }})
97
+ '''
98
+
99
+ # OPTIONS handler
100
+ code += '''
101
+ // Handle CORS preflight
102
+ export async function OPTIONS() {
103
+ return handleCorsPreflightRequest()
104
+ }
105
+ '''
106
+
107
+ # GET handler
108
+ if 'GET' in methods:
109
+ code += f'''
110
+ // GET /api/v1/{name} - List {name}
111
+ export const GET = withApiLogging(async (req: NextRequest): Promise<NextResponse> => {{
112
+ try {{
113
+ '''
114
+ if auth_type == 'required':
115
+ code += ''' // Authenticate using dual auth
116
+ const authResult = await authenticateRequest(req)
117
+
118
+ if (!authResult.success) {
119
+ return NextResponse.json(
120
+ { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
121
+ { status: 401 }
122
+ )
123
+ }
124
+
125
+ if (authResult.rateLimitResponse) {
126
+ return authResult.rateLimitResponse as NextResponse
127
+ }
128
+
129
+ '''
130
+ code += f''' const {{ page, limit, offset }} = parsePaginationParams(req)
131
+
132
+ // TODO: Implement data fetching with queryWithRLS
133
+ const data: unknown[] = []
134
+ const total = 0
135
+
136
+ const paginationMeta = createPaginationMeta(page, limit, total)
137
+ const response = createApiResponse(data, paginationMeta)
138
+ return addCorsHeaders(response)
139
+ }} catch (error) {{
140
+ console.error('[{name.upper()}] List error:', error)
141
+ const response = createApiError('Failed to fetch {name}', 500)
142
+ return addCorsHeaders(response)
143
+ }}
144
+ }})
145
+ '''
146
+
147
+ # POST handler
148
+ if 'POST' in methods:
149
+ code += f'''
150
+ // POST /api/v1/{name} - Create {singular}
151
+ export const POST = withApiLogging(async (req: NextRequest): Promise<NextResponse> => {{
152
+ try {{
153
+ '''
154
+ if auth_type == 'required':
155
+ code += ''' // Authenticate using dual auth
156
+ const authResult = await authenticateRequest(req)
157
+
158
+ if (!authResult.success) {
159
+ return NextResponse.json(
160
+ { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
161
+ { status: 401 }
162
+ )
163
+ }
164
+
165
+ if (authResult.rateLimitResponse) {
166
+ return authResult.rateLimitResponse as NextResponse
167
+ }
168
+
169
+ '''
170
+ code += f''' // Validate input
171
+ const body = Create{pascal}Schema.parse(await req.json())
172
+
173
+ // TODO: Implement creation with mutateWithRLS
174
+ const created = {{ id: 'new-id', ...body }}
175
+
176
+ const response = createApiResponse(created, {{ created: true }}, 201)
177
+ return addCorsHeaders(response)
178
+ }} catch (error) {{
179
+ if (error instanceof z.ZodError) {{
180
+ const response = createApiError('Validation error', 400, error.issues, 'VALIDATION_ERROR')
181
+ return addCorsHeaders(response)
182
+ }}
183
+ console.error('[{name.upper()}] Create error:', error)
184
+ const response = createApiError('Failed to create {singular}', 500)
185
+ return addCorsHeaders(response)
186
+ }}
187
+ }})
188
+ '''
189
+
190
+ return code
191
+
192
+
193
+ def generate_id_route(name: str, methods: list, auth_type: str) -> str:
194
+ """Generate single resource route file."""
195
+ pascal = to_pascal_case(name)
196
+ singular = name.rstrip('s')
197
+
198
+ # Build imports
199
+ imports = [
200
+ "import { NextRequest, NextResponse } from 'next/server'",
201
+ "import { queryWithRLS, mutateWithRLS } from '@/core/lib/db'",
202
+ ]
203
+
204
+ helper_imports = [
205
+ "createApiResponse",
206
+ "createApiError",
207
+ "withApiLogging",
208
+ "handleCorsPreflightRequest",
209
+ "addCorsHeaders",
210
+ ]
211
+
212
+ imports.append(f"import {{ {', '.join(helper_imports)} }} from '@/core/lib/api/helpers'")
213
+
214
+ if auth_type == 'required':
215
+ imports.append("import { authenticateRequest } from '@/core/lib/api/auth/dual-auth'")
216
+
217
+ if 'PATCH' in methods:
218
+ imports.append("import { z } from 'zod'")
219
+
220
+ code = f'''/**
221
+ * {pascal} Single Resource API Route
222
+ *
223
+ * Handles read, update, and delete operations for a single {singular}.
224
+ *
225
+ * Endpoints:
226
+ * GET /api/v1/{name}/[id]
227
+ * PATCH /api/v1/{name}/[id]
228
+ * DELETE /api/v1/{name}/[id]
229
+ */
230
+
231
+ {chr(10).join(imports)}
232
+
233
+ interface RouteParams {{
234
+ params: Promise<{{ id: string }}>
235
+ }}
236
+ '''
237
+
238
+ # Add schema if PATCH
239
+ if 'PATCH' in methods:
240
+ code += f'''
241
+ // Validation schema for updating {singular}
242
+ const Update{pascal}Schema = z.object({{
243
+ title: z.string().min(1).max(255).optional(),
244
+ description: z.string().optional(),
245
+ // Add more fields as needed
246
+ }}).partial()
247
+ '''
248
+
249
+ # OPTIONS handler
250
+ code += '''
251
+ // Handle CORS preflight
252
+ export async function OPTIONS() {
253
+ return handleCorsPreflightRequest()
254
+ }
255
+ '''
256
+
257
+ # GET handler
258
+ if 'GET' in methods:
259
+ code += f'''
260
+ // GET /api/v1/{name}/[id] - Get single {singular}
261
+ export const GET = withApiLogging(async (
262
+ req: NextRequest,
263
+ {{ params }}: RouteParams
264
+ ): Promise<NextResponse> => {{
265
+ const {{ id }} = await params
266
+
267
+ try {{
268
+ '''
269
+ if auth_type == 'required':
270
+ code += ''' // Authenticate using dual auth
271
+ const authResult = await authenticateRequest(req)
272
+
273
+ if (!authResult.success) {
274
+ return NextResponse.json(
275
+ { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
276
+ { status: 401 }
277
+ )
278
+ }
279
+
280
+ if (authResult.rateLimitResponse) {
281
+ return authResult.rateLimitResponse as NextResponse
282
+ }
283
+
284
+ '''
285
+ code += f''' // TODO: Implement fetching by ID with queryWithRLS
286
+ const data = {{ id }}
287
+
288
+ if (!data) {{
289
+ const response = createApiError('{singular.title()} not found', 404)
290
+ return addCorsHeaders(response)
291
+ }}
292
+
293
+ const response = createApiResponse(data)
294
+ return addCorsHeaders(response)
295
+ }} catch (error) {{
296
+ console.error('[{name.upper()}] Get error:', error)
297
+ const response = createApiError('Failed to fetch {singular}', 500)
298
+ return addCorsHeaders(response)
299
+ }}
300
+ }})
301
+ '''
302
+
303
+ # PATCH handler
304
+ if 'PATCH' in methods:
305
+ code += f'''
306
+ // PATCH /api/v1/{name}/[id] - Update {singular}
307
+ export const PATCH = withApiLogging(async (
308
+ req: NextRequest,
309
+ {{ params }}: RouteParams
310
+ ): Promise<NextResponse> => {{
311
+ const {{ id }} = await params
312
+
313
+ try {{
314
+ '''
315
+ if auth_type == 'required':
316
+ code += ''' // Authenticate using dual auth
317
+ const authResult = await authenticateRequest(req)
318
+
319
+ if (!authResult.success) {
320
+ return NextResponse.json(
321
+ { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
322
+ { status: 401 }
323
+ )
324
+ }
325
+
326
+ if (authResult.rateLimitResponse) {
327
+ return authResult.rateLimitResponse as NextResponse
328
+ }
329
+
330
+ '''
331
+ code += f''' // Validate input
332
+ const body = Update{pascal}Schema.parse(await req.json())
333
+
334
+ // TODO: Implement update with mutateWithRLS
335
+ const updated = {{ id, ...body }}
336
+
337
+ const response = createApiResponse(updated)
338
+ return addCorsHeaders(response)
339
+ }} catch (error) {{
340
+ if (error instanceof z.ZodError) {{
341
+ const response = createApiError('Validation error', 400, error.issues, 'VALIDATION_ERROR')
342
+ return addCorsHeaders(response)
343
+ }}
344
+ console.error('[{name.upper()}] Update error:', error)
345
+ const response = createApiError('Failed to update {singular}', 500)
346
+ return addCorsHeaders(response)
347
+ }}
348
+ }})
349
+ '''
350
+
351
+ # DELETE handler
352
+ if 'DELETE' in methods:
353
+ code += f'''
354
+ // DELETE /api/v1/{name}/[id] - Delete {singular}
355
+ export const DELETE = withApiLogging(async (
356
+ req: NextRequest,
357
+ {{ params }}: RouteParams
358
+ ): Promise<NextResponse> => {{
359
+ const {{ id }} = await params
360
+
361
+ try {{
362
+ '''
363
+ if auth_type == 'required':
364
+ code += ''' // Authenticate using dual auth
365
+ const authResult = await authenticateRequest(req)
366
+
367
+ if (!authResult.success) {
368
+ return NextResponse.json(
369
+ { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
370
+ { status: 401 }
371
+ )
372
+ }
373
+
374
+ if (authResult.rateLimitResponse) {
375
+ return authResult.rateLimitResponse as NextResponse
376
+ }
377
+
378
+ '''
379
+ code += f''' // TODO: Implement delete with mutateWithRLS
380
+
381
+ const response = createApiResponse({{ deleted: true, id }})
382
+ return addCorsHeaders(response)
383
+ }} catch (error) {{
384
+ console.error('[{name.upper()}] Delete error:', error)
385
+ const response = createApiError('Failed to delete {singular}', 500)
386
+ return addCorsHeaders(response)
387
+ }}
388
+ }})
389
+ '''
390
+
391
+ return code
392
+
393
+
394
+ def main():
395
+ parser = argparse.ArgumentParser(description='Scaffold API endpoint')
396
+ parser.add_argument('--name', required=True, help='Endpoint name (kebab-case)')
397
+ parser.add_argument('--methods', default='GET,POST', help='HTTP methods (comma-separated)')
398
+ parser.add_argument('--auth', choices=['required', 'optional', 'none'], default='required')
399
+ parser.add_argument('--override', action='store_true', help='Create in (contents)/ folder')
400
+ parser.add_argument('--with-id', action='store_true', help='Include [id] route')
401
+ parser.add_argument('--dry-run', action='store_true', help='Show what would be created')
402
+
403
+ args = parser.parse_args()
404
+
405
+ name = args.name.lower()
406
+ methods = [m.strip().upper() for m in args.methods.split(',')]
407
+
408
+ # Determine base path
409
+ if args.override:
410
+ base_path = Path(f'app/api/v1/(contents)/{name}')
411
+ else:
412
+ base_path = Path(f'app/api/v1/{name}')
413
+
414
+ print(f"\n{'=' * 60}")
415
+ print(f"SCAFFOLDING API ENDPOINT: {name}")
416
+ print(f"{'=' * 60}")
417
+ print(f"Methods: {', '.join(methods)}")
418
+ print(f"Auth: {args.auth}")
419
+ print(f"Override: {args.override}")
420
+ print(f"Path: {base_path}")
421
+ print(f"{'=' * 60}\n")
422
+
423
+ # Files to create
424
+ files = {
425
+ 'route.ts': generate_list_route(name, methods, args.auth)
426
+ }
427
+
428
+ # Add [id] route if requested
429
+ if args.with_id:
430
+ id_methods = []
431
+ if 'GET' in methods:
432
+ id_methods.append('GET')
433
+ if 'POST' in methods or 'PUT' in methods or 'PATCH' in methods:
434
+ id_methods.append('PATCH')
435
+ if 'DELETE' in methods:
436
+ id_methods.append('DELETE')
437
+
438
+ files['[id]/route.ts'] = generate_id_route(name, id_methods, args.auth)
439
+
440
+ if args.dry_run:
441
+ print("DRY RUN - Files that would be created:\n")
442
+ for file_path, content in files.items():
443
+ print(f" {base_path / file_path}")
444
+ print(f" Lines: {len(content.splitlines())}")
445
+ print("\n" + "-" * 60)
446
+ print("GENERATED CODE PREVIEW (route.ts):")
447
+ print("-" * 60)
448
+ print(files['route.ts'])
449
+ print("-" * 60)
450
+ print("\nRun without --dry-run to create files.")
451
+ return 0
452
+
453
+ # Create files
454
+ for file_path, content in files.items():
455
+ full_path = base_path / file_path
456
+ full_path.parent.mkdir(parents=True, exist_ok=True)
457
+
458
+ if full_path.exists():
459
+ print(f" SKIP (exists): {full_path}")
460
+ else:
461
+ with open(full_path, 'w', encoding='utf-8') as f:
462
+ f.write(content)
463
+ print(f" CREATED: {full_path}")
464
+
465
+ print(f"\n{'=' * 60}")
466
+ print("NEXT STEPS:")
467
+ print("=" * 60)
468
+ print(f"1. Implement TODO sections in route files")
469
+ print(f"2. Add API scopes to core/lib/api/keys.ts:")
470
+ print(f" '{name}:read': 'Read {name}',")
471
+ print(f" '{name}:write': 'Create/update {name}',")
472
+ print(f" '{name}:delete': 'Delete {name}',")
473
+ print(f"3. Create Cypress tests for the endpoint")
474
+ print(f"4. Test with both API key and session auth")
475
+ print("=" * 60 + "\n")
476
+
477
+ return 0
478
+
479
+
480
+ if __name__ == '__main__':
481
+ sys.exit(main())