@levironexe/architect 0.1.0

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 (210) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/CONTRIBUTING.md +55 -0
  3. package/README.md +341 -0
  4. package/dist/analyzers/ast-parser.d.ts +3 -0
  5. package/dist/analyzers/ast-parser.js +305 -0
  6. package/dist/analyzers/ast-parser.js.map +1 -0
  7. package/dist/analyzers/dependency-graph.d.ts +2 -0
  8. package/dist/analyzers/dependency-graph.js +67 -0
  9. package/dist/analyzers/dependency-graph.js.map +1 -0
  10. package/dist/analyzers/duplication.d.ts +2 -0
  11. package/dist/analyzers/duplication.js +56 -0
  12. package/dist/analyzers/duplication.js.map +1 -0
  13. package/dist/analyzers/file-walker.d.ts +3 -0
  14. package/dist/analyzers/file-walker.js +80 -0
  15. package/dist/analyzers/file-walker.js.map +1 -0
  16. package/dist/cli/context-runner.d.ts +1 -0
  17. package/dist/cli/context-runner.js +16 -0
  18. package/dist/cli/context-runner.js.map +1 -0
  19. package/dist/cli/index.d.ts +24 -0
  20. package/dist/cli/index.js +217 -0
  21. package/dist/cli/index.js.map +1 -0
  22. package/dist/cli/init-runner.d.ts +25 -0
  23. package/dist/cli/init-runner.js +152 -0
  24. package/dist/cli/init-runner.js.map +1 -0
  25. package/dist/cli/scan-runner.d.ts +8 -0
  26. package/dist/cli/scan-runner.js +133 -0
  27. package/dist/cli/scan-runner.js.map +1 -0
  28. package/dist/formatters/plan-json.d.ts +2 -0
  29. package/dist/formatters/plan-json.js +4 -0
  30. package/dist/formatters/plan-json.js.map +1 -0
  31. package/dist/formatters/plan-markdown.d.ts +2 -0
  32. package/dist/formatters/plan-markdown.js +42 -0
  33. package/dist/formatters/plan-markdown.js.map +1 -0
  34. package/dist/formatters/plan-prompt.d.ts +4 -0
  35. package/dist/formatters/plan-prompt.js +5 -0
  36. package/dist/formatters/plan-prompt.js.map +1 -0
  37. package/dist/formatters/plan-terminal.d.ts +5 -0
  38. package/dist/formatters/plan-terminal.js +62 -0
  39. package/dist/formatters/plan-terminal.js.map +1 -0
  40. package/dist/generators/blueprint-renderer.d.ts +3 -0
  41. package/dist/generators/blueprint-renderer.js +27 -0
  42. package/dist/generators/blueprint-renderer.js.map +1 -0
  43. package/dist/generators/claudeWriter.d.ts +3 -0
  44. package/dist/generators/claudeWriter.js +9 -0
  45. package/dist/generators/claudeWriter.js.map +1 -0
  46. package/dist/generators/copilotWriter.d.ts +3 -0
  47. package/dist/generators/copilotWriter.js +11 -0
  48. package/dist/generators/copilotWriter.js.map +1 -0
  49. package/dist/generators/cursorWriter.d.ts +3 -0
  50. package/dist/generators/cursorWriter.js +14 -0
  51. package/dist/generators/cursorWriter.js.map +1 -0
  52. package/dist/generators/genericWriter.d.ts +3 -0
  53. package/dist/generators/genericWriter.js +9 -0
  54. package/dist/generators/genericWriter.js.map +1 -0
  55. package/dist/generators/template-context.d.ts +18 -0
  56. package/dist/generators/template-context.js +126 -0
  57. package/dist/generators/template-context.js.map +1 -0
  58. package/dist/generators/templateRenderer.d.ts +2 -0
  59. package/dist/generators/templateRenderer.js +19 -0
  60. package/dist/generators/templateRenderer.js.map +1 -0
  61. package/dist/generators/windsurfWriter.d.ts +3 -0
  62. package/dist/generators/windsurfWriter.js +14 -0
  63. package/dist/generators/windsurfWriter.js.map +1 -0
  64. package/dist/generators/writer-types.d.ts +11 -0
  65. package/dist/generators/writer-types.js +40 -0
  66. package/dist/generators/writer-types.js.map +1 -0
  67. package/dist/llm/claude-provider.d.ts +8 -0
  68. package/dist/llm/claude-provider.js +22 -0
  69. package/dist/llm/claude-provider.js.map +1 -0
  70. package/dist/llm/concern-classifier.d.ts +15 -0
  71. package/dist/llm/concern-classifier.js +61 -0
  72. package/dist/llm/concern-classifier.js.map +1 -0
  73. package/dist/llm/config.d.ts +11 -0
  74. package/dist/llm/config.js +120 -0
  75. package/dist/llm/config.js.map +1 -0
  76. package/dist/llm/ollama-provider.d.ts +8 -0
  77. package/dist/llm/ollama-provider.js +27 -0
  78. package/dist/llm/ollama-provider.js.map +1 -0
  79. package/dist/llm/openai-provider.d.ts +8 -0
  80. package/dist/llm/openai-provider.js +19 -0
  81. package/dist/llm/openai-provider.js.map +1 -0
  82. package/dist/llm/prompt-builder.d.ts +12 -0
  83. package/dist/llm/prompt-builder.js +132 -0
  84. package/dist/llm/prompt-builder.js.map +1 -0
  85. package/dist/llm/provider.d.ts +17 -0
  86. package/dist/llm/provider.js +2 -0
  87. package/dist/llm/provider.js.map +1 -0
  88. package/dist/llm/response-parser.d.ts +6 -0
  89. package/dist/llm/response-parser.js +128 -0
  90. package/dist/llm/response-parser.js.map +1 -0
  91. package/dist/planner/plan-generator.d.ts +7 -0
  92. package/dist/planner/plan-generator.js +275 -0
  93. package/dist/planner/plan-generator.js.map +1 -0
  94. package/dist/planner/plan-prompt-builder.d.ts +9 -0
  95. package/dist/planner/plan-prompt-builder.js +92 -0
  96. package/dist/planner/plan-prompt-builder.js.map +1 -0
  97. package/dist/planner/plan-response-parser.d.ts +7 -0
  98. package/dist/planner/plan-response-parser.js +21 -0
  99. package/dist/planner/plan-response-parser.js.map +1 -0
  100. package/dist/planner/plan-validator.d.ts +3 -0
  101. package/dist/planner/plan-validator.js +49 -0
  102. package/dist/planner/plan-validator.js.map +1 -0
  103. package/dist/reporters/scan-json.d.ts +13 -0
  104. package/dist/reporters/scan-json.js +26 -0
  105. package/dist/reporters/scan-json.js.map +1 -0
  106. package/dist/reporters/terminal.d.ts +6 -0
  107. package/dist/reporters/terminal.js +224 -0
  108. package/dist/reporters/terminal.js.map +1 -0
  109. package/dist/scoring/consistency-score.d.ts +3 -0
  110. package/dist/scoring/consistency-score.js +23 -0
  111. package/dist/scoring/consistency-score.js.map +1 -0
  112. package/dist/scoring/duplication-score.d.ts +3 -0
  113. package/dist/scoring/duplication-score.js +16 -0
  114. package/dist/scoring/duplication-score.js.map +1 -0
  115. package/dist/scoring/health-score.d.ts +4 -0
  116. package/dist/scoring/health-score.js +20 -0
  117. package/dist/scoring/health-score.js.map +1 -0
  118. package/dist/scoring/issue-builder.d.ts +4 -0
  119. package/dist/scoring/issue-builder.js +62 -0
  120. package/dist/scoring/issue-builder.js.map +1 -0
  121. package/dist/scoring/modularity-score.d.ts +3 -0
  122. package/dist/scoring/modularity-score.js +56 -0
  123. package/dist/scoring/modularity-score.js.map +1 -0
  124. package/dist/scoring/pattern-analysis.d.ts +3 -0
  125. package/dist/scoring/pattern-analysis.js +74 -0
  126. package/dist/scoring/pattern-analysis.js.map +1 -0
  127. package/dist/scoring/separation-score.d.ts +3 -0
  128. package/dist/scoring/separation-score.js +35 -0
  129. package/dist/scoring/separation-score.js.map +1 -0
  130. package/dist/skills/detector.d.ts +4 -0
  131. package/dist/skills/detector.js +104 -0
  132. package/dist/skills/detector.js.map +1 -0
  133. package/dist/skills/lister.d.ts +9 -0
  134. package/dist/skills/lister.js +35 -0
  135. package/dist/skills/lister.js.map +1 -0
  136. package/dist/skills/loader.d.ts +6 -0
  137. package/dist/skills/loader.js +76 -0
  138. package/dist/skills/loader.js.map +1 -0
  139. package/dist/skills/structure-check.d.ts +2 -0
  140. package/dist/skills/structure-check.js +37 -0
  141. package/dist/skills/structure-check.js.map +1 -0
  142. package/dist/skills/validator.d.ts +6 -0
  143. package/dist/skills/validator.js +229 -0
  144. package/dist/skills/validator.js.map +1 -0
  145. package/dist/types/analysis.d.ts +130 -0
  146. package/dist/types/analysis.js +41 -0
  147. package/dist/types/analysis.js.map +1 -0
  148. package/dist/types/concern.d.ts +48 -0
  149. package/dist/types/concern.js +16 -0
  150. package/dist/types/concern.js.map +1 -0
  151. package/dist/types/generation.d.ts +32 -0
  152. package/dist/types/generation.js +2 -0
  153. package/dist/types/generation.js.map +1 -0
  154. package/dist/types/issue.d.ts +12 -0
  155. package/dist/types/issue.js +2 -0
  156. package/dist/types/issue.js.map +1 -0
  157. package/dist/types/pattern.d.ts +15 -0
  158. package/dist/types/pattern.js +2 -0
  159. package/dist/types/pattern.js.map +1 -0
  160. package/dist/types/plan.d.ts +56 -0
  161. package/dist/types/plan.js +2 -0
  162. package/dist/types/plan.js.map +1 -0
  163. package/dist/types/scan-output.d.ts +84 -0
  164. package/dist/types/scan-output.js +2 -0
  165. package/dist/types/scan-output.js.map +1 -0
  166. package/dist/types/scoring.d.ts +15 -0
  167. package/dist/types/scoring.js +2 -0
  168. package/dist/types/scoring.js.map +1 -0
  169. package/dist/types/skill.d.ts +97 -0
  170. package/dist/types/skill.js +2 -0
  171. package/dist/types/skill.js.map +1 -0
  172. package/dist/utils/agent-detector.d.ts +2 -0
  173. package/dist/utils/agent-detector.js +22 -0
  174. package/dist/utils/agent-detector.js.map +1 -0
  175. package/dist/utils/interactive.d.ts +6 -0
  176. package/dist/utils/interactive.js +15 -0
  177. package/dist/utils/interactive.js.map +1 -0
  178. package/dist/utils/path.d.ts +5 -0
  179. package/dist/utils/path.js +31 -0
  180. package/dist/utils/path.js.map +1 -0
  181. package/dist/utils/progress.d.ts +17 -0
  182. package/dist/utils/progress.js +48 -0
  183. package/dist/utils/progress.js.map +1 -0
  184. package/dist/utils/thresholds.d.ts +6 -0
  185. package/dist/utils/thresholds.js +48 -0
  186. package/dist/utils/thresholds.js.map +1 -0
  187. package/package.json +63 -0
  188. package/skills/meta/general-js.skill.yaml +131 -0
  189. package/skills/patterns/clerk-auth.skill.yaml +349 -0
  190. package/skills/patterns/docker-deploy.skill.yaml +214 -0
  191. package/skills/patterns/drizzle.skill.yaml +277 -0
  192. package/skills/patterns/mongoose.skill.yaml +290 -0
  193. package/skills/patterns/nextauth.skill.yaml +308 -0
  194. package/skills/patterns/playwright-e2e.skill.yaml +265 -0
  195. package/skills/patterns/prisma.skill.yaml +255 -0
  196. package/skills/patterns/s3-storage.skill.yaml +235 -0
  197. package/skills/patterns/selenium-e2e.skill.yaml +276 -0
  198. package/skills/patterns/supabase-auth.skill.yaml +298 -0
  199. package/skills/patterns/supabase.skill.yaml +304 -0
  200. package/skills/patterns/vercel-deploy.skill.yaml +219 -0
  201. package/skills/patterns/vitest-testing.skill.yaml +262 -0
  202. package/skills/stacks/express-api.skill.yaml +155 -0
  203. package/skills/stacks/fastify-api.skill.yaml +119 -0
  204. package/skills/stacks/hono-api.skill.yaml +130 -0
  205. package/skills/stacks/nestjs.skill.yaml +135 -0
  206. package/skills/stacks/nextjs-app-router.skill.yaml +176 -0
  207. package/skills/stacks/react-spa.skill.yaml +153 -0
  208. package/skills/stacks/vue-nuxt.skill.yaml +115 -0
  209. package/templates/architect-plan.md +139 -0
  210. package/templates/architect-refactor.md +119 -0
