@polymorphism-tech/morph-spec 7.9.0 → 7.9.1

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 (167) hide show
  1. package/README.md +2 -2
  2. package/bin/validate.js +379 -379
  3. package/claude-plugin.json +1 -1
  4. package/docs/CHEATSHEET.md +5 -1
  5. package/docs/QUICKSTART.md +1 -1
  6. package/framework/commands/commit.md +166 -166
  7. package/framework/commands/morph-infra.md +215 -215
  8. package/framework/commands/morph-preflight.md +205 -205
  9. package/framework/commands/morph-troubleshoot.md +124 -124
  10. package/framework/hooks/claude-code/statusline.py +679 -679
  11. package/framework/hooks/claude-code/statusline.sh +11 -11
  12. package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
  13. package/framework/hooks/git/pre-commit/agents.sh +25 -25
  14. package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
  15. package/framework/hooks/git/pre-commit/specs.sh +50 -50
  16. package/framework/hooks/git/pre-push/run-tests.sh +44 -44
  17. package/framework/hooks/shared/activity-logger.js +160 -160
  18. package/framework/hooks/shared/hook-response.js +45 -45
  19. package/framework/hooks/shared/payload-utils.js +78 -78
  20. package/framework/hooks/shared/stdin-reader.js +26 -26
  21. package/framework/rubrics/backend.json +41 -41
  22. package/framework/rules/ai-agents-standards.md +45 -45
  23. package/framework/rules/dotnet-templates.md +86 -86
  24. package/framework/rules/frontend-standards.md +13 -13
  25. package/framework/rules/infrastructure-standards.md +27 -27
  26. package/framework/rules/neon-standards.md +25 -25
  27. package/framework/rules/nextjs-standards.md +20 -20
  28. package/framework/rules/nextjs-templates.md +40 -40
  29. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  30. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  31. package/framework/skills/core/morph-apply/SKILL.md +1 -1
  32. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  33. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  34. package/framework/skills/core/morph-implement/SKILL.md +1 -1
  35. package/framework/skills/core/morph-plan/SKILL.md +1 -1
  36. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  37. package/framework/skills/core/morph-review/SKILL.md +1 -1
  38. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  39. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  40. package/framework/standards/ai-agents/agent-session.md +160 -160
  41. package/framework/standards/ai-agents/batching.md +193 -193
  42. package/framework/standards/ai-agents/context-providers.md +188 -188
  43. package/framework/standards/ai-agents/mcp-server.md +250 -250
  44. package/framework/standards/ai-agents/mcp-tools.md +197 -197
  45. package/framework/standards/ai-agents/middleware-patterns.md +207 -207
  46. package/framework/standards/ai-agents/modalities-image-gen.md +173 -173
  47. package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -171
  48. package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -181
  49. package/framework/standards/ai-agents/modalities-vision.md +201 -201
  50. package/framework/standards/ai-agents/multi-agent-patterns.md +155 -155
  51. package/framework/standards/ai-agents/production.md +275 -275
  52. package/framework/standards/ai-agents/prompts-in-db.md +214 -214
  53. package/framework/standards/ai-agents/providers/model-registry.md +158 -158
  54. package/framework/standards/ai-agents/service-tier-flex.md +135 -135
  55. package/framework/standards/ai-agents/structured-output.md +249 -249
  56. package/framework/standards/ai-agents/sweet-spot.md +109 -109
  57. package/framework/templates/IDE-SNIPPETS.md +262 -262
  58. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  59. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
  60. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
  61. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
  62. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
  63. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
  64. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
  65. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
  66. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
  67. package/framework/templates/code/dotnet/database/migration.cs +83 -83
  68. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
  69. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  70. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  71. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
  72. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
  73. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  74. package/framework/templates/code/typescript/contracts.ts +167 -167
  75. package/framework/templates/docs/clarifications.md +253 -253
  76. package/framework/templates/docs/schema-analysis.md +119 -119
  77. package/framework/templates/docs/ui-components.md +52 -52
  78. package/framework/templates/docs/ui-design-system.md +76 -76
  79. package/framework/templates/docs/ui-flows.md +167 -167
  80. package/framework/templates/docs/ui-mockups.md +98 -98
  81. package/framework/templates/feature/decisions.md +122 -122
  82. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
  83. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  84. package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
  85. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  86. package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
  87. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  88. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
  89. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  90. package/framework/templates/infrastructure/docker/docker-compose.template.yml +50 -50
  91. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  92. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  93. package/framework/templates/infrastructure/github/README.md +56 -56
  94. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  95. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  96. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  97. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  98. package/framework/templates/integrations/asaas-client.cs +387 -387
  99. package/framework/templates/integrations/asaas-webhook.cs +351 -351
  100. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  101. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  102. package/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -113
  103. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
  104. package/framework/templates/project/validate.js +120 -120
  105. package/framework/templates/state.template.json +17 -17
  106. package/framework/templates/ui/design-system.css +226 -226
  107. package/package.json +2 -1
  108. package/src/commands/dashboard/dashboard.js +53 -53
  109. package/src/commands/index.js +13 -13
  110. package/src/commands/mcp/mcp-setup.js +519 -519
  111. package/src/commands/project/checkpoint.js +209 -209
  112. package/src/commands/project/update.js +4 -1
  113. package/src/core/state/phase-state-machine.js +197 -197
  114. package/src/core/templates/template-renderer.js +477 -477
  115. package/src/dashboard/app/components/DetailPanel.jsx +11 -11
  116. package/src/dashboard/app/components/FlowGraph.jsx +17 -17
  117. package/src/dashboard/app/components/SearchFilter.jsx +22 -22
  118. package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
  119. package/src/dashboard/app/main.jsx +13 -13
  120. package/src/dashboard/app/pages/AgentMap.jsx +370 -370
  121. package/src/dashboard/app/pages/HookInspector.jsx +418 -418
  122. package/src/dashboard/app/pages/LiveState.jsx +239 -239
  123. package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
  124. package/src/dashboard/app/pages/RulesMap.jsx +273 -273
  125. package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
  126. package/src/dashboard/app/pages/Standards.jsx +332 -332
  127. package/src/dashboard/app/styles/index.css +47 -47
  128. package/src/dashboard/index.html +12 -12
  129. package/src/dashboard/package.json +24 -24
  130. package/src/dashboard/scanner/hooks-scanner.js +41 -41
  131. package/src/dashboard/scanner/phases-scanner.js +15 -15
  132. package/src/dashboard/scanner/rubrics-scanner.js +12 -12
  133. package/src/dashboard/scanner/rules-scanner.js +37 -37
  134. package/src/dashboard/scanner/skills-scanner.js +43 -43
  135. package/src/dashboard/scanner/squads-scanner.js +13 -13
  136. package/src/dashboard/scanner/standards-scanner.js +26 -26
  137. package/src/dashboard/vite-plugin-morph-data.js +17 -17
  138. package/src/dashboard/vite.config.js +24 -24
  139. package/src/lib/agents/metrics-aggregator.js +56 -56
  140. package/src/lib/agents/metrics-calculator.js +125 -125
  141. package/src/lib/agents/output-collector.js +73 -73
  142. package/src/lib/detectors/claude-config-detector.js +152 -152
  143. package/src/lib/detectors/design-system-detector.js +231 -231
  144. package/src/lib/detectors/index.js +217 -217
  145. package/src/lib/generators/architecture-scanner.js +639 -639
  146. package/src/lib/generators/design-system-generator.js +508 -508
  147. package/src/lib/generators/index.js +13 -13
  148. package/src/lib/generators/settings-generator.js +209 -209
  149. package/src/lib/hooks/hook-executor.js +167 -167
  150. package/src/lib/installers/mcp-installer.js +719 -719
  151. package/src/lib/tasks/task-classifier.js +30 -30
  152. package/src/lib/tasks/task-parser.js +209 -209
  153. package/src/lib/tasks/test-runner.js +81 -81
  154. package/src/lib/validators/architecture/architecture-validator.js +259 -259
  155. package/src/lib/validators/checkpoint-persistence.js +39 -39
  156. package/src/lib/validators/contracts/contract-compliance-validator.js +274 -274
  157. package/src/lib/validators/css/css-validator.js +340 -340
  158. package/src/lib/validators/packages/package-validator.js +347 -347
  159. package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
  160. package/src/lib/validators/shared/issue-counter.js +14 -14
  161. package/src/lib/validators/validation-runner.js +349 -349
  162. package/src/scripts/setup-infra.js +385 -385
  163. package/src/utils/agent-id-mapper.js +11 -11
  164. package/src/utils/claude-settings-manager.js +300 -300
  165. package/src/utils/skills-installer.js +174 -174
  166. package/framework/templates/.idea/morph-templates.xml +0 -92
  167. package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
