create-win-project 1.3.0 → 1.4.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 (232) hide show
  1. package/README.md +19 -28
  2. package/{scripts/compatibility-matrix.mjs → checks/check-compatibility.js} +24 -6
  3. package/{scripts/verify-generated.mjs → checks/check-generated-project.js} +2 -2
  4. package/{scripts/validate-content.mjs → checks/check-library.js} +5 -5
  5. package/checks/classify-changes.js +39 -0
  6. package/docs/ARCHITECTURE.md +83 -40
  7. package/docs/CONTENT_MODEL.md +3 -3
  8. package/docs/CONTRIBUTING.md +154 -0
  9. package/docs/DEPENDENCY_MAINTENANCE.md +1 -1
  10. package/index.js +2 -429
  11. package/{playbooks → library}/INDEX.md +4 -4
  12. package/{playbooks/capabilities/ci/github-actions.manifest.json → library/development-tools/ci/definition.json} +1 -0
  13. package/{playbooks/devops/makefile.manifest.json → library/development-tools/devops/makefile/definition.json} +1 -0
  14. package/{playbooks/devops/pr-template.manifest.json → library/development-tools/devops/pr-template/definition.json} +1 -0
  15. package/{playbooks/platform/mobile.manifest.json → library/platforms/mobile/definition.json} +1 -0
  16. package/{playbooks/platform/web.manifest.json → library/platforms/web/definition.json} +1 -0
  17. package/{compatibility/profiles.json → library/tested-versions.json} +4 -0
  18. package/{playbooks/universal/accessibility.manifest.json → library/universal/accessibility/definition.json} +1 -1
  19. package/{playbooks/universal/coding-rules.manifest.json → library/universal/coding-rules/definition.json} +1 -0
  20. package/{playbooks/universal/error-handling.manifest.json → library/universal/error-handling/definition.json} +1 -0
  21. package/{playbooks/universal/git-conventions.manifest.json → library/universal/git-conventions/definition.json} +1 -0
  22. package/{playbooks/universal/observability.manifest.json → library/universal/observability/definition.json} +1 -0
  23. package/{playbooks/universal/security.manifest.json → library/universal/security/definition.json} +1 -0
  24. package/{playbooks/universal/typescript.manifest.json → library/universal/typescript/definition.json} +1 -0
  25. package/package.json +12 -11
  26. package/public/logo.svg +19 -0
  27. package/src/cli/arguments.js +52 -0
  28. package/src/cli/display.js +220 -0
  29. package/src/cli/main.js +185 -0
  30. package/src/cli/navigation.js +156 -0
  31. package/src/cli/questions.js +187 -0
  32. package/src/cli/system-check.js +138 -0
  33. package/src/engine/create-project.js +10 -0
  34. package/src/engine/install-dependencies.js +13 -0
  35. package/{lib/catalog.js → src/engine/load-library.js} +5 -6
  36. package/{lib/playbooks.js → src/engine/project-guidance.js} +25 -3
  37. package/{lib/template.js → src/engine/render-templates.js} +8 -0
  38. package/src/engine/write-files.js +34 -0
  39. package/{lib/stacks/registry.js → src/stacks/available-stacks.js} +23 -1
  40. package/src/stacks/backends/README.md +5 -0
  41. package/{lib/stacks → src/stacks/backends}/laravel/architecture.js +1 -0
  42. package/{lib/stacks → src/stacks/backends}/laravel/auth/oidc.js +1 -0
  43. package/{lib/stacks → src/stacks/backends}/laravel/auth/public.js +1 -0
  44. package/{lib/stacks → src/stacks/backends}/laravel/auth/sanctum.js +1 -0
  45. package/{lib/stacks → src/stacks/backends}/laravel/auth/session.js +1 -0
  46. package/src/stacks/backends/laravel/ci.js +3 -0
  47. package/{lib/stacks → src/stacks/backends}/laravel/composer.js +1 -1
  48. package/{lib/stacks/laravel/generate.js → src/stacks/backends/laravel/create-files.js} +1 -0
  49. package/src/stacks/backends/laravel/docker.js +14 -0
  50. package/src/stacks/backends/laravel/environment.js +5 -0
  51. package/{lib/stacks → src/stacks/backends}/laravel/index.js +11 -3
  52. package/{lib/stacks → src/stacks/backends}/laravel/ui/blade.js +1 -0
  53. package/{lib/stacks → src/stacks/backends}/laravel/ui/index.js +1 -0
  54. package/{lib/stacks → src/stacks/backends}/laravel/ui/inertia-react.js +4 -2
  55. package/{lib/stacks → src/stacks/backends}/laravel/ui/livewire.js +1 -0
  56. package/{lib/stacks → src/stacks/backends}/laravel/ui/shared.js +1 -0
  57. package/src/stacks/backends/none/index.js +23 -0
  58. package/src/stacks/backends/postgres/ci.js +3 -0
  59. package/src/stacks/backends/postgres/create-files.js +21 -0
  60. package/src/stacks/backends/postgres/docker.js +3 -0
  61. package/src/stacks/backends/postgres/environment.js +3 -0
  62. package/src/stacks/backends/postgres/index.js +30 -0
  63. package/src/stacks/backends/springboot/ci.js +3 -0
  64. package/src/stacks/backends/springboot/create-files.js +91 -0
  65. package/src/stacks/backends/springboot/docker.js +3 -0
  66. package/src/stacks/backends/springboot/environment.js +3 -0
  67. package/src/stacks/backends/springboot/index.js +31 -0
  68. package/src/stacks/backends/supabase/ci.js +3 -0
  69. package/src/stacks/backends/supabase/create-files.js +52 -0
  70. package/src/stacks/backends/supabase/docker.js +3 -0
  71. package/src/stacks/backends/supabase/environment.js +3 -0
  72. package/src/stacks/backends/supabase/index.js +31 -0
  73. package/src/stacks/backends/supabase/native.js +14 -0
  74. package/src/stacks/compose-files.js +241 -0
  75. package/{lib/generator.js → src/stacks/create-project.js} +78 -50
  76. package/src/stacks/frontends/README.md +4 -0
  77. package/src/stacks/frontends/nextjs/ci.js +3 -0
  78. package/src/stacks/frontends/nextjs/create-files.js +46 -0
  79. package/src/stacks/frontends/nextjs/dependencies.js +5 -0
  80. package/src/stacks/frontends/nextjs/docker.js +3 -0
  81. package/src/stacks/frontends/nextjs/environment.js +7 -0
  82. package/src/stacks/frontends/nextjs/index.js +35 -0
  83. package/src/stacks/frontends/react-native/ci.js +3 -0
  84. package/src/stacks/frontends/react-native/create-files.js +25 -0
  85. package/src/stacks/frontends/react-native/dependencies.js +5 -0
  86. package/src/stacks/frontends/react-native/docker.js +5 -0
  87. package/src/stacks/frontends/react-native/environment.js +7 -0
  88. package/src/stacks/frontends/react-native/index.js +30 -0
  89. package/src/stacks/frontends/react-vite/ci.js +3 -0
  90. package/src/stacks/frontends/react-vite/create-files.js +27 -0
  91. package/src/stacks/frontends/react-vite/dependencies.js +5 -0
  92. package/src/stacks/frontends/react-vite/docker.js +3 -0
  93. package/src/stacks/frontends/react-vite/environment.js +8 -0
  94. package/src/stacks/frontends/react-vite/index.js +32 -0
  95. package/{lib → src}/stacks/shared/contributions.js +1 -1
  96. package/src/stacks/shared/environment.js +30 -0
  97. package/src/stacks/shared/javascript-package.js +111 -0
  98. package/src/stacks/shared/testing-files.js +16 -0
  99. package/templates/docker/compose/postgres.yml +1 -1
  100. package/templates/docker/compose/springboot.yml +3 -3
  101. package/templates/docker/compose/supabase.yml +1 -1
  102. package/templates/docker/compose-prod/springboot.yml +1 -1
  103. package/lib/banner.js +0 -45
  104. package/lib/constants.js +0 -3
  105. package/lib/doctor.js +0 -45
  106. package/lib/interview.js +0 -77
  107. package/lib/laravel-scaffold.js +0 -3
  108. package/lib/scaffold.js +0 -467
  109. package/lib/stacks/index.js +0 -8
  110. /package/{playbooks/capabilities → library/development-tools}/ci/github-actions.md +0 -0
  111. /package/{playbooks/devops → library/development-tools/devops/makefile}/makefile.md +0 -0
  112. /package/{playbooks/devops → library/development-tools/devops/pr-template}/pr-template.md +0 -0
  113. /package/{playbooks/capabilities/docker/docker.manifest.json → library/development-tools/docker/definition.json} +0 -0
  114. /package/{playbooks/capabilities → library/development-tools}/docker/overview.md +0 -0
  115. /package/{playbooks/capabilities → library/features}/auth/oidc-resource-server.md +0 -0
  116. /package/{playbooks/capabilities → library/features}/auth/spring-session.md +0 -0
  117. /package/{playbooks/capabilities/flyway/flyway.manifest.json → library/features/flyway/definition.json} +0 -0
  118. /package/{playbooks/capabilities → library/features}/flyway/environments.md +0 -0
  119. /package/{playbooks/capabilities → library/features}/flyway/migrations.md +0 -0
  120. /package/{playbooks/capabilities → library/features}/flyway/testing.md +0 -0
  121. /package/{playbooks/capabilities → library/features}/laravel/database.md +0 -0
  122. /package/{playbooks/capabilities → library/features}/laravel/migrations.md +0 -0
  123. /package/{playbooks/capabilities → library/features}/laravel/observability.md +0 -0
  124. /package/{playbooks/capabilities → library/features}/laravel/oidc-resource-server.md +0 -0
  125. /package/{playbooks/capabilities → library/features}/laravel/queues.md +0 -0
  126. /package/{playbooks/capabilities → library/features}/laravel/sanctum-spa.md +0 -0
  127. /package/{playbooks/capabilities → library/features}/laravel/scheduler.md +0 -0
  128. /package/{playbooks/capabilities → library/features}/laravel/session-auth.md +0 -0
  129. /package/{playbooks/capabilities → library/features}/laravel/storage-uploads.md +0 -0
  130. /package/{playbooks/capabilities → library/features}/postgresql/architecture.md +0 -0
  131. /package/{playbooks/capabilities/postgresql/postgresql.manifest.json → library/features/postgresql/definition.json} +0 -0
  132. /package/{playbooks/capabilities → library/features}/postgresql/migrations.md +0 -0
  133. /package/{playbooks/capabilities → library/features}/postgresql/schema-design.md +0 -0
  134. /package/{playbooks/capabilities → library/features}/postgresql/security.md +0 -0
  135. /package/{playbooks/capabilities → library/features}/postgresql/testing.md +0 -0
  136. /package/{playbooks/capabilities → library/features}/prisma/architecture.md +0 -0
  137. /package/{playbooks/capabilities/prisma/prisma.manifest.json → library/features/prisma/definition.json} +0 -0
  138. /package/{playbooks/capabilities → library/features}/prisma/migrations.md +0 -0
  139. /package/{playbooks/capabilities → library/features}/prisma/runtime.md +0 -0
  140. /package/{playbooks/capabilities → library/features}/prisma/schema.md +0 -0
  141. /package/{playbooks/capabilities → library/features}/prisma/testing.md +0 -0
  142. /package/{playbooks/capabilities → library/features}/supabase/architecture.md +0 -0
  143. /package/{playbooks/capabilities → library/features}/supabase/authentication.md +0 -0
  144. /package/{playbooks/capabilities/supabase/supabase.manifest.json → library/features/supabase/definition.json} +0 -0
  145. /package/{playbooks/capabilities → library/features}/supabase/expo.md +0 -0
  146. /package/{playbooks/capabilities → library/features}/supabase/migrations.md +0 -0
  147. /package/{playbooks/capabilities → library/features}/supabase/nextjs.md +0 -0
  148. /package/{playbooks/capabilities → library/features}/supabase/rls.md +0 -0
  149. /package/{playbooks/capabilities → library/features}/supabase/testing.md +0 -0
  150. /package/{playbooks/capabilities → library/features}/supabase/vite.md +0 -0
  151. /package/{playbooks → library/optional-features}/concerns/axios.md +0 -0
  152. /package/{playbooks → library/optional-features}/concerns/next-safe-action.md +0 -0
  153. /package/{playbooks → library/optional-features}/concerns/next-themes.md +0 -0
  154. /package/{playbooks → library/optional-features}/concerns/nuqs.md +0 -0
  155. /package/{playbooks → library/optional-features}/concerns/t3-env.md +0 -0
  156. /package/{playbooks → library/optional-features}/concerns/tanstack-query.md +0 -0
  157. /package/{playbooks → library/optional-features}/concerns/zod.md +0 -0
  158. /package/{playbooks → library/optional-features}/concerns/zustand.md +0 -0
  159. /package/{playbooks/styling → library/optional-features/styling/css-modules}/css-modules-extensions.md +0 -0
  160. /package/{playbooks/styling/css-modules.manifest.json → library/optional-features/styling/css-modules/definition.json} +0 -0
  161. /package/{playbooks/styling/native-styles.manifest.json → library/optional-features/styling/native-styles/definition.json} +0 -0
  162. /package/{playbooks/styling → library/optional-features/styling/native-styles}/native-styles.md +0 -0
  163. /package/{playbooks/styling/tailwind.manifest.json → library/optional-features/styling/tailwind/definition.json} +0 -0
  164. /package/{playbooks/styling → library/optional-features/styling/tailwind}/tailwind-extensions.md +0 -0
  165. /package/{playbooks/platform → library/platforms}/laravel-ui/blade/architecture.md +0 -0
  166. /package/{playbooks/platform → library/platforms}/laravel-ui/blade/runtime.md +0 -0
  167. /package/{playbooks/platform → library/platforms}/laravel-ui/blade/security.md +0 -0
  168. /package/{playbooks/platform → library/platforms}/laravel-ui/blade/structure.md +0 -0
  169. /package/{playbooks/platform → library/platforms}/laravel-ui/blade/testing.md +0 -0
  170. /package/{playbooks/stack/laravel-ui.manifest.json → library/platforms/laravel-ui/definition.json} +0 -0
  171. /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/architecture.md +0 -0
  172. /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/runtime.md +0 -0
  173. /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/security.md +0 -0
  174. /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/structure.md +0 -0
  175. /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/testing.md +0 -0
  176. /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/architecture.md +0 -0
  177. /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/runtime.md +0 -0
  178. /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/security.md +0 -0
  179. /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/structure.md +0 -0
  180. /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/testing.md +0 -0
  181. /package/{playbooks/platform → library/platforms/mobile}/mobile.md +0 -0
  182. /package/{playbooks/platform → library/platforms/web}/web.md +0 -0
  183. /package/{playbooks/stack → library/stacks}/expo/architecture.md +0 -0
  184. /package/{playbooks/stack/react-native.manifest.json → library/stacks/expo/definition.json} +0 -0
  185. /package/{playbooks/stack → library/stacks}/expo/runtime.md +0 -0
  186. /package/{playbooks/stack → library/stacks}/expo/security.md +0 -0
  187. /package/{playbooks/stack → library/stacks}/expo/structure.md +0 -0
  188. /package/{playbooks/stack → library/stacks}/expo/testing.md +0 -0
  189. /package/{playbooks/stack → library/stacks}/laravel/architecture.md +0 -0
  190. /package/{playbooks/stack/laravel.manifest.json → library/stacks/laravel/definition.json} +0 -0
  191. /package/{playbooks/stack → library/stacks}/laravel/runtime.md +0 -0
  192. /package/{playbooks/stack → library/stacks}/laravel/security.md +0 -0
  193. /package/{playbooks/stack → library/stacks}/laravel/structure.md +0 -0
  194. /package/{playbooks/stack → library/stacks}/laravel/testing.md +0 -0
  195. /package/{playbooks/stack → library/stacks}/nextjs/architecture.md +0 -0
  196. /package/{playbooks/stack/nextjs.manifest.json → library/stacks/nextjs/definition.json} +0 -0
  197. /package/{playbooks/stack → library/stacks}/nextjs/runtime.md +0 -0
  198. /package/{playbooks/stack → library/stacks}/nextjs/security.md +0 -0
  199. /package/{playbooks/stack → library/stacks}/nextjs/structure.md +0 -0
  200. /package/{playbooks/stack → library/stacks}/nextjs/testing.md +0 -0
  201. /package/{playbooks/stack/no-frontend.manifest.json → library/stacks/no-frontend/definition.json} +0 -0
  202. /package/{playbooks/stack/none.manifest.json → library/stacks/none/definition.json} +0 -0
  203. /package/{playbooks/stack → library/stacks}/react-vite/architecture.md +0 -0
  204. /package/{playbooks/stack/react-vite.manifest.json → library/stacks/react-vite/definition.json} +0 -0
  205. /package/{playbooks/stack → library/stacks}/react-vite/runtime.md +0 -0
  206. /package/{playbooks/stack → library/stacks}/react-vite/security.md +0 -0
  207. /package/{playbooks/stack → library/stacks}/react-vite/structure.md +0 -0
  208. /package/{playbooks/stack → library/stacks}/react-vite/testing.md +0 -0
  209. /package/{playbooks/stack → library/stacks}/springboot/architecture.md +0 -0
  210. /package/{playbooks/stack/springboot.manifest.json → library/stacks/springboot/definition.json} +0 -0
  211. /package/{playbooks/stack → library/stacks}/springboot/runtime.md +0 -0
  212. /package/{playbooks/stack → library/stacks}/springboot/security.md +0 -0
  213. /package/{playbooks/stack → library/stacks}/springboot/structure.md +0 -0
  214. /package/{playbooks/stack → library/stacks}/springboot/testing.md +0 -0
  215. /package/{playbooks/universal → library/universal/accessibility}/accessibility.md +0 -0
  216. /package/{playbooks/universal → library/universal/coding-rules}/coding-rules.md +0 -0
  217. /package/{playbooks/universal → library/universal/error-handling}/error-handling.md +0 -0
  218. /package/{playbooks/universal → library/universal/git-conventions}/git-conventions.md +0 -0
  219. /package/{playbooks/universal → library/universal/observability}/observability.md +0 -0
  220. /package/{playbooks/universal → library/universal/security}/security.md +0 -0
  221. /package/{playbooks/universal → library/universal/typescript}/typescript.md +0 -0
  222. /package/{lib/files.js → src/engine/project-files.js} +0 -0
  223. /package/{lib → src/engine}/project-location.js +0 -0
  224. /package/{lib/application-shapes.js → src/engine/project-shapes.js} +0 -0
  225. /package/{lib/compatibility.js → src/engine/tested-versions.js} +0 -0
  226. /package/{lib → src}/stacks/context.js +0 -0
  227. /package/{lib/stacks/contract.js → src/stacks/rules.js} +0 -0
  228. /package/{ci → templates/ci}/expo.yml +0 -0
  229. /package/{ci → templates/ci}/laravel.yml +0 -0
  230. /package/{ci → templates/ci}/nextjs.yml +0 -0
  231. /package/{ci → templates/ci}/springboot.yml +0 -0
  232. /package/{ci → templates/ci}/vite.yml +0 -0
