@baldurpan/create-ai-workflow 0.2.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 (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/agents-block.js +70 -0
  4. package/dist/bin.js +14 -0
  5. package/dist/check/markdown.js +47 -0
  6. package/dist/check/parse.js +113 -0
  7. package/dist/check/rules.js +245 -0
  8. package/dist/cli.js +109 -0
  9. package/dist/commands/check.js +41 -0
  10. package/dist/commands/install.js +76 -0
  11. package/dist/commands/standards-add.js +145 -0
  12. package/dist/commands/update.js +214 -0
  13. package/dist/layout.js +115 -0
  14. package/dist/log.js +20 -0
  15. package/dist/manifest.js +53 -0
  16. package/dist/paths.js +41 -0
  17. package/package.json +37 -0
  18. package/templates/blocks/agents-block.md +30 -0
  19. package/templates/claude/agents/planner.agent.md +60 -0
  20. package/templates/claude/agents/reviewer.agent.md +77 -0
  21. package/templates/context/README.md +81 -0
  22. package/templates/context/plan-template.md +69 -0
  23. package/templates/context/plan-template.notes.md +55 -0
  24. package/templates/context/roles/coder.md +76 -0
  25. package/templates/context/workflow.md +143 -0
  26. package/templates/skills/feature-close/SKILL.md +102 -0
  27. package/templates/skills/feature-implement/SKILL.md +142 -0
  28. package/templates/skills/feature-plan/SKILL.md +138 -0
  29. package/templates/skills/feature-status/SKILL.md +86 -0
  30. package/templates/skills/onboard/SKILL.md +122 -0
  31. package/templates/skills/orchestrate/SKILL.md +92 -0
  32. package/templates/skills/roadmap/SKILL.md +97 -0
  33. package/templates/standards/.source +8 -0
  34. package/templates/standards/README.md +104 -0
  35. package/templates/standards/architecture/api-design.md +212 -0
  36. package/templates/standards/architecture/dependency-boundaries.md +104 -0
  37. package/templates/standards/architecture/feature-driven.md +102 -0
  38. package/templates/standards/architecture/folder-structure.md +108 -0
  39. package/templates/standards/architecture/monorepos.md +107 -0
  40. package/templates/standards/architecture/refactoring.md +97 -0
  41. package/templates/standards/architecture/shared-code.md +81 -0
  42. package/templates/standards/docs/PHP-SPEC.md +1195 -0
  43. package/templates/standards/docs/SPEC.md +540 -0
  44. package/templates/standards/examples/bad/data-fetching.tsx +52 -0
  45. package/templates/standards/examples/bad/derived-state.tsx +60 -0
  46. package/templates/standards/examples/bad/feature-component.tsx +80 -0
  47. package/templates/standards/examples/bad/prop-drilling.tsx +70 -0
  48. package/templates/standards/examples/good/data-fetching.tsx +53 -0
  49. package/templates/standards/examples/good/derived-state.tsx +52 -0
  50. package/templates/standards/examples/good/feature-component.tsx +141 -0
  51. package/templates/standards/examples/good/invoice.schema.ts +20 -0
  52. package/templates/standards/examples/good/prop-drilling.tsx +83 -0
  53. package/templates/standards/philosophy/ai-agent-behavior.md +93 -0
  54. package/templates/standards/philosophy/core-principles.md +49 -0
  55. package/templates/standards/philosophy/incremental-abstraction.md +56 -0
  56. package/templates/standards/philosophy/maintainability.md +66 -0
  57. package/templates/standards/philosophy/readability.md +87 -0
  58. package/templates/standards/php/README.md +62 -0
  59. package/templates/standards/php/anti-patterns.md +259 -0
  60. package/templates/standards/php/architecture.md +241 -0
  61. package/templates/standards/php/frameworks.md +197 -0
  62. package/templates/standards/php/rules.md +205 -0
  63. package/templates/standards/php/security.md +190 -0
  64. package/templates/standards/php/testing.md +139 -0
  65. package/templates/standards/php/tooling.md +245 -0
  66. package/templates/standards/react/accessibility.md +130 -0
  67. package/templates/standards/react/anti-patterns.md +187 -0
  68. package/templates/standards/react/component-design.md +139 -0
  69. package/templates/standards/react/error-boundaries.md +195 -0
  70. package/templates/standards/react/forms.md +147 -0
  71. package/templates/standards/react/hooks.md +88 -0
  72. package/templates/standards/react/memoization.md +87 -0
  73. package/templates/standards/react/state-management.md +123 -0
  74. package/templates/standards/react/testing.md +118 -0
  75. package/templates/standards/react/use-effect.md +110 -0
  76. package/templates/standards/security/api-security.md +136 -0
  77. package/templates/standards/security/auth.md +112 -0
  78. package/templates/standards/security/secrets.md +105 -0
  79. package/templates/standards/security/validation.md +89 -0
  80. package/templates/standards/templates/.editorconfig +16 -0
  81. package/templates/standards/templates/.nvmrc +1 -0
  82. package/templates/standards/templates/AGENTS.md +46 -0
  83. package/templates/standards/templates/CLAUDE.md +3 -0
  84. package/templates/standards/templates/_dot_gitignore +50 -0
  85. package/templates/standards/templates/biome.json +53 -0
  86. package/templates/standards/templates/eslint.config.js +61 -0
  87. package/templates/standards/templates/project-readme.md +76 -0
  88. package/templates/standards/templates/pull-request-template.md +46 -0
  89. package/templates/standards/templates/tsconfig.json +35 -0
  90. package/templates/standards/tooling/biome.md +92 -0
  91. package/templates/standards/tooling/ci.md +128 -0
  92. package/templates/standards/tooling/dates.md +194 -0
  93. package/templates/standards/tooling/dependencies.md +90 -0
  94. package/templates/standards/tooling/nx.md +113 -0
  95. package/templates/standards/tooling/observability.md +183 -0
  96. package/templates/standards/tooling/prisma.md +152 -0
  97. package/templates/standards/tooling/shadcn.md +115 -0
  98. package/templates/standards/tooling/tailwind.md +135 -0
  99. package/templates/standards/tooling/tanstack-query.md +214 -0
  100. package/templates/standards/tooling/tanstack-router.md +365 -0
  101. package/templates/standards/tooling/tanstack.md +31 -0
  102. package/templates/standards/tooling/vite.md +135 -0
  103. package/templates/standards/typescript/anti-patterns.md +107 -0
  104. package/templates/standards/typescript/error-handling.md +216 -0
  105. package/templates/standards/typescript/naming.md +78 -0
  106. package/templates/standards/typescript/rules.md +159 -0
  107. package/templates/standards/typescript/tsconfig/base.json +32 -0
  108. package/templates/standards/typescript/tsconfig/nextjs.json +12 -0
  109. package/templates/standards/typescript/tsconfig/react.json +9 -0
  110. package/templates/standards/typescript/validation.md +104 -0
  111. package/templates/stubs/executors.md +49 -0
  112. package/templates/stubs/findings.md +40 -0
  113. package/templates/stubs/history.md +13 -0
  114. package/templates/stubs/roadmap.md +29 -0
  115. package/templates/stubs/stack.md +35 -0
  116. package/templates/stubs/verify.md +48 -0
@@ -0,0 +1,212 @@
1
+ # API Design and Client Patterns
2
+
3
+ ## Core Rules
4
+
5
+ - API types are generated or inferred — never duplicated by hand
6
+ - Validate at the boundary on both sides (server validates incoming, client validates responses)
7
+ - Use a consistent error response shape across all endpoints
8
+ - Versioning is explicit when contracts change in breaking ways
9
+ - Mock servers in development — do not block frontend work on backend availability
10
+
11
+ ## Choosing an API Layer
12
+
13
+ | Approach | Use when |
14
+ |---|---|
15
+ | **tRPC** | Same team owns FE and BE, both in TypeScript — end-to-end type safety, no codegen step |
16
+ | **OpenAPI + generated client** | Polyglot backend, public API, or external consumers |
17
+ | **GraphQL** | Many client types with different field needs, or complex relational queries |
18
+ | **Hand-written REST + Zod** | Small project, no FE/BE coordination needed, simple endpoints |
19
+
20
+ Pick one per service. Mixing approaches creates two type pipelines to maintain.
21
+
22
+ ## tRPC Pattern
23
+
24
+ ```ts
25
+ // server/router.ts
26
+ import { initTRPC } from "@trpc/server";
27
+ import { z } from "zod";
28
+
29
+ const t = initTRPC.create();
30
+
31
+ export const appRouter = t.router({
32
+ invoice: t.router({
33
+ list: t.procedure
34
+ .input(z.object({ status: z.enum(["all", "open", "paid"]).default("all") }))
35
+ .query(({ input }) => db.invoice.findMany({ where: { status: input.status } })),
36
+
37
+ create: t.procedure
38
+ .input(createInvoiceSchema)
39
+ .mutation(({ input, ctx }) =>
40
+ db.invoice.create({ data: { ...input, userId: ctx.userId } }),
41
+ ),
42
+ }),
43
+ });
44
+
45
+ export type AppRouter = typeof appRouter;
46
+ ```
47
+
48
+ ```ts
49
+ // client — types flow from the server router definition
50
+ const invoices = await trpc.invoice.list.query({ status: "open" });
51
+ // invoices is fully typed; no manual DTO
52
+ ```
53
+
54
+ ## OpenAPI Pattern
55
+
56
+ For polyglot or public APIs:
57
+
58
+ ```bash
59
+ # Generate a typed client from an OpenAPI spec
60
+ pnpm dlx openapi-typescript ./openapi.yaml -o ./src/lib/api-types.ts
61
+ ```
62
+
63
+ Use a small fetch wrapper that validates with the generated types:
64
+
65
+ ```ts
66
+ import type { paths } from "~/lib/api-types";
67
+ import createClient from "openapi-fetch";
68
+
69
+ export const api = createClient<paths>({ baseUrl: env.VITE_API_BASE_URL });
70
+
71
+ const { data, error } = await api.GET("/invoices", { params: { query: { status: "open" } } });
72
+ ```
73
+
74
+ ## Hand-Written Fetch + Zod
75
+
76
+ For small projects without a generated client:
77
+
78
+ ```ts
79
+ import { z } from "zod";
80
+
81
+ const invoiceSchema = z.object({ id: z.string(), title: z.string(), amount: z.number() });
82
+ const invoicesResponseSchema = z.object({ items: invoiceSchema.array(), nextCursor: z.string().nullable() });
83
+
84
+ export async function fetchInvoices(cursor?: string) {
85
+ const url = new URL("/api/invoices", env.VITE_API_BASE_URL);
86
+ if (cursor) url.searchParams.set("cursor", cursor);
87
+
88
+ const response = await fetch(url);
89
+ if (!response.ok) {
90
+ throw new ApiError(response.status, await response.text());
91
+ }
92
+ return invoicesResponseSchema.parse(await response.json());
93
+ }
94
+ ```
95
+
96
+ ## Standard Error Response Shape
97
+
98
+ Use one error shape across all endpoints:
99
+
100
+ ```ts
101
+ // shared/schemas/api-error.schema.ts
102
+ export const apiErrorSchema = z.object({
103
+ error: z.object({
104
+ code: z.string(), // machine-readable: "NOT_FOUND", "VALIDATION_FAILED"
105
+ message: z.string(), // human-readable, safe to show
106
+ details: z.record(z.unknown()).optional(), // field errors, etc.
107
+ requestId: z.string().optional(),
108
+ }),
109
+ });
110
+ ```
111
+
112
+ Server example:
113
+
114
+ ```ts
115
+ return res.status(422).json({
116
+ error: {
117
+ code: "VALIDATION_FAILED",
118
+ message: "Some fields are invalid",
119
+ details: result.error.flatten().fieldErrors,
120
+ requestId: req.id,
121
+ },
122
+ });
123
+ ```
124
+
125
+ ## Pagination
126
+
127
+ Prefer **cursor-based pagination** for performance and stability with mutable datasets:
128
+
129
+ ```ts
130
+ // Request: GET /invoices?cursor=eyJpZCI6...&limit=20
131
+ // Response:
132
+ {
133
+ items: Invoice[],
134
+ nextCursor: string | null, // null when at end
135
+ }
136
+ ```
137
+
138
+ Use **offset/page pagination** only for small, stable datasets where the user expects page numbers (admin tables, search results).
139
+
140
+ ## Versioning
141
+
142
+ When making a breaking change:
143
+
144
+ - **Additive change** (new optional field, new endpoint) — no version bump needed
145
+ - **Breaking change** (removed field, changed type, removed endpoint) — bump the API version
146
+
147
+ Common strategies:
148
+ - URL prefix: `/v1/invoices`, `/v2/invoices`
149
+ - Header: `Accept: application/vnd.acme.v2+json`
150
+
151
+ Keep the old version working for one deprecation cycle (typically 1–2 releases). Document the migration path.
152
+
153
+ ## Mock Servers
154
+
155
+ Frontend should never be blocked on backend availability.
156
+
157
+ Options:
158
+ - **MSW** (Mock Service Worker) — intercepts fetch at the browser/Node level; same handlers in tests and dev
159
+ - **Prism** — runs an OpenAPI spec as a mock server
160
+ - **tRPC** — type-safe mocks via `@trpc/react-query`'s `createTRPCMsw`
161
+
162
+ ```ts
163
+ // MSW handler
164
+ import { http, HttpResponse } from "msw";
165
+
166
+ export const handlers = [
167
+ http.get("/api/invoices", () =>
168
+ HttpResponse.json({
169
+ items: [{ id: "1", title: "Q4 Report", amount: 500 }],
170
+ nextCursor: null,
171
+ }),
172
+ ),
173
+ ];
174
+ ```
175
+
176
+ ## Idempotency
177
+
178
+ For mutations that might be retried (network errors, optimistic UI), accept an `Idempotency-Key` header so the same request can be safely sent twice:
179
+
180
+ ```ts
181
+ // Client
182
+ await api.POST("/invoices", {
183
+ body: invoice,
184
+ headers: { "Idempotency-Key": crypto.randomUUID() },
185
+ });
186
+ ```
187
+
188
+ The server deduplicates on this key for some window (e.g., 24 hours).
189
+
190
+ ## DO NOT
191
+
192
+ - Hand-write FE types that mirror BE types — generate or infer instead
193
+ - Return different error shapes from different endpoints
194
+ - Mix snake_case and camelCase in the same API surface
195
+ - Expose internal IDs / database errors / stack traces in error responses
196
+ - Skip mocking in development — it slows everyone down
197
+
198
+ ## PRIORITY
199
+
200
+ ```
201
+ Generated types > Hand-written DTOs
202
+ Cursor pagination > Offset pagination
203
+ Mock-first frontend > Blocked-on-backend frontend
204
+ ```
205
+
206
+ ## See Also
207
+
208
+ - [`typescript/validation.md`](../typescript/validation.md) — schema-driven validation
209
+ - [`security/api-security.md`](../security/api-security.md) — status codes, rate limiting, CORS
210
+ - [`security/validation.md`](../security/validation.md) — input validation at boundaries
211
+ - [`tooling/tanstack-query.md`](../tooling/tanstack-query.md) — TanStack Query patterns
212
+ - [`tooling/tanstack-router.md`](../tooling/tanstack-router.md) — route loaders, typed search params
@@ -0,0 +1,104 @@
1
+ # Dependency Boundaries
2
+
3
+ ## Core Rule
4
+
5
+ Features must not depend on each other. Features depend on `shared/`. `shared/` depends on nothing internal.
6
+
7
+ ## Allowed Dependencies
8
+
9
+ ```
10
+ apps/web → packages/ui, packages/schemas
11
+ apps/api → packages/schemas
12
+ features/X → shared/
13
+ features/X → lib/
14
+ shared/ → lib/
15
+ lib/ → external packages only
16
+ packages/* → external packages only (no internal app code)
17
+ ```
18
+
19
+ ## Forbidden Dependencies
20
+
21
+ ```
22
+ features/invoices → features/users ✗ cross-feature import
23
+ packages/ui → apps/web ✗ package depends on app
24
+ shared/ → features/ ✗ shared depends on feature
25
+ ```
26
+
27
+ ## In Practice
28
+
29
+ If feature A needs something from feature B:
30
+
31
+ **Option 1: Move it to `shared/`**
32
+ - Move the shared concept to `shared/`
33
+ - Both features import from `shared/`
34
+
35
+ **Option 2: Pass it as a prop or callback**
36
+ - Feature A receives the data it needs via props
37
+ - Feature B provides the data at the composition layer (page, layout)
38
+
39
+ **Option 3: Use a shared store or context**
40
+ - If it is runtime state (current user, theme), put it in context or Zustand
41
+ - Both features read from the same source
42
+
43
+ ## Detecting Violations
44
+
45
+ In a monorepo, use Nx's enforcement:
46
+
47
+ ```json
48
+ // nx.json
49
+ {
50
+ "targetDefaults": {
51
+ "lint": {
52
+ "configurations": {
53
+ "enforce-boundaries": true
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ In a single app, use ESLint's `import/no-restricted-paths`:
61
+
62
+ ```js
63
+ // eslint.config.js
64
+ {
65
+ rules: {
66
+ "import/no-restricted-paths": ["error", {
67
+ zones: [
68
+ {
69
+ target: "./src/features",
70
+ from: "./src/features",
71
+ except: ["./src/features/invoices"], // each feature only allows itself
72
+ },
73
+ ],
74
+ }],
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Circular Dependencies
80
+
81
+ Circular dependencies are always forbidden. They indicate a design problem.
82
+
83
+ Common causes:
84
+ - `shared/` importing from a feature
85
+ - Two features that should be combined into one
86
+ - Missing abstraction that should be in `shared/`
87
+
88
+ Use `madge` to detect cycles:
89
+
90
+ ```bash
91
+ pnpm dlx madge --circular src/
92
+ ```
93
+
94
+ ## PRIORITY
95
+
96
+ ```
97
+ Isolation > Convenience > DRY
98
+ ```
99
+
100
+ ## See Also
101
+
102
+ - [`feature-driven.md`](feature-driven.md) — feature ownership
103
+ - [`shared-code.md`](shared-code.md) — what belongs in `shared/`
104
+ - [`monorepos.md`](monorepos.md) — package-level boundaries
@@ -0,0 +1,102 @@
1
+ # Feature-Driven Architecture
2
+
3
+ ## Core Rule
4
+
5
+ Organize code by feature, not by type. A feature owns everything it needs.
6
+
7
+ ## Structure
8
+
9
+ ```
10
+ src/
11
+ features/
12
+ invoices/
13
+ InvoiceTable.tsx ← component
14
+ InvoiceTable.test.tsx ← test colocated
15
+ InvoiceFilters.tsx
16
+ InvoiceRow.tsx
17
+ useInvoiceSort.ts ← hook used only in this feature
18
+ invoice.schema.ts ← Zod schemas for this feature
19
+ invoice.api.ts ← data fetching for this feature
20
+ invoice.types.ts ← types not derivable from schema
21
+ users/
22
+ UserProfile.tsx
23
+ useCurrentUser.ts
24
+ user.schema.ts
25
+ shared/
26
+ components/ ← reused across 3+ features
27
+ hooks/
28
+ schemas/
29
+ utils/
30
+ app/ ← routing, layout, providers
31
+ ```
32
+
33
+ ## What Goes in a Feature
34
+
35
+ A feature folder contains everything the feature needs that is not shared with other features:
36
+
37
+ - Components (primary + sub-components)
38
+ - Hooks specific to this feature
39
+ - API functions
40
+ - Zod schemas and inferred types
41
+ - Tests
42
+ - Constants used only here
43
+
44
+ ## What Belongs in `shared/`
45
+
46
+ Move to `shared/` only when:
47
+ - Used by 3 or more distinct features
48
+ - The shared nature is expected to be permanent, not incidental
49
+
50
+ Never move something to `shared/` preemptively.
51
+
52
+ ## DO NOT
53
+
54
+ - Organize by type at the root level (`components/`, `hooks/`, `types/`) for a large app
55
+ - Import from another feature's internals directly
56
+ - Create a `utils/` catch-all that accumulates unrelated helpers over time
57
+
58
+ ## Feature Communication
59
+
60
+ Features must not import from each other's internals. If two features share a concept:
61
+
62
+ 1. Move the shared concept to `shared/`
63
+ 2. Both features import from `shared/`
64
+
65
+ ```
66
+ features/
67
+ invoices/
68
+ invoice.schema.ts ← imports User from shared/schemas/user.schema.ts
69
+ users/
70
+ user.schema.ts ← defined here, re-exported from shared/
71
+ shared/
72
+ schemas/
73
+ user.schema.ts ← canonical location for shared User schema
74
+ ```
75
+
76
+ ## Scaling
77
+
78
+ As the app grows, features can be grouped by domain:
79
+
80
+ ```
81
+ features/
82
+ billing/
83
+ invoices/
84
+ payments/
85
+ subscriptions/
86
+ crm/
87
+ contacts/
88
+ companies/
89
+ ```
90
+
91
+ ## PRIORITY
92
+
93
+ ```
94
+ Feature isolation > Shared reuse > Organizational elegance
95
+ ```
96
+
97
+ ## See Also
98
+
99
+ - [`shared-code.md`](shared-code.md) — what belongs in `shared/`
100
+ - [`folder-structure.md`](folder-structure.md) — canonical folder maps
101
+ - [`dependency-boundaries.md`](dependency-boundaries.md) — feature isolation rules
102
+ - [`../philosophy/maintainability.md`](../philosophy/maintainability.md) — colocation principle
@@ -0,0 +1,108 @@
1
+ # Folder Structure
2
+
3
+ ## React App (Single Repo)
4
+
5
+ ```
6
+ src/
7
+ app/ ← routing, layout, root providers
8
+ layout.tsx
9
+ providers.tsx
10
+ router.tsx
11
+ features/ ← feature-driven modules
12
+ invoices/
13
+ InvoiceTable.tsx
14
+ InvoiceTable.test.tsx
15
+ useInvoiceSort.ts
16
+ invoice.schema.ts
17
+ invoice.api.ts
18
+ users/
19
+ UserProfile.tsx
20
+ user.schema.ts
21
+ shared/ ← reused across 3+ features
22
+ components/
23
+ Button.tsx
24
+ Modal.tsx
25
+ hooks/
26
+ useDebounce.ts
27
+ schemas/
28
+ pagination.schema.ts
29
+ utils/
30
+ format-currency.ts
31
+ lib/ ← third-party adapter layer
32
+ db.ts
33
+ auth.ts
34
+ stripe.ts
35
+ styles/
36
+ globals.css
37
+ main.tsx
38
+ ```
39
+
40
+ ## Next.js App (App Router)
41
+
42
+ ```
43
+ app/ ← Next.js App Router
44
+ (auth)/
45
+ login/
46
+ page.tsx
47
+ (dashboard)/
48
+ invoices/
49
+ page.tsx
50
+ [id]/
51
+ page.tsx
52
+ layout.tsx
53
+ providers.tsx
54
+ src/ ← application code (same as above)
55
+ features/
56
+ shared/
57
+ lib/
58
+ public/
59
+ ```
60
+
61
+ ## Monorepo
62
+
63
+ ```
64
+ apps/
65
+ web/ ← frontend app
66
+ src/
67
+ features/
68
+ shared/
69
+ lib/
70
+ api/ ← backend app
71
+ src/
72
+ routes/
73
+ services/
74
+ lib/
75
+ packages/
76
+ ui/ ← shared component library
77
+ schemas/ ← shared Zod schemas
78
+ tsconfig/
79
+ eslint-config/
80
+ biome-config/
81
+ nx.json
82
+ pnpm-workspace.yaml
83
+ ```
84
+
85
+ ## Rules
86
+
87
+ - Feature folders are flat by default — add sub-folders only when a feature grows large
88
+ - `shared/` files are named by purpose, not by type: `format-currency.ts` not `string-utils.ts`
89
+ - `lib/` contains only external service adapters — no business logic
90
+ - Tests live next to the code they test, not in a separate `__tests__/` directory
91
+ - Use `index.ts` barrel exports sparingly — only at feature boundaries, not inside features
92
+
93
+ ## File Naming
94
+
95
+ | Type | Convention | Example |
96
+ |---|---|---|
97
+ | React components | `PascalCase.tsx` | `InvoiceTable.tsx` |
98
+ | Hooks | `camelCase.ts` | `useInvoiceSort.ts` |
99
+ | Schemas | `kebab-case.schema.ts` | `invoice.schema.ts` |
100
+ | API functions | `kebab-case.api.ts` | `invoice.api.ts` |
101
+ | Utilities | `kebab-case.ts` | `format-currency.ts` |
102
+ | Tests | same name + `.test.ts(x)` | `InvoiceTable.test.tsx` |
103
+
104
+ ## See Also
105
+
106
+ - [`feature-driven.md`](feature-driven.md) — feature folder anatomy
107
+ - [`shared-code.md`](shared-code.md) — `shared/` vs `lib/`
108
+ - [`dependency-boundaries.md`](dependency-boundaries.md) — import rules between layers
@@ -0,0 +1,107 @@
1
+ # Monorepos
2
+
3
+ ## Preferred Tooling
4
+
5
+ - **Nx** — build system, task orchestration, generators, affected commands
6
+ - **pnpm** — package manager (workspaces, efficient storage, strict linking)
7
+
8
+ ## When to Use a Monorepo
9
+
10
+ Use a monorepo when:
11
+ - A frontend and backend share types or schemas
12
+ - Multiple apps share a component library
13
+ - A team maintains more than one deployable unit with significant shared code
14
+
15
+ Do not add monorepo tooling to a single-app project speculatively.
16
+
17
+ ## Workspace Structure
18
+
19
+ ```
20
+ apps/
21
+ web/ ← Next.js / Remix frontend
22
+ api/ ← Express / Hono / tRPC backend
23
+ packages/
24
+ ui/ ← shared component library
25
+ schemas/ ← shared Zod schemas (FE + BE)
26
+ tsconfig/ ← shared tsconfig presets
27
+ eslint-config/ ← shared ESLint config
28
+ biome-config/ ← shared Biome config
29
+ ```
30
+
31
+ Group packages by domain when scaling:
32
+
33
+ ```
34
+ packages/
35
+ frontend/
36
+ ui/
37
+ design-tokens/
38
+ backend/
39
+ database/
40
+ email/
41
+ shared/
42
+ schemas/
43
+ utils/
44
+ ```
45
+
46
+ ## Nx Setup
47
+
48
+ ```bash
49
+ pnpm dlx create-nx-workspace@latest acme --preset=ts
50
+ ```
51
+
52
+ Key Nx commands:
53
+
54
+ ```bash
55
+ nx build web # build a specific project
56
+ nx test api # test a specific project
57
+ nx affected --target=build # build only changed projects
58
+ nx graph # visualize dependency graph
59
+ nx generate @nx/react:component # generate a component
60
+ ```
61
+
62
+ ## pnpm Workspaces
63
+
64
+ ```yaml
65
+ # pnpm-workspace.yaml
66
+ packages:
67
+ - "apps/*"
68
+ - "packages/*"
69
+ ```
70
+
71
+ Use workspace protocol for internal dependencies:
72
+
73
+ ```json
74
+ {
75
+ "dependencies": {
76
+ "@acme/schemas": "workspace:*",
77
+ "@acme/ui": "workspace:*"
78
+ }
79
+ }
80
+ ```
81
+
82
+ ## Dependency Rules
83
+
84
+ - Apps may depend on packages
85
+ - Packages must not depend on apps
86
+ - Packages should not depend on other packages unless the dependency is stable and intentional
87
+ - Use `nx graph` to audit the dependency graph
88
+ - Circular dependencies are forbidden
89
+
90
+ ## DO NOT
91
+
92
+ - Create publishable packages unless explicitly required for external consumption
93
+ - Add unnecessary inter-package dependencies
94
+ - Bypass the monorepo's package boundaries with relative imports across app/package boundaries
95
+ - Use `npm` or `yarn` in a pnpm workspace
96
+
97
+ ## PRIORITY
98
+
99
+ ```
100
+ Feature isolation > Build efficiency > Package granularity
101
+ ```
102
+
103
+ ## See Also
104
+
105
+ - [`../tooling/nx.md`](../tooling/nx.md) — Nx commands and configuration
106
+ - [`dependency-boundaries.md`](dependency-boundaries.md) — cross-package rules
107
+ - [`../tooling/ci.md`](../tooling/ci.md) — `nx affected` in CI