@@ -0,0 +1,135 @@
1
+ schema_version: "2.0.0"
2
+ id: nestjs
3
+ name: "NestJS"
4
+ version: "1.1.0"
5
+ description: "Enterprise-grade NestJS with module-per-feature structure, dependency injection, guards, and pipes."
6
+ category: stack
7
+ language: javascript
8
+ frameworks:
9
+ - nestjs
10
+ detection:
11
+ dependencies:
12
+ any:
13
+ - "@nestjs/core"
14
+ none:
15
+ - express
16
+ - fastify
17
+ - hono
18
+ source_indicators:
19
+ - "@Module("
20
+ - "@Controller("
21
+ - "@Injectable("
22
+ - "@nestjs/common"
23
+ structure:
24
+ required_dirs:
25
+ - path: src/modules
26
+ purpose: "Feature modules — one directory per domain (users/, orders/, etc.) containing controller, service, and module file."
27
+ - path: src/common
28
+ purpose: "Cross-cutting NestJS primitives shared across all feature modules: guards (auth, roles), pipes (validation, transformation), interceptors (logging, caching), decorators, and exception filters. Nothing business-domain specific lives here."
29
+ - path: src/config
30
+ purpose: "Configuration module and environment validation."
31
+ recommended_dirs:
32
+ - path: src/database
33
+ purpose: "Database module, entity definitions, and repository setup. TypeORM entities, Prisma schema, or Drizzle table definitions live here — not in feature modules. Feature modules import the database module via DI."
34
+ - path: src/shared
35
+ purpose: "Shared DTOs, TypeScript interfaces, and pure utility functions used across feature modules. Unlike src/common (NestJS primitives), src/shared contains plain TypeScript — no NestJS decorators."
36
+ separation:
37
+ rules:
38
+ - concern: module_structure
39
+ belongs_in: src/modules
40
+ rule_text: "Each feature module contains its own controller, service, and module file co-located in one directory. Do NOT put all controllers in one folder and all services in another — group by feature, not by type."
41
+ example: |
42
+ // src/modules/users/users.module.ts
43
+ @Module({ controllers: [UsersController], providers: [UsersService] })
44
+ export class UsersModule {}
45
+
46
+ // src/modules/users/users.controller.ts
47
+ @Controller('users')
48
+ export class UsersController {
49
+ constructor(private readonly usersService: UsersService) {}
50
+ }
51
+ indicators:
52
+ - "@Module("
53
+ - "src/modules"
54
+ - concern: dependency_injection
55
+ belongs_in: src/modules
56
+ rule_text: "Inject all dependencies via constructor — never instantiate services or repositories with `new`. This enables testing and module substitution."
57
+ example: |
58
+ // ✓ Injected via constructor
59
+ @Controller('users')
60
+ export class UsersController {
61
+ constructor(private readonly usersService: UsersService) {}
62
+ @Get() findAll() { return this.usersService.findAll(); }
63
+ }
64
+ anti_indicators:
65
+ - "new UsersService"
66
+ - "new Repository"
67
+ - concern: guards_and_pipes
68
+ belongs_in: src/common
69
+ rule_text: "Auth guards, validation pipes, and response interceptors live in src/common. Apply them globally via APP_GUARD/APP_PIPE in AppModule, or per-controller/route with decorators."
70
+ example: |
71
+ // src/common/guards/jwt-auth.guard.ts
72
+ @Injectable()
73
+ export class JwtAuthGuard extends AuthGuard('jwt') {}
74
+
75
+ // Apply globally in app.module.ts
76
+ providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }]
77
+ indicators:
78
+ - "@UseGuards"
79
+ - "@UsePipes"
80
+ - "APP_GUARD"
81
+ - "APP_PIPE"
82
+ patterns:
83
+ data_flow:
84
+ direction: "Controller → Service → Repository/ORM"
85
+ rules:
86
+ - "Controllers receive HTTP input and delegate to services."
87
+ - "Services contain business logic and call repositories."
88
+ - "Repositories handle all database interactions."
89
+ error_handling:
90
+ recommended: "Use NestJS exception filters and built-in HttpException classes."
91
+ naming:
92
+ modules: "[resource].module.ts"
93
+ controllers: "[resource].controller.ts"
94
+ services: "[resource].service.ts"
95
+ anti_patterns:
96
+ - id: direct_instantiation
97
+ severity: critical
98
+ description: "Creating service or repository instances manually with `new` instead of using NestJS dependency injection — untestable and bypasses the DI container."
99
+ bad_example: |
100
+ // ❌ Bypasses DI — untestable and breaks module scoping
101
+ @Controller('users')
102
+ export class UsersController {
103
+ private service = new UsersService();
104
+ }
105
+ good_example: |
106
+ // ✓ Injected via constructor — testable and scoped correctly
107
+ constructor(private readonly usersService: UsersService) {}
108
+ - id: flat_file_structure
109
+ severity: warning
110
+ description: "Organizing all controllers in one folder and all services in another instead of grouping by feature module."
111
+ bad_example: |
112
+ // ❌ Flat structure — breaks NestJS module boundaries
113
+ src/controllers/users.controller.ts
114
+ src/services/users.service.ts
115
+ good_example: |
116
+ // ✓ Feature module structure
117
+ src/modules/users/users.controller.ts
118
+ src/modules/users/users.service.ts
119
+ src/modules/users/users.module.ts
120
+ - id: business_logic_in_controller
121
+ severity: critical
122
+ description: "Placing business rules, validation logic, or DB queries directly in controllers instead of services."
123
+ bad_example: |
124
+ @Post()
125
+ async create(@Body() dto: CreateUserDto) {
126
+ const existing = await this.db.findOne({ email: dto.email });
127
+ if (existing) throw new ConflictException();
128
+ dto.password = await bcrypt.hash(dto.password, 10);
129
+ return this.db.save(dto);
130
+ }
131
+ good_example: |
132
+ @Post()
133
+ create(@Body() dto: CreateUserDto) {
134
+ return this.usersService.create(dto);
135
+ }
@@ -0,0 +1,176 @@
1
+ schema_version: "2.0.0"
2
+ id: nextjs-app-router
3
+ name: "Next.js App Router"
4
+ version: "1.1.0"
5
+ description: "Next.js App Router structure with app routes, layouts, server components, server actions, shared UI, and data-access helpers properly separated."
6
+ category: stack
7
+ language: javascript
8
+ frameworks:
9
+ - next
10
+ - react
11
+ detection:
12
+ dependencies:
13
+ any:
14
+ - next
15
+ files:
16
+ - next.config.js
17
+ - next.config.mjs
18
+ - next.config.ts
19
+ - app
20
+ source_indicators:
21
+ - "next/"
22
+ - "\"use client\""
23
+ - "'use client'"
24
+ structure:
25
+ required_dirs:
26
+ - path: app
27
+ purpose: "App Router entry point. Contains only Next.js file-convention files: layout.tsx, page.tsx, loading.tsx, error.tsx, route.ts. No business logic or reusable components live here."
28
+ - path: components
29
+ purpose: "Reusable React components shared across multiple routes. Components here must not import from app/ — they receive data as props or use shared hooks."
30
+ - path: lib
31
+ purpose: "Server-side data access, third-party SDK wrappers, and shared utilities. All database queries and external API calls live here so they can be reused by server components, actions, and route handlers."
32
+ recommended_dirs:
33
+ - path: actions
34
+ purpose: "Server Actions for form mutations and data mutations. Each file begins with 'use server'. Actions call lib/ functions — they do not access the database directly."
35
+ - path: hooks
36
+ purpose: "Client-only React hooks that encapsulate stateful browser behaviour (useLocalStorage, useDebounce). Must not import server-only modules."
37
+ separation:
38
+ rules:
39
+ - concern: routing
40
+ belongs_in: app
41
+ rule_text: "The app directory owns route structure using App Router file conventions (layout.tsx, page.tsx, loading.tsx, error.tsx, route.ts). Pages are thin: they call lib/ functions and pass data to components. No inline SQL, fetch wrappers, or reusable UI definitions inside page.tsx files."
42
+ example: |
43
+ // app/users/page.tsx — correct: thin page, delegates to lib and components
44
+ import { listUsers } from '@/lib/users';
45
+ import { UsersTable } from '@/components/users-table';
46
+
47
+ export default async function UsersPage() {
48
+ const users = await listUsers();
49
+ return <UsersTable users={users} />;
50
+ }
51
+ indicators:
52
+ - "app/"
53
+ - "layout.tsx"
54
+ - "page.tsx"
55
+ - "route.ts"
56
+ - concern: shared_ui
57
+ belongs_in: components
58
+ rule_text: "Reusable React components belong in components/ so route files stay focused on composition and data loading. A component should receive data as props and not perform its own data fetching unless it is an explicitly-marked client component using SWR/React Query."
59
+ example: |
60
+ // components/users-table.tsx — server-safe, pure presentational
61
+ import type { User } from '@/lib/users';
62
+
63
+ export function UsersTable({ users }: { users: User[] }) {
64
+ return (
65
+ <table>
66
+ <tbody>
67
+ {users.map((user) => (
68
+ <tr key={user.id}><td>{user.name}</td></tr>
69
+ ))}
70
+ </tbody>
71
+ </table>
72
+ );
73
+ }
74
+ anti_indicators:
75
+ - "prisma"
76
+ - "sql`"
77
+ - "drizzle"
78
+ - concern: server_action
79
+ belongs_in: actions
80
+ rule_text: "Server Actions for mutations and form handling live in actions/ with an explicit 'use server' directive at the top of the file. Actions validate input, call lib/ functions, and revalidate cache — they do not contain SQL or SDK calls directly."
81
+ example: |
82
+ // actions/user-actions.ts
83
+ 'use server';
84
+
85
+ import { revalidatePath } from 'next/cache';
86
+ import { createUser } from '@/lib/users';
87
+ import { z } from 'zod';
88
+
89
+ const schema = z.object({ name: z.string().min(1) });
90
+
91
+ export async function createUserAction(formData: FormData) {
92
+ const { name } = schema.parse({ name: formData.get('name') });
93
+ await createUser({ name });
94
+ revalidatePath('/users');
95
+ }
96
+ indicators:
97
+ - "\"use server\""
98
+ - "'use server'"
99
+ patterns:
100
+ data_flow:
101
+ direction: "app/page.tsx -> lib/ -> database/external API; actions/ -> lib/ -> database"
102
+ rules:
103
+ - "Use React Server Components by default. Only add 'use client' when the component needs browser APIs, event handlers, or client-side state."
104
+ - "Push 'use client' as far down the component tree as possible to maximize server-rendered surface."
105
+ - "Use loading.tsx and error.tsx file conventions for every route segment that performs async data fetching."
106
+ - "Never access process.env directly in components or lib/ — import from a centralized config module."
107
+ naming:
108
+ routes: "Use App Router file conventions: page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, route.ts. Use (group) folders for layout sharing without URL impact. Use _folder prefix for private non-routable helpers colocated with routes."
109
+ components: "Use PascalCase for component files (UsersTable.tsx) and function names. Use kebab-case for utility and hook files (use-debounce.ts)."
110
+ anti_patterns:
111
+ - id: use_client_everywhere
112
+ severity: warning
113
+ description: "The 'use client' directive is placed at the top of layout, page, or large wrapper components rather than pushed down to only the leaf components that actually need browser interactivity. This unnecessarily turns large component subtrees into client bundles, increasing JavaScript shipped to the browser."
114
+ bad_example: |
115
+ // app/dashboard/layout.tsx — wrong: entire layout becomes a client bundle
116
+ 'use client';
117
+
118
+ export default function DashboardLayout({ children }: { children: React.ReactNode }) {
119
+ return <div className="dashboard">{children}</div>;
120
+ }
121
+ good_example: |
122
+ // app/dashboard/layout.tsx — server component, no directive needed
123
+ export default function DashboardLayout({ children }: { children: React.ReactNode }) {
124
+ return <div className="dashboard">{children}</div>;
125
+ }
126
+
127
+ // components/dashboard-nav.tsx — only the interactive nav is a client component
128
+ 'use client';
129
+ import { useState } from 'react';
130
+ export function DashboardNav() { /* toggle state, event handlers */ }
131
+ - id: client_data_fetching_by_default
132
+ severity: warning
133
+ description: "Data fetching is moved to client components using useEffect/useState without a user interaction requirement. This delays the first meaningful paint, exposes API endpoints unnecessarily, and forfeits React Server Component streaming and caching benefits."
134
+ bad_example: |
135
+ 'use client';
136
+
137
+ export default function UsersPage() {
138
+ const [users, setUsers] = useState([]);
139
+ useEffect(() => {
140
+ fetch('/api/users').then((r) => r.json()).then(setUsers);
141
+ }, []);
142
+ return <UsersTable users={users} />;
143
+ }
144
+ good_example: |
145
+ // Server component — data fetches on the server before any HTML is sent
146
+ import { listUsers } from '@/lib/users';
147
+ import { UsersTable } from '@/components/users-table';
148
+
149
+ export default async function UsersPage() {
150
+ const users = await listUsers();
151
+ return <UsersTable users={users} />;
152
+ }
153
+ - id: direct_db_in_page
154
+ severity: critical
155
+ description: "Database queries or external API calls are made directly inside page.tsx or layout.tsx files instead of being encapsulated in lib/. This scatters data-access logic across the route tree, makes it impossible to reuse queries in Server Actions or Route Handlers, and prevents centralized error handling and logging."
156
+ bad_example: |
157
+ // app/users/page.tsx — wrong: database logic inside the page
158
+ import { prisma } from '@/lib/prisma';
159
+
160
+ export default async function UsersPage() {
161
+ const users = await prisma.user.findMany({ where: { active: true } });
162
+ return <UserList users={users} />;
163
+ }
164
+ good_example: |
165
+ // lib/users.ts — all user queries live here
166
+ import { prisma } from './prisma';
167
+ export async function listActiveUsers() {
168
+ return prisma.user.findMany({ where: { active: true } });
169
+ }
170
+
171
+ // app/users/page.tsx — page calls lib, never touches prisma directly
172
+ import { listActiveUsers } from '@/lib/users';
173
+ export default async function UsersPage() {
174
+ const users = await listActiveUsers();
175
+ return <UserList users={users} />;
176
+ }
@@ -0,0 +1,153 @@
1
+ schema_version: "2.0.0"
2
+ id: react-spa
3
+ name: "React Single Page Application"
4
+ version: "1.1.0"
5
+ description: "React SPA structure with UI components, hooks, pages, services, and utilities separated. Enforces one-way data flow and keeps network logic out of render cycles."
6
+ category: stack
7
+ language: javascript
8
+ frameworks:
9
+ - react
10
+ detection:
11
+ dependencies:
12
+ any:
13
+ - react
14
+ none:
15
+ - next
16
+ source_indicators:
17
+ - "from 'react'"
18
+ - "from \"react\""
19
+ - "useState("
20
+ - "useEffect("
21
+ structure:
22
+ required_dirs:
23
+ - path: src/components
24
+ purpose: "Reusable presentational React components shared across multiple pages. Components here receive all data via props and must not call services or perform fetch requests directly."
25
+ - path: src/hooks
26
+ purpose: "Custom React hooks that encapsulate stateful behaviour, data fetching, and side effects. Hooks here are reused by multiple pages or components — one-off hooks live colocated with their component."
27
+ - path: src/services
28
+ purpose: "Functions that perform HTTP calls and interact with external APIs. Every network request in the app originates here, making it the single place to add auth headers, error normalization, and request retries."
29
+ recommended_dirs:
30
+ - path: src/pages
31
+ purpose: "Top-level route components that correspond to URL paths. Pages orchestrate data loading via hooks and pass results down to components — they are not reused across routes."
32
+ - path: src/utils
33
+ purpose: "Pure helper functions with no React dependency (date formatting, string manipulation, array transforms). Functions here must be synchronous and have no side effects."
34
+ separation:
35
+ rules:
36
+ - concern: ui_component
37
+ belongs_in: src/components
38
+ rule_text: "Components render UI from props and delegated hooks instead of embedding network or business logic. A component that calls fetch() or a service directly cannot be rendered in isolation during testing."
39
+ example: |
40
+ // src/components/user-card.tsx — receives data, never fetches it
41
+ import type { User } from '@/types';
42
+
43
+ export function UserCard({ user }: { user: User }) {
44
+ return (
45
+ <article>
46
+ <h2>{user.name}</h2>
47
+ <p>{user.email}</p>
48
+ </article>
49
+ );
50
+ }
51
+ indicators:
52
+ - "return <"
53
+ - "React.FC"
54
+ - concern: state_logic
55
+ belongs_in: src/hooks
56
+ rule_text: "Reusable stateful behaviour belongs in hooks so pages and components stay declarative. A hook name must start with 'use'. If the same useState/useEffect block appears in two components, extract it into a shared hook."
57
+ example: |
58
+ // src/hooks/use-users.ts — all user-list state in one place
59
+ import { useState, useEffect } from 'react';
60
+ import { listUsers } from '@/services/users';
61
+ import type { User } from '@/types';
62
+
63
+ export function useUsers() {
64
+ const [users, setUsers] = useState<User[]>([]);
65
+ const [loading, setLoading] = useState(true);
66
+
67
+ useEffect(() => {
68
+ void listUsers().then((data) => {
69
+ setUsers(data);
70
+ setLoading(false);
71
+ });
72
+ }, []);
73
+
74
+ return { users, loading };
75
+ }
76
+ indicators:
77
+ - "useState"
78
+ - "useEffect"
79
+ - concern: api_access
80
+ belongs_in: src/services
81
+ rule_text: "HTTP calls and third-party integrations belong in services that hooks and components consume. Services are plain async functions — they do not call useState or useEffect. This makes them independently testable with mocked fetch."
82
+ example: |
83
+ // src/services/users.ts — network logic isolated from React
84
+ import type { User } from '@/types';
85
+
86
+ export async function listUsers(): Promise<User[]> {
87
+ const response = await fetch('/api/users', {
88
+ headers: { Authorization: `Bearer ${getToken()}` },
89
+ });
90
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
91
+ return response.json() as Promise<User[]>;
92
+ }
93
+ indicators:
94
+ - "fetch("
95
+ - "axios."
96
+ patterns:
97
+ data_flow:
98
+ direction: "src/pages -> src/hooks -> src/services -> external API"
99
+ rules:
100
+ - "Components do not perform inline API calls during render. All data fetching happens in hooks."
101
+ - "Shared behaviour moves into custom hooks. If the same useState/useEffect pair appears in two components, it must be extracted."
102
+ - "Lift state to the lowest common ancestor that needs it. Do not put local UI state (modal open, form field value) into global state management."
103
+ - "Derive values from state — do not create a second useState to hold a value that is computable from existing state."
104
+ naming:
105
+ components: "Use PascalCase for component files and function names (UserCard.tsx, ProductList.tsx). Use kebab-case for non-component utility and hook files (use-users.ts, format-date.ts)."
106
+ hooks: "All hook function names must start with 'use' (useUsers, useAuth). The file name matches the hook name in kebab-case (use-users.ts)."
107
+ anti_patterns:
108
+ - id: business_logic_in_components
109
+ severity: warning
110
+ description: "Business logic (validation, data transformation, API calls) is embedded directly in UI components. This makes the component impossible to render in isolation during testing and ties UI to network behaviour."
111
+ bad_example: |
112
+ export function SignupForm() {
113
+ const handleSubmit = async (event: React.FormEvent) => {
114
+ event.preventDefault();
115
+ const payload = validateSignup(new FormData(event.currentTarget));
116
+ await fetch('/api/signup', { method: 'POST', body: JSON.stringify(payload) });
117
+ };
118
+ return <form onSubmit={handleSubmit}>...</form>;
119
+ }
120
+ good_example: |
121
+ // Component delegates to a hook; hook delegates to a service
122
+ export function SignupForm() {
123
+ const { submit, error } = useSignupForm();
124
+ return <form onSubmit={submit}>{error && <p>{error}</p>}</form>;
125
+ }
126
+ - id: inline_api_calls_in_render
127
+ severity: critical
128
+ description: "API calls occur directly during render (outside of useEffect or an async event handler). Each re-render triggers another network request, leading to request storms and race conditions."
129
+ bad_example: |
130
+ export function UsersPage() {
131
+ // called on every render — network storm
132
+ fetch('/api/users').then(() => undefined);
133
+ return <div>Loading...</div>;
134
+ }
135
+ good_example: |
136
+ export function UsersPage() {
137
+ const { users, loading } = useUsers();
138
+ if (loading) return <div>Loading...</div>;
139
+ return <UsersList users={users} />;
140
+ }
141
+ - id: array_index_as_key
142
+ severity: warning
143
+ description: "Using the array index as the React 'key' prop on list items causes silent reconciliation bugs when the list is reordered, filtered, or items are inserted or deleted. React uses the key to match elements between renders — an index-based key can swap component state to the wrong item."
144
+ bad_example: |
145
+ // key={index} breaks when items are reordered or deleted
146
+ {users.map((user, index) => (
147
+ <UserCard key={index} user={user} />
148
+ ))}
149
+ good_example: |
150
+ // Stable unique id from the data model — safe for any list mutation
151
+ {users.map((user) => (
152
+ <UserCard key={user.id} user={user} />
153
+ ))}
@@ -0,0 +1,115 @@
1
+ schema_version: "2.0.0"
2
+ id: vue-nuxt
3
+ name: "Nuxt 3"
4
+ version: "1.1.0"
5
+ description: "Full-stack Nuxt 3 with auto-imports, composables, Nitro server routes, and Pinia state management."
6
+ category: stack
7
+ language: javascript
8
+ frameworks:
9
+ - nuxt
10
+ - vue
11
+ detection:
12
+ dependencies:
13
+ any:
14
+ - nuxt
15
+ none:
16
+ - next
17
+ source_indicators:
18
+ - "defineNuxtConfig"
19
+ - "nuxt.config"
20
+ - "useNuxtApp"
21
+ structure:
22
+ required_dirs:
23
+ - path: pages
24
+ purpose: "File-based route components — each .vue file maps directly to a URL path. Pages are thin: they call composables for data and delegate rendering to components. No business logic or direct API calls in page components."
25
+ - path: components
26
+ purpose: "Reusable Vue components auto-imported by Nuxt — no import statement needed. Components receive data via props and emit events; they must not call useFetch or useAsyncData directly."
27
+ - path: composables
28
+ purpose: "Reusable stateful logic using Vue Composition API — auto-imported. Composables own local or feature-scoped reactive state. For state that must survive navigation or be shared between distant components, use a Pinia store instead."
29
+ - path: server/api
30
+ purpose: "Server-side Nitro API route handlers auto-discovered by filename ([resource].[method].ts). Handlers call server/utils/ functions — they must not embed business logic or SQL directly."
31
+ recommended_dirs:
32
+ - path: server/middleware
33
+ purpose: "Nitro server-side middleware that runs on every request: auth token validation, rate limiting, CORS headers. Executes before server/api/ route handlers."
34
+ - path: stores
35
+ purpose: "Pinia stores for global state that must persist across route navigations or be shared between unrelated components (auth session, shopping cart, notifications). Local UI state that belongs to one component or page stays as composable state — not in a store."
36
+ - path: utils
37
+ purpose: "Auto-imported pure utility functions with no Vue or Nuxt dependency (formatDate, slugify, truncate). Must be synchronous and side-effect-free."
38
+ - path: server/utils
39
+ purpose: "Server-side utility functions and service layer shared across server/api/ route handlers. Database queries, third-party API wrappers, and business logic live here — never inline in event handlers."
40
+ separation:
41
+ rules:
42
+ - concern: data_fetching
43
+ belongs_in: composables
44
+ rule_text: "Use useFetch() or useAsyncData() inside composables, not directly in page components. This enables reuse, keeps pages declarative, and supports SSR hydration without duplication."
45
+ example: |
46
+ // composables/useUsers.ts
47
+ export function useUsers() {
48
+ return useFetch('/api/users');
49
+ }
50
+ // pages/users.vue
51
+ const { data: users } = useUsers();
52
+ indicators:
53
+ - "useFetch"
54
+ - "useAsyncData"
55
+ - concern: server_routes
56
+ belongs_in: server/api
57
+ rule_text: "Server routes in server/api/ use defineEventHandler(). They call services or utilities for business logic — no DB queries directly in event handlers."
58
+ example: |
59
+ // server/api/users.get.ts
60
+ export default defineEventHandler(async (event) => {
61
+ return getUsersService();
62
+ });
63
+ - concern: auto_imports
64
+ belongs_in: components
65
+ rule_text: "Nuxt auto-imports components, composables, and utils. Do NOT add explicit import statements for these — let Nuxt's auto-import system handle it."
66
+ example: |
67
+ // ✓ Just use it — Nuxt handles the import
68
+ const { data } = useUsers();
69
+ anti_indicators:
70
+ - "import { use"
71
+ - "from '~/composables"
72
+ - "from '~/components"
73
+ patterns:
74
+ data_flow:
75
+ direction: "Page → Composable → useFetch/useAsyncData → Server Route → Service"
76
+ rules:
77
+ - "Pages use composables for data fetching — not useFetch directly."
78
+ - "Server API routes handle business logic via server utilities."
79
+ - "Pinia stores manage global client-side state."
80
+ error_handling:
81
+ recommended: "Use createError() in server routes and useError() in pages for unified error handling."
82
+ naming:
83
+ composables: "use[Resource].ts"
84
+ stores: "[resource].store.ts"
85
+ server_routes: "[resource].[method].ts"
86
+ anti_patterns:
87
+ - id: explicit_auto_imports
88
+ severity: warning
89
+ description: "Writing explicit import statements for components, composables, or utils that Nuxt auto-imports adds noise and can cause confusion."
90
+ bad_example: |
91
+ // ❌ Nuxt auto-imports this — explicit import is redundant
92
+ import { useUsers } from '~/composables/useUsers';
93
+ good_example: |
94
+ // ✓ Just use it — Nuxt handles the import automatically
95
+ const { data } = useUsers();
96
+ - id: db_in_page_component
97
+ severity: critical
98
+ description: "Querying databases directly in page or layout components instead of going through server routes."
99
+ bad_example: |
100
+ // ❌ DB access in a page component — only works server-side, breaks hydration
101
+ const users = await prisma.user.findMany();
102
+ good_example: |
103
+ // ✓ Page → composable → server route → service
104
+ const { data: users } = useUsers();
105
+ - id: fetch_in_component
106
+ severity: warning
107
+ description: "Using useFetch() or useAsyncData() directly in page components instead of wrapping them in composables — prevents reuse and makes pages harder to test."
108
+ bad_example: |
109
+ // pages/users.vue — useFetch directly in page
110
+ const { data: users } = useFetch('/api/users');
111
+ good_example: |
112
+ // composables/useUsers.ts
113
+ export function useUsers() { return useFetch('/api/users'); }
114
+ // pages/users.vue
115
+ const { data: users } = useUsers();