@polymorphism-tech/morph-spec 7.8.0 → 7.8.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 (166) 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 +1 -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-brainstorming/SKILL.md +8 -4
  32. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  33. package/framework/skills/core/morph-plan/SKILL.md +8 -4
  34. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  35. package/framework/skills/core/morph-review/SKILL.md +13 -7
  36. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  37. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  38. package/framework/standards/ai-agents/agent-session.md +160 -160
  39. package/framework/standards/ai-agents/batching.md +193 -193
  40. package/framework/standards/ai-agents/context-providers.md +188 -188
  41. package/framework/standards/ai-agents/mcp-server.md +250 -250
  42. package/framework/standards/ai-agents/mcp-tools.md +197 -197
  43. package/framework/standards/ai-agents/middleware-patterns.md +207 -207
  44. package/framework/standards/ai-agents/modalities-image-gen.md +173 -173
  45. package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -171
  46. package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -181
  47. package/framework/standards/ai-agents/modalities-vision.md +201 -201
  48. package/framework/standards/ai-agents/multi-agent-patterns.md +155 -155
  49. package/framework/standards/ai-agents/production.md +275 -275
  50. package/framework/standards/ai-agents/prompts-in-db.md +214 -214
  51. package/framework/standards/ai-agents/providers/model-registry.md +158 -158
  52. package/framework/standards/ai-agents/service-tier-flex.md +135 -135
  53. package/framework/standards/ai-agents/structured-output.md +249 -249
  54. package/framework/standards/ai-agents/sweet-spot.md +109 -109
  55. package/framework/templates/IDE-SNIPPETS.md +262 -262
  56. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  57. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
  58. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
  59. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
  60. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
  61. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
  62. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
  63. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
  64. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
  65. package/framework/templates/code/dotnet/database/migration.cs +83 -83
  66. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
  67. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  68. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  69. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
  70. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
  71. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  72. package/framework/templates/code/typescript/contracts.ts +167 -167
  73. package/framework/templates/docs/clarifications.md +253 -253
  74. package/framework/templates/docs/schema-analysis.md +119 -119
  75. package/framework/templates/docs/ui-components.md +52 -52
  76. package/framework/templates/docs/ui-design-system.md +76 -76
  77. package/framework/templates/docs/ui-flows.md +167 -167
  78. package/framework/templates/docs/ui-mockups.md +98 -98
  79. package/framework/templates/feature/decisions.md +122 -122
  80. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
  81. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  82. package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
  83. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  84. package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
  85. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  86. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
  87. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  88. package/framework/templates/infrastructure/docker/docker-compose.template.yml +50 -50
  89. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  90. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  91. package/framework/templates/infrastructure/github/README.md +56 -56
  92. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  93. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  94. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  95. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  96. package/framework/templates/integrations/asaas-client.cs +387 -387
  97. package/framework/templates/integrations/asaas-webhook.cs +351 -351
  98. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  99. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  100. package/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -113
  101. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
  102. package/framework/templates/project/validate.js +120 -120
  103. package/framework/templates/state.template.json +17 -17
  104. package/framework/templates/ui/design-system.css +226 -226
  105. package/package.json +1 -1
  106. package/src/commands/dashboard/dashboard.js +53 -53
  107. package/src/commands/index.js +13 -13
  108. package/src/commands/mcp/mcp-setup.js +519 -519
  109. package/src/commands/project/checkpoint.js +209 -209
  110. package/src/commands/project/update.js +7 -4
  111. package/src/core/state/phase-state-machine.js +197 -197
  112. package/src/core/templates/template-renderer.js +477 -477
  113. package/src/dashboard/app/components/DetailPanel.jsx +11 -11
  114. package/src/dashboard/app/components/FlowGraph.jsx +17 -17
  115. package/src/dashboard/app/components/SearchFilter.jsx +22 -22
  116. package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
  117. package/src/dashboard/app/main.jsx +13 -13
  118. package/src/dashboard/app/pages/AgentMap.jsx +370 -370
  119. package/src/dashboard/app/pages/HookInspector.jsx +418 -418
  120. package/src/dashboard/app/pages/LiveState.jsx +239 -239
  121. package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
  122. package/src/dashboard/app/pages/RulesMap.jsx +273 -273
  123. package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
  124. package/src/dashboard/app/pages/Standards.jsx +332 -332
  125. package/src/dashboard/app/styles/index.css +47 -47
  126. package/src/dashboard/index.html +12 -12
  127. package/src/dashboard/package.json +24 -24
  128. package/src/dashboard/scanner/hooks-scanner.js +41 -41
  129. package/src/dashboard/scanner/phases-scanner.js +15 -15
  130. package/src/dashboard/scanner/rubrics-scanner.js +12 -12
  131. package/src/dashboard/scanner/rules-scanner.js +37 -37
  132. package/src/dashboard/scanner/skills-scanner.js +43 -43
  133. package/src/dashboard/scanner/squads-scanner.js +13 -13
  134. package/src/dashboard/scanner/standards-scanner.js +26 -26
  135. package/src/dashboard/vite-plugin-morph-data.js +17 -17
  136. package/src/dashboard/vite.config.js +24 -24
  137. package/src/lib/agents/metrics-aggregator.js +56 -56
  138. package/src/lib/agents/metrics-calculator.js +125 -125
  139. package/src/lib/agents/output-collector.js +73 -73
  140. package/src/lib/detectors/claude-config-detector.js +152 -152
  141. package/src/lib/detectors/design-system-detector.js +231 -231
  142. package/src/lib/detectors/index.js +217 -217
  143. package/src/lib/generators/architecture-scanner.js +639 -639
  144. package/src/lib/generators/design-system-generator.js +508 -508
  145. package/src/lib/generators/index.js +13 -13
  146. package/src/lib/generators/settings-generator.js +209 -209
  147. package/src/lib/hooks/hook-executor.js +167 -167
  148. package/src/lib/installers/mcp-installer.js +719 -719
  149. package/src/lib/tasks/task-classifier.js +30 -30
  150. package/src/lib/tasks/task-parser.js +209 -209
  151. package/src/lib/tasks/test-runner.js +81 -81
  152. package/src/lib/validators/architecture/architecture-validator.js +259 -259
  153. package/src/lib/validators/checkpoint-persistence.js +39 -39
  154. package/src/lib/validators/contracts/contract-compliance-validator.js +274 -274
  155. package/src/lib/validators/css/css-validator.js +340 -340
  156. package/src/lib/validators/packages/package-validator.js +347 -347
  157. package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
  158. package/src/lib/validators/shared/issue-counter.js +14 -14
  159. package/src/lib/validators/validation-runner.js +349 -349
  160. package/src/scripts/setup-infra.js +383 -383
  161. package/src/utils/agent-id-mapper.js +11 -11
  162. package/src/utils/banner.js +1 -2
  163. package/src/utils/claude-settings-manager.js +300 -300
  164. package/src/utils/skills-installer.js +172 -172
  165. package/framework/templates/.idea/morph-templates.xml +0 -92
  166. 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
+ }