package/README.md CHANGED
@@ -1,15 +1,8 @@
1
- ```
2
- ██╗ ██╗ ██╗ ███╗ ██╗
3
- ██║ ██║ ███║ ████╗ ██║
4
- ██║ █╗ ██║ ╚██║ ██╔██╗██║
5
- ██║███╗██║ ██║ ██║╚████║
6
- ╚███╔███╔╝ ██║ ██║ ╚███║
7
- ╚══╝╚══╝ ╚═╝ ╚═╝ ╚══╝
8
-
9
- █▀█ █▀█ █▀█ █ █▀▀ █▀▀ ▀█▀
10
- █▀▀ █▀█ █ █ █ █▀ █ █
11
- █ █ █ █▄█ █▄█ █▄▄ █▄▄ █
12
- ```
1
+ <div align="center">
2
+ <img src="./public/logo.svg" alt="W1N Project logo" width="160">
3
+ <h1>W1N PROJECT</h1>
4
+ <p>Production-ready project scaffolding.</p>
5
+ </div>
13
6
 
14
7
  # Are you confused creating architecture rules, AGENTS.md, and folder structures from scratch every time you pick a new stack?
15
8
 
@@ -19,7 +12,7 @@ Stop bikeshedding folders for 3 days. Stop pasting a 500-line `AGENTS.md` that b
19
12
 