@@ -1,122 +1,122 @@
1
- # Architecture Decision Records - {{titleCase FEATURE_NAME}}
2
-
3
- ## ADR-001: {Decision Title}
4
-
5
- **Date:** {{DATE}}
6
- **Status:** Proposed | Accepted | Deprecated | Superseded
7
- **Deciders:** MORPH Agents, Developer
8
-
9
- ### Context
10
-
11
- {Describe the context and problem that led to this decision}
12
-
13
- ### Decision
14
-
15
- {Describe the decision made}
16
-
17
- ### Consequences
18
-
19
- **Pros:**
20
- - {Positive consequence 1}
21
- - {Positive consequence 2}
22
-
23
- **Cons:**
24
- - {Negative consequence 1}
25
-
26
- **Risks:**
27
- - {Identified risk}
28
-
29
- ### Alternatives Considered
30
-
31
- #### Option A: {Name}
32
- - Pros: {advantages}
33
- - Cons: {disadvantages}
34
- - **Rejected because:** {reason}
35
-
36
- #### Option B: {Name}
37
- - Pros: {advantages}
38
- - Cons: {disadvantages}
39
- - **Rejected because:** {reason}
40
-
41
- ---
42
-
43
- {{#if (eq STACK "nextjs-neon")}}
44
- ## ADR-002: Database Access Strategy
45
-
46
- **Date:** {{DATE}}
47
- **Status:** Accepted
48
-
49
- ### Context
50
-
51
- Need to decide how the .NET API accesses Neon PostgreSQL.
52
-
53
- ### Decision
54
-
55
- Use Dapper with Npgsql for direct SQL queries. No EF Core.
56
-
57
- ### Consequences
58
-
59
- **Pros:**
60
- - Full control over SQL queries
61
- - Better performance (no ORM overhead)
62
- - Direct access to PostgreSQL features (jsonb, pgvector, functions)
63
- - RLS policies apply naturally through connection
64
-
65
- **Cons:**
66
- - No automatic migrations (use Neon CLI / dotnet ef instead)
67
- - Manual SQL query writing
68
- - No change tracking
69
-
70
- ---
71
-
72
- ## ADR-003: Auth Strategy
73
-
74
- **Date:** {{DATE}}
75
- **Status:** Accepted
76
-
77
- ### Context
78
-
79
- Need authentication for both Next.js frontend and .NET API.
80
-
81
- ### Decision
82
-
83
- Use Neon Auth (Better Auth) for authentication. Auth data lives in the Neon database. JWT validated by .NET API middleware.
84
-
85
- ### Consequences
86
-
87
- **Pros:**
88
- - Auth data in same database — no external provider, no sync delays
89
- - RLS policies work with Neon Auth JWT via auth.user_id() / pg_session_jwt
90
- - Built-in social login, email/password via @neondatabase/auth SDK
91
- - Branch isolation — each Neon branch gets isolated auth data
92
- - No webhooks needed — query neon_auth schema directly
93
-
94
- **Cons:**
95
- - Neon Auth is currently in Beta
96
- - JWT must be forwarded to .NET API for backend auth
97
- {{/if}}
98
-
99
- ---
100
-
101
- ## Template for New ADRs
102
-
103
- ```markdown
104
- ## ADR-XXX: {Title}
105
-
106
- **Date:**
107
- **Status:** Proposed | Accepted | Deprecated | Superseded
108
-
109
- ### Context
110
- {Why is this decision needed?}
111
-
112
- ### Decision
113
- {What was decided?}
114
-
115
- ### Consequences
116
- **Pros:** {list}
117
- **Cons:** {list}
118
- ```
119
-
120
- ---
121
-
122
- *Generated by MORPH Framework*
1
+ # Architecture Decision Records - {{titleCase FEATURE_NAME}}
2
+
3
+ ## ADR-001: {Decision Title}
4
+
5
+ **Date:** {{DATE}}
6
+ **Status:** Proposed | Accepted | Deprecated | Superseded
7
+ **Deciders:** MORPH Agents, Developer
8
+
9
+ ### Context
10
+
11
+ {Describe the context and problem that led to this decision}
12
+
13
+ ### Decision
14
+
15
+ {Describe the decision made}
16
+
17
+ ### Consequences
18
+
19
+ **Pros:**
20
+ - {Positive consequence 1}
21
+ - {Positive consequence 2}
22
+
23
+ **Cons:**
24
+ - {Negative consequence 1}
25
+
26
+ **Risks:**
27
+ - {Identified risk}
28
+
29
+ ### Alternatives Considered
30
+
31
+ #### Option A: {Name}
32
+ - Pros: {advantages}
33
+ - Cons: {disadvantages}
34
+ - **Rejected because:** {reason}
35
+
36
+ #### Option B: {Name}
37
+ - Pros: {advantages}
38
+ - Cons: {disadvantages}
39
+ - **Rejected because:** {reason}
40
+
41
+ ---
42
+
43
+ {{#if (eq STACK "nextjs-neon")}}
44
+ ## ADR-002: Database Access Strategy
45
+
46
+ **Date:** {{DATE}}
47
+ **Status:** Accepted
48
+
49
+ ### Context
50
+
51
+ Need to decide how the .NET API accesses Neon PostgreSQL.
52
+
53
+ ### Decision
54
+
55
+ Use Dapper with Npgsql for direct SQL queries. No EF Core.
56
+
57
+ ### Consequences
58
+
59
+ **Pros:**
60
+ - Full control over SQL queries
61
+ - Better performance (no ORM overhead)
62
+ - Direct access to PostgreSQL features (jsonb, pgvector, functions)
63
+ - RLS policies apply naturally through connection
64
+
65
+ **Cons:**
66
+ - No automatic migrations (use Neon CLI / dotnet ef instead)
67
+ - Manual SQL query writing
68
+ - No change tracking
69
+
70
+ ---
71
+
72
+ ## ADR-003: Auth Strategy
73
+
74
+ **Date:** {{DATE}}
75
+ **Status:** Accepted
76
+
77
+ ### Context
78
+
79
+ Need authentication for both Next.js frontend and .NET API.
80
+
81
+ ### Decision
82
+
83
+ Use Neon Auth (Better Auth) for authentication. Auth data lives in the Neon database. JWT validated by .NET API middleware.
84
+
85
+ ### Consequences
86
+
87
+ **Pros:**
88
+ - Auth data in same database — no external provider, no sync delays
89
+ - RLS policies work with Neon Auth JWT via auth.user_id() / pg_session_jwt
90
+ - Built-in social login, email/password via @neondatabase/auth SDK
91
+ - Branch isolation — each Neon branch gets isolated auth data
92
+ - No webhooks needed — query neon_auth schema directly
93
+
94
+ **Cons:**
95
+ - Neon Auth is currently in Beta
96
+ - JWT must be forwarded to .NET API for backend auth
97
+ {{/if}}
98
+
99
+ ---
100
+
101
+ ## Template for New ADRs
102
+
103
+ ```markdown
104
+ ## ADR-XXX: {Title}
105
+
106
+ **Date:**
107
+ **Status:** Proposed | Accepted | Deprecated | Superseded
108
+
109
+ ### Context
110
+ {Why is this decision needed?}
111
+
112
+ ### Decision
113
+ {What was decided?}
114
+
115
+ ### Consequences
116
+ **Pros:** {list}
117
+ **Cons:** {list}
118
+ ```
119
+
120
+ ---
121
+
122
+ *Generated by MORPH Framework*
@@ -1,43 +1,43 @@
1
- # Multi-stage Next.js production build for Coolify
2
- # Stage 1: Dependencies
3
- FROM node:20-alpine AS deps
4
- RUN apk add --no-cache libc6-compat
5
- WORKDIR /app
6
-
7
- COPY package.json package-lock.json* ./
8
- RUN npm ci --only=production && npm cache clean --force
9
-
10
- # Stage 2: Build
11
- FROM node:20-alpine AS builder
12
- WORKDIR /app
13
-
14
- COPY --from=deps /app/node_modules ./node_modules
15
- COPY . .
16
-
17
- # Build args for NEXT_PUBLIC_ variables (must be available at build time)
18
- ARG NEXT_PUBLIC_APP_URL
19
- ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
20
-
21
- RUN npm run build
22
-
23
- # Stage 3: Production runner
24
- FROM node:20-alpine AS runner
25
- WORKDIR /app
26
-
27
- ENV NODE_ENV=production
28
- ENV NEXT_TELEMETRY_DISABLED=1
29
-
30
- RUN addgroup --system --gid 1001 nodejs
31
- RUN adduser --system --uid 1001 nextjs
32
-
33
- COPY --from=builder /app/public ./public
34
- COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
35
- COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
36
-
37
- USER nextjs
38
-
39
- EXPOSE 3000
40
- ENV PORT=3000
41
- ENV HOSTNAME="0.0.0.0"
42
-
43
- CMD ["node", "server.js"]
1
+ # Multi-stage Next.js production build for Coolify
2
+ # Stage 1: Dependencies
3
+ FROM node:20-alpine AS deps
4
+ RUN apk add --no-cache libc6-compat
5
+ WORKDIR /app
6
+
7
+ COPY package.json package-lock.json* ./
8
+ RUN npm ci --only=production && npm cache clean --force
9
+
10
+ # Stage 2: Build
11
+ FROM node:20-alpine AS builder
12
+ WORKDIR /app
13
+
14
+ COPY --from=deps /app/node_modules ./node_modules
15
+ COPY . .
16
+
17
+ # Build args for NEXT_PUBLIC_ variables (must be available at build time)
18
+ ARG NEXT_PUBLIC_APP_URL
19
+ ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
20
+
21
+ RUN npm run build
22
+
23
+ # Stage 3: Production runner
24
+ FROM node:20-alpine AS runner
25
+ WORKDIR /app
26
+
27
+ ENV NODE_ENV=production
28
+ ENV NEXT_TELEMETRY_DISABLED=1
29
+
30
+ RUN addgroup --system --gid 1001 nodejs
31
+ RUN adduser --system --uid 1001 nextjs
32
+
33
+ COPY --from=builder /app/public ./public
34
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
35
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
36
+
37
+ USER nextjs
38
+
39
+ EXPOSE 3000
40
+ ENV PORT=3000
41
+ ENV HOSTNAME="0.0.0.0"
42
+
43
+ CMD ["node", "server.js"]
@@ -1,26 +1,26 @@
1
- // features/{{kebabCase featureName}}/components/{{kebabCase featureName}}-list.tsx
2
- 'use client';
3
-
4
- import { use{{pascalCase featureName}}s } from '@/features/{{kebabCase featureName}}/hooks/use-{{kebabCase featureName}}s';
5
- import { DataTable } from '@/components/data-table';
6
- import type { {{pascalCase featureName}} } from '@/features/{{kebabCase featureName}}/types/{{kebabCase featureName}}.types';
7
- import type { ColumnDef } from '@tanstack/react-table';
8
-
9
- const columns: ColumnDef<{{pascalCase featureName}}>[] = [
10
- { accessorKey: 'id', header: 'ID' },
11
- { accessorKey: 'name', header: 'Name' },
12
- ];
13
-
14
- interface {{pascalCase featureName}}ListProps {
15
- initialData?: {{pascalCase featureName}}[];
16
- }
17
-
18
- export function {{pascalCase featureName}}List({ initialData }: {{pascalCase featureName}}ListProps) {
19
- const { data = initialData ?? [], isLoading } = use{{pascalCase featureName}}s();
20
-
21
- if (isLoading) {
22
- return <div className="flex items-center justify-center h-32">Loading...</div>;
23
- }
24
-
25
- return <DataTable columns={columns} data={data} />;
26
- }
1
+ // features/{{kebabCase featureName}}/components/{{kebabCase featureName}}-list.tsx
2
+ 'use client';
3
+
4
+ import { use{{pascalCase featureName}}s } from '@/features/{{kebabCase featureName}}/hooks/use-{{kebabCase featureName}}s';
5
+ import { DataTable } from '@/components/data-table';
6
+ import type { {{pascalCase featureName}} } from '@/features/{{kebabCase featureName}}/types/{{kebabCase featureName}}.types';
7
+ import type { ColumnDef } from '@tanstack/react-table';
8
+
9
+ const columns: ColumnDef<{{pascalCase featureName}}>[] = [
10
+ { accessorKey: 'id', header: 'ID' },
11
+ { accessorKey: 'name', header: 'Name' },
12
+ ];
13
+
14
+ interface {{pascalCase featureName}}ListProps {
15
+ initialData?: {{pascalCase featureName}}[];
16
+ }
17
+
18
+ export function {{pascalCase featureName}}List({ initialData }: {{pascalCase featureName}}ListProps) {
19
+ const { data = initialData ?? [], isLoading } = use{{pascalCase featureName}}s();
20
+
21
+ if (isLoading) {
22
+ return <div className="flex items-center justify-center h-32">Loading...</div>;
23
+ }
24
+
25
+ return <DataTable columns={columns} data={data} />;
26
+ }
@@ -1,32 +1,32 @@
1
- // env.mjs — Zod-validated environment variables
2
- // Crashes at startup if required vars are missing — no silent undefined
3
- import { z } from 'zod';
4
-
5
- const serverSchema = z.object({
6
- API_URL: z.string().url('API_URL must be a valid URL'),
7
- NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
8
- });
9
-
10
- const clientSchema = z.object({
11
- NEXT_PUBLIC_APP_URL: z.string().url().optional(),
12
- });
13
-
14
- // Validate server-side env (only available on server)
15
- const serverEnv = serverSchema.safeParse(process.env);
16
- if (!serverEnv.success) {
17
- console.error('❌ Invalid server environment variables:');
18
- console.error(serverEnv.error.flatten().fieldErrors);
19
- throw new Error('Invalid environment variables');
20
- }
21
-
22
- // Validate client-side env
23
- const clientEnv = clientSchema.safeParse({
24
- NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
25
- });
26
- if (!clientEnv.success) {
27
- console.error('❌ Invalid client environment variables:');
28
- console.error(clientEnv.error.flatten().fieldErrors);
29
- throw new Error('Invalid client environment variables');
30
- }
31
-
32
- export const env = { ...serverEnv.data, ...clientEnv.data };
1
+ // env.mjs — Zod-validated environment variables
2
+ // Crashes at startup if required vars are missing — no silent undefined
3
+ import { z } from 'zod';
4
+
5
+ const serverSchema = z.object({
6
+ API_URL: z.string().url('API_URL must be a valid URL'),
7
+ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
8
+ });
9
+
10
+ const clientSchema = z.object({
11
+ NEXT_PUBLIC_APP_URL: z.string().url().optional(),
12
+ });
13
+
14
+ // Validate server-side env (only available on server)
15
+ const serverEnv = serverSchema.safeParse(process.env);
16
+ if (!serverEnv.success) {
17
+ console.error('❌ Invalid server environment variables:');
18
+ console.error(serverEnv.error.flatten().fieldErrors);
19
+ throw new Error('Invalid environment variables');
20
+ }
21
+
22
+ // Validate client-side env
23
+ const clientEnv = clientSchema.safeParse({
24
+ NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
25
+ });
26
+ if (!clientEnv.success) {
27
+ console.error('❌ Invalid client environment variables:');
28
+ console.error(clientEnv.error.flatten().fieldErrors);
29
+ throw new Error('Invalid client environment variables');
30
+ }
31
+
32
+ export const env = { ...serverEnv.data, ...clientEnv.data };
@@ -1,56 +1,56 @@
1
- // features/{{kebabCase featureName}}/components/create-{{kebabCase featureName}}-form.tsx
2
- 'use client';
3
-
4
- import { useForm } from 'react-hook-form';
5
- import { zodResolver } from '@hookform/resolvers/zod';
6
- import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
7
- import { Input } from '@/components/ui/input';
8
- import { Button } from '@/components/ui/button';
9
- import { useCreate{{pascalCase featureName}} } from '@/features/{{kebabCase featureName}}/hooks/use-create-{{kebabCase featureName}}';
10
- import { create{{pascalCase featureName}}Schema, type Create{{pascalCase featureName}}Input } from '@/features/{{kebabCase featureName}}/types/{{kebabCase featureName}}.schemas';
11
-
12
- interface Create{{pascalCase featureName}}FormProps {
13
- onSuccess?: () => void;
14
- }
15
-
16
- export function Create{{pascalCase featureName}}Form({ onSuccess }: Create{{pascalCase featureName}}FormProps) {
17
- const form = useForm<Create{{pascalCase featureName}}Input>({
18
- resolver: zodResolver(create{{pascalCase featureName}}Schema),
19
- defaultValues: { name: '' },
20
- });
21
-
22
- const { mutate: create{{pascalCase featureName}}, isPending } = useCreate{{pascalCase featureName}}();
23
-
24
- function onSubmit(values: Create{{pascalCase featureName}}Input) {
25
- create{{pascalCase featureName}}(values, {
26
- onSuccess: () => { form.reset(); onSuccess?.(); },
27
- onError: (error) => { form.setError('root', { message: error.message }); },
28
- });
29
- }
30
-
31
- return (
32
- <Form {...form}>
33
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
34
- <FormField
35
- control={form.control}
36
- name="name"
37
- render={({ field }) => (
38
- <FormItem>
39
- <FormLabel>Name</FormLabel>
40
- <FormControl>
41
- <Input placeholder="Enter name" {...field} />
42
- </FormControl>
43
- <FormMessage />
44
- </FormItem>
45
- )}
46
- />
47
- {form.formState.errors.root && (
48
- <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
49
- )}
50
- <Button type="submit" disabled={isPending}>
51
- {isPending ? 'Creating...' : 'Create {{pascalCase featureName}}'}
52
- </Button>
53
- </form>
54
- </Form>
55
- );
56
- }
1
+ // features/{{kebabCase featureName}}/components/create-{{kebabCase featureName}}-form.tsx
2
+ 'use client';
3
+
4
+ import { useForm } from 'react-hook-form';
5
+ import { zodResolver } from '@hookform/resolvers/zod';
6
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
7
+ import { Input } from '@/components/ui/input';
8
+ import { Button } from '@/components/ui/button';
9
+ import { useCreate{{pascalCase featureName}} } from '@/features/{{kebabCase featureName}}/hooks/use-create-{{kebabCase featureName}}';
10
+ import { create{{pascalCase featureName}}Schema, type Create{{pascalCase featureName}}Input } from '@/features/{{kebabCase featureName}}/types/{{kebabCase featureName}}.schemas';
11
+
12
+ interface Create{{pascalCase featureName}}FormProps {
13
+ onSuccess?: () => void;
14
+ }
15
+
16
+ export function Create{{pascalCase featureName}}Form({ onSuccess }: Create{{pascalCase featureName}}FormProps) {
17
+ const form = useForm<Create{{pascalCase featureName}}Input>({
18
+ resolver: zodResolver(create{{pascalCase featureName}}Schema),
19
+ defaultValues: { name: '' },
20
+ });
21
+
22
+ const { mutate: create{{pascalCase featureName}}, isPending } = useCreate{{pascalCase featureName}}();
23
+
24
+ function onSubmit(values: Create{{pascalCase featureName}}Input) {
25
+ create{{pascalCase featureName}}(values, {
26
+ onSuccess: () => { form.reset(); onSuccess?.(); },
27
+ onError: (error) => { form.setError('root', { message: error.message }); },
28
+ });
29
+ }
30
+
31
+ return (
32
+ <Form {...form}>
33
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
34
+ <FormField
35
+ control={form.control}
36
+ name="name"
37
+ render={({ field }) => (
38
+ <FormItem>
39
+ <FormLabel>Name</FormLabel>
40
+ <FormControl>
41
+ <Input placeholder="Enter name" {...field} />
42
+ </FormControl>
43
+ <FormMessage />
44
+ </FormItem>
45
+ )}
46
+ />
47
+ {form.formState.errors.root && (
48
+ <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
49
+ )}
50
+ <Button type="submit" disabled={isPending}>
51
+ {isPending ? 'Creating...' : 'Create {{pascalCase featureName}}'}
52
+ </Button>
53
+ </form>
54
+ </Form>
55
+ );
56
+ }
@@ -1,22 +1,22 @@
1
- // app/(dashboard)/{{kebabCase featureName}}/page.tsx
2
- // Server Component — fetches initial data, renders feature component
3
- import { {{pascalCase featureName}}List } from '@/features/{{kebabCase featureName}}';
4
-
5
- async function get{{pascalCase featureName}}List() {
6
- const res = await fetch(`${process.env.API_URL}/api/{{kebabCase featureName}}`, {
7
- next: { revalidate: 30 },
8
- headers: { 'Content-Type': 'application/json' },
9
- });
10
- if (!res.ok) throw new Error('Failed to fetch {{featureName}}');
11
- return res.json();
12
- }
13
-
14
- export default async function {{pascalCase featureName}}Page() {
15
- const data = await get{{pascalCase featureName}}List();
16
- return (
17
- <div className="container py-6">
18
- <h1 className="text-2xl font-bold mb-6">{{pascalCase featureName}}</h1>
19
- <{{pascalCase featureName}}List initialData={data} />
20
- </div>
21
- );
22
- }
1
+ // app/(dashboard)/{{kebabCase featureName}}/page.tsx
2
+ // Server Component — fetches initial data, renders feature component
3
+ import { {{pascalCase featureName}}List } from '@/features/{{kebabCase featureName}}';
4
+
5
+ async function get{{pascalCase featureName}}List() {
6
+ const res = await fetch(`${process.env.API_URL}/api/{{kebabCase featureName}}`, {
7
+ next: { revalidate: 30 },
8
+ headers: { 'Content-Type': 'application/json' },
9
+ });
10
+ if (!res.ok) throw new Error('Failed to fetch {{featureName}}');
11
+ return res.json();
12
+ }
13
+
14
+ export default async function {{pascalCase featureName}}Page() {
15
+ const data = await get{{pascalCase featureName}}List();
16
+ return (
17
+ <div className="container py-6">
18
+ <h1 className="text-2xl font-bold mb-6">{{pascalCase featureName}}</h1>
19
+ <{{pascalCase featureName}}List initialData={data} />
20
+ </div>
21
+ );
22
+ }
@@ -1,26 +1,26 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": false,
6
- "skipLibCheck": true,
7
- "strict": true,
8
- "noUncheckedIndexedAccess": true,
9
- "noImplicitOverride": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "noEmit": true,
12
- "esModuleInterop": true,
13
- "module": "esnext",
14
- "moduleResolution": "bundler",
15
- "resolveJsonModule": true,
16
- "isolatedModules": true,
17
- "jsx": "preserve",
18
- "incremental": true,
19
- "plugins": [{ "name": "next" }],
20
- "paths": {
21
- "@/*": ["./src/*"]
22
- }
23
- },
24
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25
- "exclude": ["node_modules"]
26
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": false,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "noImplicitOverride": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "noEmit": true,
12
+ "esModuleInterop": true,
13
+ "module": "esnext",
14
+ "moduleResolution": "bundler",
15
+ "resolveJsonModule": true,
16
+ "isolatedModules": true,
17
+ "jsx": "preserve",
18
+ "incremental": true,
19
+ "plugins": [{ "name": "next" }],
20
+ "paths": {
21
+ "@/*": ["./src/*"]
22
+ }
23
+ },
24
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25
+ "exclude": ["node_modules"]
26
+ }