20
13
  [![CI](https://github.com/itsw1n/create-win-project/actions/workflows/ci.yml/badge.svg)](https://github.com/itsw1n/create-win-project/actions/workflows/ci.yml)
21
14
  [![Node](https://img.shields.io/badge/node-24_LTS-green)](https://nodejs.org)
22
- [![Manifest-driven](https://img.shields.io/badge/architecture-manifest--driven-blue)](./playbooks)
15
+ [![Definition-driven](https://img.shields.io/badge/architecture-definition--driven-blue)](./library)
23
16
  [![Lean docs](https://img.shields.io/badge/AGENTS.md-lean%20%26%20lazy-9cf)](./playbooks)
24
17
  [![Interactive](https://img.shields.io/badge/cli-interactive-ff69b4)](./index.js)
25
18
 
@@ -43,14 +36,14 @@ Manifests declare capabilities and package names. A tested compatibility profile
43
36
  ### Lane 1 — To run *this generator*
44
37
  **Node 24 LTS *OR* Docker — that's it.**
45
38
 
46
- - No global `prettier`, `eslint`, or `typescript` — they are generated inside your project (`package.json` devDeps + `.prettierrc` + `.editorconfig` + `eslint.config` via `lib/scaffold.js`).
39
+ - No global `prettier`, `eslint`, or `typescript` — each stack generates them inside your project through its own dependency and file contributions.
47
40
  - Prefer zero host setup? Use Docker directly. Make is an optional convenience, never a prerequisite.
48
41
 
49
42
  ### Lane 2 — To run *what it generates* (depends on your answers)
50
43
  | You picked | You need | What the generator includes |
51
44
  |---|---|---|
52
- | **Next.js** or **React + Vite** | Node 24 LTS → `npm install` → `npm run dev` | Page/entry, Vite/Next config, strict TS, ESLint, tests, `frontend/.env.example` |
53
- | **Expo** | Node 24 LTS + Expo Go app → `npm install` → `npx expo start` | Expo Router layout/screen, `app.json`, Jest, TS |
45
+ | **Next.js** or **React + Vite** | Node 22.14+ with npm 11.19+ (tested on Node 24) → `npm install` → `npm run dev` | Page/entry, Vite/Next config, strict TS, ESLint, tests, `frontend/.env.example` |
46
+ | **Expo** | Node 22.14+ with npm 11.19+ (tested on Node 24) + Expo Go app → `npm install` → `npx expo start` | Expo Router layout/screen, `app.json`, Jest, TS |
54
47
  | **Supabase** | Docker for the generated local Supabase stack | Pinned local CLI, migrations/RLS tests, platform-native clients; login/callback/secure lifecycle only when login is selected |
55
48
  | **Spring Boot / PostgreSQL** | JDK 21 + Docker for DB **only if you selected them** | Maven app, public health + fail-closed security, Flyway/PostgreSQL; server session or OIDC Resource Server when login is selected |
56
49
 
@@ -112,6 +105,8 @@ npm run dev
112
105
 
113
106
  The generator asks whether to install dependencies. One local `npm install` provides Prettier, ESLint, TypeScript, and the selected test tools; global installs are neither required nor silently performed.
114
107
 
108
+ Before automatic installation, the CLI checks the current Node, npm, PHP, and Composer versions needed by the selected stack. A mismatch never changes global tools: interactive users can create files without installing, view setup instructions, or cancel; noninteractive runs safely create files and skip installation. Node 22 is supported with npm 11.19 or newer. npm 10.9.8 and early npm 11 releases can crash while resolving current generated dependencies, so switch through Mise/NVM or update that managed Node installation before retrying.
109
+
115
110
  > The generator **never overwrites a non-empty folder** — it stages to a temp dir and moves into place only on success.
116
111
 
117
112
  ## Features
@@ -122,11 +117,11 @@ The generator asks whether to install dependencies. One local `npm install` prov
122
117
  - **Lean agent docs** — `AGENTS.md` (tiny, always on) + `RULES.md` (lazy index) generated per project.
123
118
  - **Stack-native profiles** — Small, Medium (recommended/default), and Large map to familiar architecture for each selected stack; Large defaults to a modular monolith, not microservices.
124
119
  - **Intent-based authentication** — choose Yes, Not yet, or No; the generator maps that intent to Supabase Auth, Spring server sessions, or external-provider OIDC validation as appropriate.
125
- - **Manifest-driven** — `*.manifest.json` drives compatibility, exact dependency requests, env prefixes (`NEXT_PUBLIC_`/`VITE_`/`EXPO_PUBLIC_`), conditional playbooks, and concern wiring.
120
+ - **Definition-driven** — `library/**/definition.json` drives compatibility, exact dependency requests, env prefixes (`NEXT_PUBLIC_`/`VITE_`/`EXPO_PUBLIC_`), conditional playbooks, and concern wiring.
126
121
  - **Tested compatibility profiles** — exact direct dependencies and runtime/container versions are resolved from one catalog; current and previous profiles are verified in CI.
127
122
  - **Optional concerns, never mandated** — validation/Zod, data-fetching, state, t3-env, URL state are advisory (`CONTEXT.md` only) not forced.
128
123
  - **Runnable foundations** — profile-specific feature slices, health endpoints, security headers, selected auth plumbing, Spring `ProblemDetail`, PostgreSQL Testcontainers, and risk-based tests.
129
- - **Safety + contracts** — destination-exists guard, manifest ↔ heading checks, and a generated-output matrix covering every pairing, architecture profile, and applicable auth model.
124
+ - **Safety + contracts** — destination-exists guard, definition ↔ heading checks, and a generated-output matrix covering every pairing, architecture profile, and applicable auth model.
130
125
 
131
126
  ## What you get
132
127
 
@@ -136,7 +131,7 @@ The generator asks whether to install dependencies. One local `npm install` prov
136
131
  | `RULES.md` | Lazy index — `concern → playbook §`. Read only what you touch. |
137
132
  | `CONTEXT.md` | Project context + any advisory "expected concerns". |
138
133
  | `playbooks/` | Curated rule playbooks (shipped lean). |
139
- | `package.json` | Generated from the selected stack's manifest. |
134
+ | `package.json` | Generated from the selected stack's definition. |
140
135
  | `create-win-project.profile.json` | Separately records compatibility, architecture, and authentication selections. |
141
136
  | `.env.example` | Generated from the stack's declared env vars (prefixes already applied). |
142
137
  | Framework source/config | A working page or screen, health endpoint where applicable, strict TypeScript, lint, tests, and build scripts. |
@@ -144,10 +139,10 @@ The generator asks whether to install dependencies. One local `npm install` prov
144
139
 
145
140
  ## How it works
146
141
 
147
- The generator never hardcodes the folder or playbook list. It loads `playbooks/**/*.manifest.json` and resolves a *stack*:
142
+ The generator never hardcodes the folder or playbook list. It loads `library/**/definition.json` and resolves a *stack*:
148
143
 
149
144
  ```jsonc
150
- // playbooks/stack/nextjs.manifest.json (excerpt)
145
+ // library/stacks/nextjs/definition.json (excerpt)
151
146
  {
152
147
  "id": "nextjs",
153
148
  "kind": "frontend",
@@ -168,19 +163,15 @@ The generator never hardcodes the folder or playbook list. It loads `playbooks/*
168
163
  }
169
164
  ```
170
165
 
171
- Versions are resolved from `compatibility/profiles.json`; manifests never own them. The current tested profile is the default, while `--profile=YYYY.MM` selects a retained profile explicitly. Add a policy-only concern with a manifest + playbook. A new executable stack also needs a focused `lib/scaffold.js` implementation and a contract test — this prevents docs from advertising code that doesn't exist.
166
+ Versions are resolved from `library/tested-versions.json`; definitions never own them. The current tested profile is the default, while `--profile=YYYY.MM` selects a retained profile explicitly. Add a policy-only concern with a definition + guidance file. A new executable stack also needs a focused stack implementation and a contract test — this prevents docs from advertising code that doesn't exist.
172
167
 
173
168
  ## Topics
174
169
 
175
- Next.js · React · Spring Boot · Supabase · PostgreSQL · TypeScript · Tailwind CSS · CSS Modules · project scaffolding · project template · `AGENTS.md` · coding agents · manifest-driven · lean documentation · lazy rules index
170
+ Next.js · React · Spring Boot · Supabase · PostgreSQL · TypeScript · Tailwind CSS · CSS Modules · project scaffolding · project template · `AGENTS.md` · coding agents · definition-driven · lean documentation · lazy rules index
176
171
 
177
172
  ## Contributing
178
173
 
179
- 1. Fork and create a feature branch.
180
- 2. `npm install` and `npm test` must stay green.
181
- 3. Add or update a `*.manifest.json` for new stacks/concerns; put package versions only in `compatibility/profiles.json`.
182
- 4. Run `npm run verify:generated -- --profile=2026.09 --case=nextjs-supabase --architecture=medium --authentication=yes` for a focused executable check. CI runs every supported combination, architecture/auth model, and retained profile.
183
- 5. Document migration work for major upgrades, then open a pull request.
174
+ See [docs/CONTRIBUTING.md](./docs/CONTRIBUTING.md) one workflow for every stack: quick start, 6-step vertical stack addition (`library/**` -> `src/stacks/<id>/` -> `available-stacks.js` -> tests/matrix -> verify), testing gates (`npm test`, `matrix:smoke` -> `dev`, `matrix:full` -> `main`), and version ownership (`library/tested-versions.json` only).
184
175
 
185
176
  ## License
186
177
 
@@ -1,8 +1,10 @@
1
1
  import fs from 'fs-extra'
2
2
 
3
- const catalog = await fs.readJson(new URL('../compatibility/profiles.json', import.meta.url))
3
+ const catalog = await fs.readJson(new URL('../library/tested-versions.json', import.meta.url))
4
4
  const scope = process.argv.find((arg) => arg.startsWith('--scope='))?.split('=')[1] || 'smoke'
5
- if (!['smoke', 'full'].includes(scope)) throw new Error('--scope must be smoke or full')
5
+ const selectedStack = process.argv.find((arg) => arg.startsWith('--stack='))?.split('=')[1]
6
+ if (!['none', 'smoke', 'stack', 'full'].includes(scope)) throw new Error('--scope must be none, smoke, stack, or full')
7
+ if (scope === 'stack' && !selectedStack) throw new Error('--stack is required for stack scope')
6
8
 
7
9
  const cases = [
8
10
  'nextjs-none', 'nextjs-supabase', 'nextjs-springboot', 'nextjs-postgres', 'nextjs-laravel',
@@ -25,10 +27,11 @@ function authChoices(caseName) {
25
27
  }
26
28
 
27
29
  const current = catalog.defaultProfile
28
- const full = Object.entries(catalog.profiles).filter(([profile]) => profile === current).flatMap(([profile, versions]) =>
30
+ const allProfiles = Object.entries(catalog.profiles).flatMap(([profile, versions]) =>
29
31
  cases.flatMap((caseName) => ['small', 'medium', 'large'].flatMap((architecture) =>
30
32
  authChoices(caseName).map((auth) => ({ profile, case: caseName, architecture, ...auth, node: versions.runtimes.node, java: versions.runtimes.java, php: versions.runtimes.php })))),
31
33
  )
34
+ const currentFull = allProfiles.filter((entry) => entry.profile === current)
32
35
 
33
36
  const smokeSelections = [
34
37
  ['nextjs-none', 'small', 'not-yet', 'website'],
@@ -42,7 +45,22 @@ const smokeSelections = [
42
45
  ['laravel-inertia-react', 'large', 'yes', 'website'],
43
46
  ['react-laravel', 'medium', 'yes', 'website'],
44
47
  ]
45
- const smoke = full.filter((entry) => entry.profile === current && smokeSelections.some(([caseName, architecture, authentication, audience]) =>
46
- entry.case === caseName && entry.architecture === architecture && entry.authentication === authentication && entry.audience === audience))
48
+ const matchesSmoke = (entry) => smokeSelections.some(([caseName, architecture, authentication, audience]) =>
49
+ entry.case === caseName && entry.architecture === architecture && entry.authentication === authentication && entry.audience === audience)
50
+ const smoke = currentFull.filter(matchesSmoke)
51
+ // A complete run exhaustively verifies the current profile and keeps every
52
+ // retained profile alive through the same representative compatibility lanes.
53
+ const full = [...currentFull, ...allProfiles.filter((entry) => entry.profile !== current && matchesSmoke(entry))]
47
54
 
48
- process.stdout.write(JSON.stringify(scope === 'full' ? full : smoke))
55
+ function belongsToStack(caseName, stackName) {
56
+ if (stackName === 'none') return caseName.endsWith('-none')
57
+ if (stackName === 'react') return caseName.startsWith('react-')
58
+ if (stackName === 'react-native') return caseName.startsWith('react-native-')
59
+ if (['nextjs'].includes(stackName)) return caseName.startsWith(`${stackName}-`)
60
+ return caseName.includes(stackName)
61
+ }
62
+
63
+ const stackCases = full.filter((entry) => belongsToStack(entry.case, selectedStack))
64
+ const stack = [...new Map([...stackCases, ...smoke].map((entry) => [JSON.stringify(entry), entry])).values()]
65
+ const selected = scope === 'full' ? full : scope === 'stack' ? stack : smoke
66
+ process.stdout.write(JSON.stringify(selected.map((entry, index) => ({ ...entry, shard: `${index % 4 + 1}/4` }))))
@@ -3,7 +3,7 @@ import os from 'node:os'
3
3
  import path from 'node:path'
4
4
  import { spawnSync } from 'node:child_process'
5
5
  import { fileURLToPath } from 'node:url'
6
- import { generateProject } from '../lib/generator.js'
6
+ import { generateProject } from '../src/engine/create-project.js'
7
7
 
8
8
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
9
9
  const args = Object.fromEntries(process.argv.slice(2).map((arg) => {
@@ -32,7 +32,7 @@ const cases = {
32
32
  }
33
33
 
34
34
  if (!args.profile || !cases[args.case]) {
35
- throw new Error(`Usage: node scripts/verify-generated.mjs --profile=<id> --case=<${Object.keys(cases).join('|')}> [--architecture=small|medium|large] [--authentication=yes|not-yet|none] [--auth-audience=website|multi-client]`)
35
+ throw new Error(`Usage: npm run verify:generated -- --profile=<id> --case=<${Object.keys(cases).join('|')}> [--architecture=small|medium|large] [--authentication=yes|not-yet|none] [--auth-audience=website|multi-client]`)
36
36
  }
37
37
 
38
38
  const architecture = args.architecture || 'medium'
@@ -1,18 +1,18 @@
1
1
  import fs from 'fs-extra'
2
2
  import path from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
- import { loadCatalog, resolveStack } from '../lib/catalog.js'
5
- import { buildRulesIndex } from '../lib/playbooks.js'
4
+ import { loadCatalog, resolveStack } from '../src/engine/load-library.js'
5
+ import { buildRulesIndex, resolvePlaybook } from '../src/engine/project-guidance.js'
6
6
 
7
7
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
8
- const playbooksDir = path.join(root, 'playbooks')
8
+ const playbooksDir = path.join(root, 'library')
9
9
  const catalog = await loadCatalog(playbooksDir)
10
10
  const errors = []
11
11
 
12
12
  for (const manifest of catalog.manifests) {
13
13
  for (const entry of manifest._playbooks || []) {
14
14
  const relative = typeof entry === 'string' ? entry : entry.file
15
- if (!await fs.pathExists(path.join(playbooksDir, relative))) {
15
+ if (!await fs.pathExists(await resolvePlaybook(playbooksDir, relative))) {
16
16
  errors.push(`${manifest.id}: missing playbook ${relative}`)
17
17
  }
18
18
  }
@@ -48,7 +48,7 @@ const markdownFiles = (await fs.readdir(playbooksDir, { recursive: true, withFil
48
48
  for (const file of markdownFiles) {
49
49
  const content = await fs.readFile(file, 'utf8')
50
50
  const relative = path.relative(playbooksDir, file)
51
- const limit = relative.startsWith('stack/') || relative.startsWith('platform/') || relative.startsWith('capabilities/') ? 250 : 650
51
+ const limit = relative.startsWith('stacks/') || relative.startsWith('platforms/') || relative.startsWith('features/') ? 250 : 650
52
52
  if (content.split('\n').length > limit) errors.push(`${relative}: exceeds ${limit} lines`)
53
53
  for (const match of content.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
54
54
  const target = match[1].split('#')[0]
@@ -0,0 +1,39 @@
1
+ import { pathToFileURL } from 'node:url'
2
+
3
+ const DOCUMENTATION = /^(?:README\.md|LICENSE|docs\/|\.github\/ISSUE_TEMPLATE\/|\.github\/PULL_REQUEST_TEMPLATE)/
4
+ const FULL_IMPACT = /^(?:library\/tested-versions\.json|lib\/(?:generator|scaffold|catalog|compatibility|template)\.js|src\/engine\/|src\/stacks\/shared\/|templates\/(?:docker|gitignore|makefile)\/|checks\/(?:check-compatibility|check-generated-project|classify-changes)\.js|\.github\/workflows\/(?:compatibility|publish)\.yml)/
5
+
6
+ const STACK_PATHS = [
7
+ ['nextjs', /^(?:src\/stacks\/frontends\/nextjs\/|library\/stacks\/nextjs\/|templates\/(?:agents|ci)\/nextjs\.)/],
8
+ ['react', /^(?:src\/stacks\/frontends\/react-vite\/|library\/stacks\/react-vite\/|templates\/(?:agents|ci)\/(?:react-vite|vite)\.)/],
9
+ ['react-native', /^(?:src\/stacks\/frontends\/react-native\/|library\/stacks\/expo\/|templates\/(?:agents|ci)\/(?:react-native|expo)\.)/],
10
+ ['springboot', /^(?:src\/stacks\/backends\/springboot\/|library\/(?:stacks\/springboot|features\/(?:flyway|postgresql))\/|templates\/ci\/springboot\.)/],
11
+ ['laravel', /^(?:src\/stacks\/backends\/laravel\/|library\/(?:stacks\/laravel|platforms\/laravel-ui|features\/laravel)\/|templates\/ci\/laravel\.)/],
12
+ ['supabase', /^(?:src\/stacks\/backends\/supabase\/|library\/features\/supabase\/)/],
13
+ ['postgres', /^(?:src\/stacks\/backends\/postgres\/|library\/features\/(?:postgresql|prisma)\/)/],
14
+ ['none', /^src\/stacks\/backends\/none\//],
15
+ ]
16
+
17
+ export function classifyChanges(files) {
18
+ const changed = [...new Set(files.map((file) => file.trim()).filter(Boolean))]
19
+ if (!changed.length || changed.every((file) => DOCUMENTATION.test(file))) return { scope: 'none' }
20
+ if (changed.some((file) => FULL_IMPACT.test(file))) return { scope: 'full' }
21
+
22
+ const stacks = new Set()
23
+ let hasOrdinaryChange = false
24
+ for (const file of changed) {
25
+ const matches = STACK_PATHS.filter(([, pattern]) => pattern.test(file)).map(([stack]) => stack)
26
+ if (matches.length) matches.forEach((stack) => stacks.add(stack))
27
+ else if (!DOCUMENTATION.test(file)) hasOrdinaryChange = true
28
+ }
29
+ if (!hasOrdinaryChange && stacks.size === 1) return { scope: 'stack', stack: [...stacks][0] }
30
+ return { scope: 'smoke' }
31
+ }
32
+
33
+ async function main() {
34
+ let input = ''
35
+ for await (const chunk of process.stdin) input += chunk
36
+ process.stdout.write(JSON.stringify(classifyChanges(input.split(/\r?\n/))))
37
+ }
38
+
39
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) await main()
@@ -1,4 +1,4 @@
1
- # Architecture
1
+ # Architecture (completed — v1.4.0 target)
2
2
 
3
3
  `create-win-project` composes a validated project specification into two coordinated outputs:
4
4
 
@@ -14,40 +14,79 @@ CLI interview
14
14
 
15
15
  validated answers
16
16
 
17
- manifest catalog + compatibility resolver
17
+ available-stacks + resolve-project + load-library + tested-versions
18
18
 
19
19
  resolved stack descriptor
20
- ├── runnable framework files
21
- ├── optional CI / Docker / Makefile files
20
+ ├── runnable framework files (from src/stacks/*/create-files.js)
21
+ ├── optional CI / Docker / Makefile files (from templates/)
22
22
  ├── project context and documentation
23
23
  └── selected playbooks + RULES.md router
24
24
 
25
25
  generated-project contract tests
26
26
  ```
27
27
 
28
- ### CLI boundary
28
+ ### Source ownership (completed)
29
29
 
30
- `index.js` owns interaction and presentation. It gathers project identity, frontend, optional backend, styling, one Small/Medium/Large architecture profile, login intent, client audience when relevant, testing depth, and optional operational tooling. Medium is shown first and is the default. It does not contain stack dependency tables.
30
+ Three explicit source boundaries. No `lib/` directory exists `src/` is canonical.
31
31
 
32
- `generateProject()` validates the same answers again because it is also an exported programmatic API. A caller cannot bypass destination-name, Java-package, or testing-profile validation by skipping the CLI.
32
+ - `src/cli` owns terminal arguments, questions and navigation, display, warnings, summaries, and system checks. It may call the engine and read stack descriptions. It must not contain stack dependency tables or `if (stack === "nextjs")` branches.
33
+ - `src/engine` owns validated project orchestration, tested-version and library loading, safe writes, dependency installation, and template rendering. It must not import terminal code or concrete stack folders. It contains zero `stack.frontendKey` branches — it is stack-agnostic.
34
+ - `src/stacks` owns stack rules, the explicit available-stack list, and stack-specific generated behavior. Stack modules must not import CLI or engine implementation modules. Each `src/stacks/<frontends|backends>/<id>/` owns its files, dependencies (names only), environment names, Docker and CI contributions.
33
35
 
34
- ### Catalog and resolution
36
+ During the migration `lib/` provided compatibility shims (`export * from '../src/...'`). After v1.4.0 those shims are deleted. `tests/architecture-boundaries.test.js` enforces dependency direction, and `tests/architecture/no-lib-legacy.test.js` bans `src -> lib` imports and one-line wrapper regressions.
37
+
38
+ Root `index.js` remains the stable executable entry point. Generated-project paths such as `playbooks/`, `RULES.md`, and application folders are user-facing and do not change merely because generator source files move.
39
+
40
+ ### CLI boundary
41
+
42
+ Root `index.js` is only the stable executable shim. `src/cli/main.js` coordinates the command, `arguments.js` parses and validates flags, `questions.js` defines the interview, `navigation.js` owns Back behavior, `display.js` owns terminal presentation (`w1nBanner` + `projectLocationNotice`), and `system-check.js` detects runtime support and `collectDiagnostics/printDoctor`. The CLI gathers project identity, frontend, optional backend, styling, one Small/Medium/Large architecture profile, login intent, client audience when relevant, testing depth, and optional operational tooling. Medium is shown first and is the default. CLI modules do not contain stack dependency tables.
35
43
 
36
- `lib/catalog.js` loads co-located `*.manifest.json` files and merges selected capabilities into one stack descriptor. `lib/compatibility.js` validates `compatibility/profiles.json` and resolves every package name to an exact version for the selected profile.
44
+ `generateProject()` in `src/engine/create-project.js` validates the same answers again because it is also an exported programmatic API. A caller cannot bypass destination-name, Java-package, or testing-profile validation by skipping the CLI.
37
45
 
38
- Stack-specific behavior crosses into core orchestration through the contract in `lib/stacks/contract.js`. Every frontend, backend, or data adapter has a stable identity, declares compatible adapters and supported application/authentication/architecture models, and is added to the explicit registry. Registration is deliberate; adapters are never discovered by scanning directories.
46
+ ### Catalog and resolution
39
47
 
40
- Adapters may contribute data in these areas:
48
+ `src/engine/load-library.js` walks `library/**/definition.json` and merges manifests into a catalog index. `src/engine/tested-versions.js` validates `library/tested-versions.json` and resolves every package name to an exact version for the selected profile. `src/engine/resolve-project.js` merges selected capabilities into one resolved stack descriptor. No versions live in definitions or scaffold code.
49
+
50
+ Stack-specific behavior crosses into core orchestration through the contract in `src/stacks/rules.js` (`defineStackAdapter`). Every frontend, backend, or data adapter has a stable identity, declares compatible adapters and supported application/authentication/architecture models, and is added to the explicit registry in `src/stacks/available-stacks.js`. Registration is deliberate and explicit — adapters are never discovered by scanning directories; adding a file does not silently activate a stack.
51
+
52
+ Adapters may contribute via `CONTRIBUTION_HOOKS`:
53
+
54
+ - `prompts` in a core-defined prompt slot;
55
+ - `authentication` models;
56
+ - `files` via `create-files.js` (`(answers, context) -> FileMap`);
57
+ - `environment` declarations (semantic names like `API_URL`);
58
+ - `install` steps;
59
+ - `docker` and `ci` fragments;
60
+ - `verification` cases.
61
+
62
+ Example:
63
+
64
+ ```js
65
+ // src/stacks/frontends/nextjs/index.js
66
+ import { defineStackAdapter } from '../../rules.js'
67
+ export const nextjsAdapter = defineStackAdapter({
68
+ id: 'nextjs', kind: 'frontend', label: 'Next.js',
69
+ compatibleWith: { backend: ['none','postgres','supabase','springboot','laravel'] },
70
+ capabilities: { applicationShapes: ['fullstack','separate'], architectureProfiles: ['small','medium','large'], authenticationModels: ['public','undecided','supabase','session','oidc','sanctum-spa','laravel-oidc'] },
71
+ contributes: {
72
+ environment: ({ backend }) => backend.id === 'none' ? [] : ['API_URL'],
73
+ install: () => [{ cwd: '.', command: 'npm', args: ['install'] }],
74
+ docker: () => [{ template: 'nextjs', developmentPath: 'Dockerfile.dev', productionPath: 'Dockerfile' }],
75
+ ci: () => [{ template: 'nextjs', path: '.github/workflows/ci-frontend.yml' }],
76
+ }
77
+ })
78
+ ```
41
79
 
42
- - questions in a core-defined prompt slot;
43
- - authentication models;
44
- - generated file descriptions;
45
- - environment declarations;
46
- - install steps;
47
- - Docker and CI fragments;
48
- - verification cases.
80
+ - **Next.js** owns route-oriented Small; feature services/actions/queries and owned repositories or remote API clients in Medium; public feature APIs and enforced boundaries in Large — all in `src/stacks/frontends/nextjs/create-files.js`.
81
+ - **React + Vite** owns thin browser features in Small, feature modules in Medium, and public feature APIs plus boundary checks in Large — in `src/stacks/frontends/react-vite/create-files.js`.
82
+ - **React Native** owns Expo shell, mobile architecture profiles, local install and CI contributions in `src/stacks/frontends/react-native/create-files.js`. It deliberately contributes no frontend Docker workflow.
83
+ - **Spring Boot** owns Maven launcher, application and security configuration, package-by-feature variants, migrations, tests, and runtime Docker/CI in `src/stacks/backends/springboot/create-files.js`.
84
+ - **Laravel** owns composer definition, application files, authentication models, and Blade/Livewire/Inertia React UI variants in `src/stacks/backends/laravel/` — `create-files.js` + `composer.js` + `architecture.js` + `auth/{session,sanctum,oidc,public}.js` + `ui/{blade,livewire,inertia-react,shared}.js`. Names `auth/` and `ui/` are kept (not `login/`/`user-interface`) for conciseness; `create-files.js` is used everywhere for consistency with `create-project.js`.
85
+ - **Supabase** owns framework-specific clients, native token lifecycle, local project config, migrations, RLS policies, and verification in `src/stacks/backends/supabase/` (`create-files.js` + `native.js`).
86
+ - **PostgreSQL + Prisma** owns schema, client initialization, migration commands, database environment, Docker contribution in `src/stacks/backends/postgres/create-files.js`.
87
+ - **no-backend** explicitly owns frontend-only compatibility and confirms no server files, install steps, Docker services, credentials, or pretend authentication are contributed.
49
88
 
50
- Core code owns prompt order, compatibility-profile resolution, atomic writes, process execution, and final composition. An adapter receives a read-only stack context and returns contributions; it cannot write arbitrary paths or install global tools. Adapter definitions do not accept dependency tables or version fields. Exact versions remain exclusively owned by `compatibility/profiles.json`.
89
+ Core code owns prompt order, compatibility-profile resolution, atomic writes, process execution, and final composition. An adapter receives a read-only stack context (`createStackContext`) and returns contributions; it cannot write arbitrary paths or install global tools. Adapter definitions do not accept dependency tables or version fields. Exact versions remain exclusively owned by `library/tested-versions.json`.
51
90
 
52
91
  Manifests declare:
53
92
 
@@ -58,30 +97,23 @@ Manifests declare:
58
97
  - constraints shown to the agent;
59
98
  - concerns and their playbook sections.
60
99
 
61
- Client environment variables are semantic in manifests (`API_URL`) and receive exactly one framework prefix during resolution (`NEXT_PUBLIC_API_URL`, `VITE_API_URL`, or `EXPO_PUBLIC_API_URL`). Public prefixes always mean the value is shipped to the client.
100
+ Client environment variables are semantic in definitions (`API_URL`) and receive exactly one framework prefix during resolution (`NEXT_PUBLIC_API_URL`, `VITE_API_URL`, or `EXPO_PUBLIC_API_URL`). Public prefixes always mean the value is shipped to the client.
62
101
 
63
- ### Runnable scaffold
102
+ ### Runnable scaffold (stack-owned vertical)
64
103
 
65
- `lib/scaffold.js` owns the minimum executable vertical slice:
66
-
67
- - Next.js: route-oriented Small; familiar feature services/actions/queries and owned repositories or remote API clients in Medium; public feature APIs and enforced boundaries in Large.
68
- - React + Vite: thin browser features in Small, feature modules in Medium, and public feature APIs plus boundary checks in Large.
69
- - Expo: screens/data in Small, feature modules in Medium, and boundaries ready for offline sync, background work, and platform adapters in Large.
70
- - Spring Boot: conventional package-by-feature in Small, explicit API/service/repository ownership in Medium, and a verified Spring Modulith modular monolith in Large.
71
-
72
- Authentication is selected during generation. Supabase emits Supabase Auth clients and login examples; website-only Spring uses a secure server-managed session; multi-client Spring emits an OIDC Resource Server and delegates issuance, refresh, and revocation to the identity provider. `Not yet` is fail-closed for Spring and never emits pretend authentication. Existing projects are never told to rerun the generator to add auth.
73
-
74
- This module intentionally generates a small working example. Domain-specific features are added after product context is known; the generator does not invent business entities.
104
+ Each `src/stacks/{frontends,backends}/<id>/create-files.js` is a pure function `(answers, stack, shared) -> FileMap` that owns its minimum executable vertical slice. `shared/` contains helpers only when at least two stacks genuinely share behavior—not forced sharing. Core composes stack adapters through their contribution hooks. This intentionally generates a small working example. Domain-specific features are added after product context is known; the generator does not invent business entities.
75
105
 
76
106
  ### Repository and operational files
77
107
 
78
- `lib/generator.js` coordinates writes and refuses to merge into a non-empty destination. It adds documentation, selected playbooks, CI, Docker, Makefile, environment examples, and repository conventions around the runnable foundation.
108
+ `src/engine/create-project.js` coordinates writes and refuses to merge into a non-empty destination. It adds documentation, selected playbooks, CI, Docker, Makefile, environment examples, and repository conventions around the runnable foundation.
109
+
110
+ Engine infrastructure is separated from generated-file decisions. `src/engine/write-files.js` validates destinations, stages writes, removes failed staging trees, and publishes completed trees atomically. `src/engine/render-templates.js` combines rendering with that safe write boundary (`writeRenderedFile` + `render`/`readTemplate`/`buildVars`). `src/engine/install-dependencies.js` is the only engine process runner and stops at the first failed package-manager step. `src/engine/tested-versions.js` and `src/engine/load-library.js` expose version resolution and library loading separately. After the migration `lib/` shims are deleted; `src/` is the sole implementation.
79
111
 
80
112
  The first `npm install` creates the lockfile. Generated CI uses `npm ci`, so the lockfile must be committed before CI is enabled. `create-win-project.profile.json` separately records the compatibility profile, architecture profile, and authentication intent/model/audience; after generation, that project owns its own upgrade lifecycle.
81
113
 
82
114
  ### Compatibility profile lifecycle
83
115
 
84
- Exactly one profile is `current` and one is `previous`. The current profile is the default. A profile owns exact npm, Spring Boot, runtime, and container versions; manifests and scaffold code may only request names or capabilities. Promotion copies the candidate into a new dated profile, marks the former current profile previous, and happens only after the generated-project matrix passes. Major changes also require migration notes. See `DEPENDENCY_MAINTENANCE.md`.
116
+ Exactly one profile is `current` and one is `previous`. The current profile is the default. A profile owns exact npm, Spring Boot, runtime, and container versions; definitions and scaffold code may only request names or capabilities. Promotion copies the candidate into a new dated profile, marks the former current profile previous, and happens only after the generated-project matrix passes. Major changes also require migration notes. See `DEPENDENCY_MAINTENANCE.md`.
85
117
 
86
118
  ## Documentation model
87
119
 
@@ -91,7 +123,8 @@ Exactly one profile is `current` and one is `previous`. The current profile is t
91
123
  | `CONTEXT.md` | Product goals, boundaries, decisions, and project-specific facts. |
92
124
  | `RULES.md` | Generated concern-to-playbook section router. |
93
125
  | `playbooks/` | Reusable standards, recipes, rationale, and stack guidance. |
94
- | `docs/` | Documentation for the generated product, not generic framework teaching. |
126
+ | `docs/` | Documentation for the generator (ARCHITECTURE, CONTRIBUTING, etc.), not generic framework teaching. |
127
+ | `docs/CONTRIBUTING.md` | How to add a stack and run checks — the workflow, not the design. |
95
128
 
96
129
  Manifest section names are checked against Markdown headings. Numbered headings are normalized for matching, and generated contract tests reject unresolved `RULES.md` entries.
97
130
 
@@ -103,16 +136,26 @@ The generator itself has three verification levels:
103
136
  2. generated-output contract tests for required files, environment naming, playbook routing, profile-specific boundaries, auth metadata/code, testing profiles, and overwrite safety;
104
137
  3. a current-and-previous matrix across every supported stack combination, all three architecture profiles, and every applicable authentication model. It installs and runs lint, typecheck, tests, builds, Expo compatibility checks/web export, Spring MVC/security/Modulith tests and Maven packaging, Compose validation, and current-profile container builds.
105
138
 
139
+ Additional architecture guards:
140
+
141
+ - `tests/architecture-boundaries.test.js` enforces `src/engine` not importing `cli`/`stacks/frontends|backends` and `src/stacks` not importing `cli`/`engine`.
142
+ - `tests/architecture/no-lib-legacy.test.js` bans `src/**` importing `lib/` and one-line wrapper regressions (`export * from '../../lib/...'`) and bans `lib/` existence after the migration.
143
+
144
+ Tests mirror the production folders: `tests/cli`, `tests/engine`, `tests/stacks/frontends`, `tests/stacks/backends`.
145
+
106
146
  Canonical Markdown code examples should progressively move into extracted fixtures so examples compile against the versions they teach.
107
147
 
108
148
  ## Extension workflow
109
149
 
110
- When adding a stack or capability:
150
+ When adding a stack or capability (see `docs/CONTRIBUTING.md` for the full checklist):
111
151
 
112
- 1. Add its manifest, all five stack facets, and any platform/capability routes.
113
- 2. Add the smallest runnable files needed in `lib/scaffold.js` or a focused scaffold module.
114
- 3. Add every supported architecture/authentication combination to the generated-output matrix.
115
- 4. Run install, lint/typecheck, tests, and production build for the new fixture.
116
- 5. Update this architecture document if ownership or the generation pipeline changed.
152
+ 1. Add its `library/**/definition.json` (names only, no versions), playbooks, and `library/tested-versions.json` entry remains version-free.
153
+ 2. Create one new `src/stacks/<frontends|backends>/<id>/` directory with `index.js` (`defineStackAdapter`), `create-files.js`, `dependencies.js`/`environment.js` where needed, and `auth/`+`ui/` subfolders for Laravel-style stacks.
154
+ 3. Register it once in `src/stacks/available-stacks.js` (explicit array no scanning).
155
+ 4. Add focused contract tests in `tests/stacks/<id>/` and add the stack's cases to `checks/check-compatibility.js`.
156
+ 5. Run `npm test`, `node checks/check-library.js`, and `npm run verify:generated -- --profile=<id> --case=<id>-<backend> --architecture=medium` for every supported arch/auth combo; run `npm run matrix:smoke` before `dev` and `matrix:full` before `main`.
157
+ 6. Update this architecture document only if ownership or the generation pipeline changed.
117
158
 
118
159
  Do not advertise a capability solely because a playbook mentions it. A generated capability must have executable configuration and contract coverage.
160
+
161
+ Adding a stack must not require editing the engine or unrelated stacks.
@@ -6,16 +6,16 @@ The project separates always-loaded instructions, task-routed standards, generat
6
6
  |---|---|---|
7
7
  | Agent commands, workflow, authority limits, definition of done | `templates/agents/*.md` → generated `AGENTS.md` | Every project; keep short |
8
8
  | Product goal, scope, decisions, unknowns | generated `CONTEXT.md` | Every project; project-specific |
9
- | Concern routing | manifests → generated `RULES.md` | Selected stack/capability only |
9
+ | Concern routing | definitions → generated `RULES.md` | Selected stack/capability only |
10
10
  | Reusable engineering policy and rationale | `playbooks/**/*.md` | A task touches that concern |
11
11
  | Setup, API, architecture, deployment for this product | generated `docs/` | Every project, then maintained with code |
12
- | Framework configuration and canonical patterns | `lib/scaffold.js` output plus tests | The capability is selected |
12
+ | Framework configuration and canonical patterns | `src/stacks/` file contributions plus tests | The capability is selected |
13
13
 
14
14
  ## Authoring rules
15
15
 
16
16
  1. Put a rule in the narrowest applicable playbook. Do not repeat it in `AGENTS.md`, `README.md`, and stack guides.
17
17
  2. Write normative language only for behavior the generator configures or tests. Label uninstalled libraries and alternative architectures as optional.
18
- 3. Route concerns to exact Markdown headings from their manifest. Heading changes and manifest changes belong in the same commit.
18
+ 3. Route concerns to exact Markdown headings from their definition. Heading changes and definition changes belong in the same commit.
19
19
  4. Prefer a compact rule, a reason, and one canonical example. Remove tutorial-length alternatives that compete with the default.
20
20
  5. Keep secrets, authentication, authorization, validation, accessibility, and failure behavior at explicit trust boundaries.
21
21
  6. Product docs describe the generated application. Playbooks teach reusable practices; they must not invent product endpoints or entities.