@cherishxn/agent-scaffold 0.0.0-stage → 1.0.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 (659) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -2
  3. package/THIRD_PARTY_NOTICES.md +14 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +100 -0
  6. package/dist/generate.d.ts +55 -0
  7. package/dist/generate.js +154 -0
  8. package/dist/model.d.ts +33 -0
  9. package/dist/model.js +24 -0
  10. package/dist/verify.d.ts +61 -0
  11. package/dist/verify.js +264 -0
  12. package/package.json +49 -4
  13. package/schemas/manifest.json +171 -0
  14. package/schemas/plan.json +164 -0
  15. package/schemas/result.json +97 -0
  16. package/schemas/spec.json +50 -0
  17. package/skills/scaffold-use/SKILL.md +6 -0
  18. package/templates/catalog.json +37 -0
  19. package/templates/next-fullstack-antd/.agents/skills/design-contract/SKILL.md +23 -0
  20. package/templates/next-fullstack-antd/.agents/skills/project-work/SKILL.md +8 -0
  21. package/templates/next-fullstack-antd/.claude/skills/design-contract/SKILL.md +23 -0
  22. package/templates/next-fullstack-antd/.claude/skills/project-work/SKILL.md +8 -0
  23. package/templates/next-fullstack-antd/.dockerignore +18 -0
  24. package/templates/next-fullstack-antd/.env.example +13 -0
  25. package/templates/next-fullstack-antd/.grok/skills/design-contract/SKILL.md +23 -0
  26. package/templates/next-fullstack-antd/.grok/skills/project-work/SKILL.md +8 -0
  27. package/templates/next-fullstack-antd/.scaffold-checks.json +7 -0
  28. package/templates/next-fullstack-antd/AGENTS.md +11 -0
  29. package/templates/next-fullstack-antd/CLAUDE.md +1 -0
  30. package/templates/next-fullstack-antd/DESIGN.md +208 -0
  31. package/templates/next-fullstack-antd/LICENSE +21 -0
  32. package/templates/next-fullstack-antd/README.md +55 -0
  33. package/templates/next-fullstack-antd/THIRD_PARTY_NOTICES.md +14 -0
  34. package/templates/next-fullstack-antd/compose.yaml +18 -0
  35. package/templates/next-fullstack-antd/design/guide.md +61 -0
  36. package/templates/next-fullstack-antd/design/layout.css +6 -0
  37. package/templates/next-fullstack-antd/design/structure.json +107 -0
  38. package/templates/next-fullstack-antd/design/tokens.json +171 -0
  39. package/templates/next-fullstack-antd/design/widgets.css +30 -0
  40. package/templates/next-fullstack-antd/design/widgets.json +233 -0
  41. package/templates/next-fullstack-antd/docs/PROJECT.md +9 -0
  42. package/templates/next-fullstack-antd/docs/api.d.ts +516 -0
  43. package/templates/next-fullstack-antd/docs/openapi.json +439 -0
  44. package/templates/next-fullstack-antd/gitignore.template +19 -0
  45. package/templates/next-fullstack-antd/licenses/fastapi.txt +21 -0
  46. package/templates/next-fullstack-antd/licenses/nest.txt +22 -0
  47. package/templates/next-fullstack-antd/licenses/next.txt +21 -0
  48. package/templates/next-fullstack-antd/licenses/shadcn.txt +21 -0
  49. package/templates/next-fullstack-antd/licenses/sources.json +27 -0
  50. package/templates/next-fullstack-antd/licenses/spring.txt +202 -0
  51. package/templates/next-fullstack-antd/package-lock.json +440 -0
  52. package/templates/next-fullstack-antd/package.json +21 -0
  53. package/templates/next-fullstack-antd/playwright.config.ts +3 -0
  54. package/templates/next-fullstack-antd/project.json +8 -0
  55. package/templates/next-fullstack-antd/scripts/design-coverage.mjs +20 -0
  56. package/templates/next-fullstack-antd/scripts/design-next-cleanup.mjs +13 -0
  57. package/templates/next-fullstack-antd/scripts/design-verify.mjs +154 -0
  58. package/templates/next-fullstack-antd/scripts/design.mjs +108 -0
  59. package/templates/next-fullstack-antd/scripts/project.mjs +118 -0
  60. package/templates/next-fullstack-antd/tests/contract.spec.ts +47 -0
  61. package/templates/next-fullstack-antd/tests/design/harness.tsx +63 -0
  62. package/templates/next-fullstack-antd/tests/ui.spec.ts +61 -0
  63. package/templates/next-fullstack-antd/web/Dockerfile +12 -0
  64. package/templates/next-fullstack-antd/web/app/api/auth/login/route.ts +1 -0
  65. package/templates/next-fullstack-antd/web/app/api/auth/logout/route.ts +1 -0
  66. package/templates/next-fullstack-antd/web/app/api/auth/me/route.ts +1 -0
  67. package/templates/next-fullstack-antd/web/app/api/health/route.ts +1 -0
  68. package/templates/next-fullstack-antd/web/app/api/records/[id]/route.ts +5 -0
  69. package/templates/next-fullstack-antd/web/app/api/records/route.ts +3 -0
  70. package/templates/next-fullstack-antd/web/app/layout.tsx +5 -0
  71. package/templates/next-fullstack-antd/web/app/page.tsx +2 -0
  72. package/templates/next-fullstack-antd/web/eslint.config.mjs +3 -0
  73. package/templates/next-fullstack-antd/web/lib/api.ts +35 -0
  74. package/templates/next-fullstack-antd/web/lib/auth.ts +10 -0
  75. package/templates/next-fullstack-antd/web/lib/db.ts +3 -0
  76. package/templates/next-fullstack-antd/web/lib/session.test.ts +15 -0
  77. package/templates/next-fullstack-antd/web/lib/validation.test.ts +3 -0
  78. package/templates/next-fullstack-antd/web/lib/validation.ts +5 -0
  79. package/templates/next-fullstack-antd/web/next-env.d.ts +7 -0
  80. package/templates/next-fullstack-antd/web/next.config.ts +3 -0
  81. package/templates/next-fullstack-antd/web/package.json +35 -0
  82. package/templates/next-fullstack-antd/web/pnpm-lock.yaml +3756 -0
  83. package/templates/next-fullstack-antd/web/pnpm-workspace.yaml +7 -0
  84. package/templates/next-fullstack-antd/web/prisma/migrations/202610190001_initial/migration.sql +99 -0
  85. package/templates/next-fullstack-antd/web/prisma/migrations/migration_lock.toml +1 -0
  86. package/templates/next-fullstack-antd/web/prisma/schema.prisma +72 -0
  87. package/templates/next-fullstack-antd/web/scripts/seed.ts +4 -0
  88. package/templates/next-fullstack-antd/web/src/App.tsx +29 -0
  89. package/templates/next-fullstack-antd/web/src/design-layout.css +7 -0
  90. package/templates/next-fullstack-antd/web/src/design-runtime.json +511 -0
  91. package/templates/next-fullstack-antd/web/src/design-tokens.css +168 -0
  92. package/templates/next-fullstack-antd/web/src/design-widgets.css +31 -0
  93. package/templates/next-fullstack-antd/web/src/structure-view.tsx +16 -0
  94. package/templates/next-fullstack-antd/web/src/styles.css +3 -0
  95. package/templates/next-fullstack-antd/web/src/ui.tsx +30 -0
  96. package/templates/next-fullstack-antd/web/src/widget-icon.tsx +5 -0
  97. package/templates/next-fullstack-antd/web/src/widget-types.ts +13 -0
  98. package/templates/next-fullstack-antd/web/src/workspace-model.ts +85 -0
  99. package/templates/next-fullstack-antd/web/tsconfig.json +42 -0
  100. package/templates/next-fullstack-antd/web/vitest.config.ts +2 -0
  101. package/templates/next-fullstack-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
  102. package/templates/next-fullstack-shadcn/.agents/skills/project-work/SKILL.md +8 -0
  103. package/templates/next-fullstack-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
  104. package/templates/next-fullstack-shadcn/.claude/skills/project-work/SKILL.md +8 -0
  105. package/templates/next-fullstack-shadcn/.dockerignore +18 -0
  106. package/templates/next-fullstack-shadcn/.env.example +13 -0
  107. package/templates/next-fullstack-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
  108. package/templates/next-fullstack-shadcn/.grok/skills/project-work/SKILL.md +8 -0
  109. package/templates/next-fullstack-shadcn/.scaffold-checks.json +7 -0
  110. package/templates/next-fullstack-shadcn/AGENTS.md +11 -0
  111. package/templates/next-fullstack-shadcn/CLAUDE.md +1 -0
  112. package/templates/next-fullstack-shadcn/DESIGN.md +208 -0
  113. package/templates/next-fullstack-shadcn/LICENSE +21 -0
  114. package/templates/next-fullstack-shadcn/README.md +55 -0
  115. package/templates/next-fullstack-shadcn/THIRD_PARTY_NOTICES.md +14 -0
  116. package/templates/next-fullstack-shadcn/compose.yaml +18 -0
  117. package/templates/next-fullstack-shadcn/design/guide.md +61 -0
  118. package/templates/next-fullstack-shadcn/design/layout.css +6 -0
  119. package/templates/next-fullstack-shadcn/design/structure.json +107 -0
  120. package/templates/next-fullstack-shadcn/design/tokens.json +171 -0
  121. package/templates/next-fullstack-shadcn/design/widgets.css +30 -0
  122. package/templates/next-fullstack-shadcn/design/widgets.json +233 -0
  123. package/templates/next-fullstack-shadcn/docs/PROJECT.md +9 -0
  124. package/templates/next-fullstack-shadcn/docs/api.d.ts +516 -0
  125. package/templates/next-fullstack-shadcn/docs/openapi.json +439 -0
  126. package/templates/next-fullstack-shadcn/gitignore.template +19 -0
  127. package/templates/next-fullstack-shadcn/licenses/fastapi.txt +21 -0
  128. package/templates/next-fullstack-shadcn/licenses/nest.txt +22 -0
  129. package/templates/next-fullstack-shadcn/licenses/next.txt +21 -0
  130. package/templates/next-fullstack-shadcn/licenses/shadcn.txt +21 -0
  131. package/templates/next-fullstack-shadcn/licenses/sources.json +27 -0
  132. package/templates/next-fullstack-shadcn/licenses/spring.txt +202 -0
  133. package/templates/next-fullstack-shadcn/package-lock.json +440 -0
  134. package/templates/next-fullstack-shadcn/package.json +21 -0
  135. package/templates/next-fullstack-shadcn/playwright.config.ts +3 -0
  136. package/templates/next-fullstack-shadcn/project.json +8 -0
  137. package/templates/next-fullstack-shadcn/scripts/design-coverage.mjs +20 -0
  138. package/templates/next-fullstack-shadcn/scripts/design-next-cleanup.mjs +13 -0
  139. package/templates/next-fullstack-shadcn/scripts/design-verify.mjs +154 -0
  140. package/templates/next-fullstack-shadcn/scripts/design.mjs +108 -0
  141. package/templates/next-fullstack-shadcn/scripts/project.mjs +118 -0
  142. package/templates/next-fullstack-shadcn/tests/contract.spec.ts +47 -0
  143. package/templates/next-fullstack-shadcn/tests/design/harness.tsx +63 -0
  144. package/templates/next-fullstack-shadcn/tests/ui.spec.ts +61 -0
  145. package/templates/next-fullstack-shadcn/web/Dockerfile +12 -0
  146. package/templates/next-fullstack-shadcn/web/app/api/auth/login/route.ts +1 -0
  147. package/templates/next-fullstack-shadcn/web/app/api/auth/logout/route.ts +1 -0
  148. package/templates/next-fullstack-shadcn/web/app/api/auth/me/route.ts +1 -0
  149. package/templates/next-fullstack-shadcn/web/app/api/health/route.ts +1 -0
  150. package/templates/next-fullstack-shadcn/web/app/api/records/[id]/route.ts +5 -0
  151. package/templates/next-fullstack-shadcn/web/app/api/records/route.ts +3 -0
  152. package/templates/next-fullstack-shadcn/web/app/layout.tsx +4 -0
  153. package/templates/next-fullstack-shadcn/web/app/page.tsx +2 -0
  154. package/templates/next-fullstack-shadcn/web/eslint.config.mjs +3 -0
  155. package/templates/next-fullstack-shadcn/web/lib/api.ts +35 -0
  156. package/templates/next-fullstack-shadcn/web/lib/auth.ts +10 -0
  157. package/templates/next-fullstack-shadcn/web/lib/db.ts +3 -0
  158. package/templates/next-fullstack-shadcn/web/lib/session.test.ts +15 -0
  159. package/templates/next-fullstack-shadcn/web/lib/validation.test.ts +3 -0
  160. package/templates/next-fullstack-shadcn/web/lib/validation.ts +5 -0
  161. package/templates/next-fullstack-shadcn/web/next-env.d.ts +7 -0
  162. package/templates/next-fullstack-shadcn/web/next.config.ts +3 -0
  163. package/templates/next-fullstack-shadcn/web/package.json +39 -0
  164. package/templates/next-fullstack-shadcn/web/pnpm-lock.yaml +3286 -0
  165. package/templates/next-fullstack-shadcn/web/pnpm-workspace.yaml +7 -0
  166. package/templates/next-fullstack-shadcn/web/postcss.config.mjs +1 -0
  167. package/templates/next-fullstack-shadcn/web/prisma/migrations/202610190001_initial/migration.sql +99 -0
  168. package/templates/next-fullstack-shadcn/web/prisma/migrations/migration_lock.toml +1 -0
  169. package/templates/next-fullstack-shadcn/web/prisma/schema.prisma +72 -0
  170. package/templates/next-fullstack-shadcn/web/scripts/seed.ts +4 -0
  171. package/templates/next-fullstack-shadcn/web/src/App.tsx +30 -0
  172. package/templates/next-fullstack-shadcn/web/src/design-layout.css +7 -0
  173. package/templates/next-fullstack-shadcn/web/src/design-runtime.json +511 -0
  174. package/templates/next-fullstack-shadcn/web/src/design-tokens.css +168 -0
  175. package/templates/next-fullstack-shadcn/web/src/design-widgets.css +31 -0
  176. package/templates/next-fullstack-shadcn/web/src/structure-view.tsx +16 -0
  177. package/templates/next-fullstack-shadcn/web/src/styles.css +3 -0
  178. package/templates/next-fullstack-shadcn/web/src/tailwind.css +2 -0
  179. package/templates/next-fullstack-shadcn/web/src/ui.tsx +13 -0
  180. package/templates/next-fullstack-shadcn/web/src/widget-icon.tsx +5 -0
  181. package/templates/next-fullstack-shadcn/web/src/widget-types.ts +13 -0
  182. package/templates/next-fullstack-shadcn/web/src/workspace-model.ts +85 -0
  183. package/templates/next-fullstack-shadcn/web/tsconfig.json +42 -0
  184. package/templates/next-fullstack-shadcn/web/vitest.config.ts +2 -0
  185. package/templates/react-fastapi-antd/.agents/skills/design-contract/SKILL.md +23 -0
  186. package/templates/react-fastapi-antd/.agents/skills/project-work/SKILL.md +8 -0
  187. package/templates/react-fastapi-antd/.claude/skills/design-contract/SKILL.md +23 -0
  188. package/templates/react-fastapi-antd/.claude/skills/project-work/SKILL.md +8 -0
  189. package/templates/react-fastapi-antd/.dockerignore +18 -0
  190. package/templates/react-fastapi-antd/.env.example +13 -0
  191. package/templates/react-fastapi-antd/.grok/skills/design-contract/SKILL.md +23 -0
  192. package/templates/react-fastapi-antd/.grok/skills/project-work/SKILL.md +8 -0
  193. package/templates/react-fastapi-antd/.scaffold-checks.json +7 -0
  194. package/templates/react-fastapi-antd/AGENTS.md +11 -0
  195. package/templates/react-fastapi-antd/CLAUDE.md +1 -0
  196. package/templates/react-fastapi-antd/DESIGN.md +208 -0
  197. package/templates/react-fastapi-antd/LICENSE +21 -0
  198. package/templates/react-fastapi-antd/README.md +55 -0
  199. package/templates/react-fastapi-antd/THIRD_PARTY_NOTICES.md +14 -0
  200. package/templates/react-fastapi-antd/backend/.python-version +1 -0
  201. package/templates/react-fastapi-antd/backend/Dockerfile +10 -0
  202. package/templates/react-fastapi-antd/backend/alembic.ini +3 -0
  203. package/templates/react-fastapi-antd/backend/app/__init__.py +0 -0
  204. package/templates/react-fastapi-antd/backend/app/core/__init__.py +0 -0
  205. package/templates/react-fastapi-antd/backend/app/core/security.py +25 -0
  206. package/templates/react-fastapi-antd/backend/app/db.py +11 -0
  207. package/templates/react-fastapi-antd/backend/app/main.py +146 -0
  208. package/templates/react-fastapi-antd/backend/app/models.py +21 -0
  209. package/templates/react-fastapi-antd/backend/app/seed.py +21 -0
  210. package/templates/react-fastapi-antd/backend/migrations/env.py +9 -0
  211. package/templates/react-fastapi-antd/backend/migrations/versions/0001_initial.py +18 -0
  212. package/templates/react-fastapi-antd/backend/pyproject.toml +16 -0
  213. package/templates/react-fastapi-antd/backend/tests/test_api.py +27 -0
  214. package/templates/react-fastapi-antd/backend/uv.lock +1085 -0
  215. package/templates/react-fastapi-antd/compose.yaml +18 -0
  216. package/templates/react-fastapi-antd/design/guide.md +61 -0
  217. package/templates/react-fastapi-antd/design/layout.css +6 -0
  218. package/templates/react-fastapi-antd/design/structure.json +107 -0
  219. package/templates/react-fastapi-antd/design/tokens.json +171 -0
  220. package/templates/react-fastapi-antd/design/widgets.css +30 -0
  221. package/templates/react-fastapi-antd/design/widgets.json +233 -0
  222. package/templates/react-fastapi-antd/docs/PROJECT.md +9 -0
  223. package/templates/react-fastapi-antd/docs/api.d.ts +516 -0
  224. package/templates/react-fastapi-antd/docs/openapi.json +439 -0
  225. package/templates/react-fastapi-antd/gitignore.template +19 -0
  226. package/templates/react-fastapi-antd/licenses/fastapi.txt +21 -0
  227. package/templates/react-fastapi-antd/licenses/nest.txt +22 -0
  228. package/templates/react-fastapi-antd/licenses/next.txt +21 -0
  229. package/templates/react-fastapi-antd/licenses/shadcn.txt +21 -0
  230. package/templates/react-fastapi-antd/licenses/sources.json +27 -0
  231. package/templates/react-fastapi-antd/licenses/spring.txt +202 -0
  232. package/templates/react-fastapi-antd/package-lock.json +440 -0
  233. package/templates/react-fastapi-antd/package.json +21 -0
  234. package/templates/react-fastapi-antd/playwright.config.ts +3 -0
  235. package/templates/react-fastapi-antd/project.json +8 -0
  236. package/templates/react-fastapi-antd/scripts/design-coverage.mjs +20 -0
  237. package/templates/react-fastapi-antd/scripts/design-next-cleanup.mjs +13 -0
  238. package/templates/react-fastapi-antd/scripts/design-verify.mjs +154 -0
  239. package/templates/react-fastapi-antd/scripts/design.mjs +108 -0
  240. package/templates/react-fastapi-antd/scripts/project.mjs +118 -0
  241. package/templates/react-fastapi-antd/tests/contract.spec.ts +47 -0
  242. package/templates/react-fastapi-antd/tests/design/harness.tsx +63 -0
  243. package/templates/react-fastapi-antd/tests/ui.spec.ts +61 -0
  244. package/templates/react-fastapi-antd/web/bun.lock +442 -0
  245. package/templates/react-fastapi-antd/web/eslint.config.mjs +3 -0
  246. package/templates/react-fastapi-antd/web/index.html +1 -0
  247. package/templates/react-fastapi-antd/web/package.json +28 -0
  248. package/templates/react-fastapi-antd/web/src/App.tsx +29 -0
  249. package/templates/react-fastapi-antd/web/src/design-layout.css +7 -0
  250. package/templates/react-fastapi-antd/web/src/design-runtime.json +511 -0
  251. package/templates/react-fastapi-antd/web/src/design-tokens.css +168 -0
  252. package/templates/react-fastapi-antd/web/src/design-widgets.css +31 -0
  253. package/templates/react-fastapi-antd/web/src/main.tsx +6 -0
  254. package/templates/react-fastapi-antd/web/src/structure-view.tsx +16 -0
  255. package/templates/react-fastapi-antd/web/src/styles.css +3 -0
  256. package/templates/react-fastapi-antd/web/src/ui.tsx +30 -0
  257. package/templates/react-fastapi-antd/web/src/widget-icon.tsx +5 -0
  258. package/templates/react-fastapi-antd/web/src/widget-types.ts +13 -0
  259. package/templates/react-fastapi-antd/web/src/workspace-model.ts +85 -0
  260. package/templates/react-fastapi-antd/web/tsconfig.json +22 -0
  261. package/templates/react-fastapi-antd/web/vite.config.ts +3 -0
  262. package/templates/react-fastapi-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
  263. package/templates/react-fastapi-shadcn/.agents/skills/project-work/SKILL.md +8 -0
  264. package/templates/react-fastapi-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
  265. package/templates/react-fastapi-shadcn/.claude/skills/project-work/SKILL.md +8 -0
  266. package/templates/react-fastapi-shadcn/.dockerignore +18 -0
  267. package/templates/react-fastapi-shadcn/.env.example +13 -0
  268. package/templates/react-fastapi-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
  269. package/templates/react-fastapi-shadcn/.grok/skills/project-work/SKILL.md +8 -0
  270. package/templates/react-fastapi-shadcn/.scaffold-checks.json +7 -0
  271. package/templates/react-fastapi-shadcn/AGENTS.md +11 -0
  272. package/templates/react-fastapi-shadcn/CLAUDE.md +1 -0
  273. package/templates/react-fastapi-shadcn/DESIGN.md +208 -0
  274. package/templates/react-fastapi-shadcn/LICENSE +21 -0
  275. package/templates/react-fastapi-shadcn/README.md +55 -0
  276. package/templates/react-fastapi-shadcn/THIRD_PARTY_NOTICES.md +14 -0
  277. package/templates/react-fastapi-shadcn/backend/.python-version +1 -0
  278. package/templates/react-fastapi-shadcn/backend/Dockerfile +10 -0
  279. package/templates/react-fastapi-shadcn/backend/alembic.ini +3 -0
  280. package/templates/react-fastapi-shadcn/backend/app/__init__.py +0 -0
  281. package/templates/react-fastapi-shadcn/backend/app/core/__init__.py +0 -0
  282. package/templates/react-fastapi-shadcn/backend/app/core/security.py +25 -0
  283. package/templates/react-fastapi-shadcn/backend/app/db.py +11 -0
  284. package/templates/react-fastapi-shadcn/backend/app/main.py +146 -0
  285. package/templates/react-fastapi-shadcn/backend/app/models.py +21 -0
  286. package/templates/react-fastapi-shadcn/backend/app/seed.py +21 -0
  287. package/templates/react-fastapi-shadcn/backend/migrations/env.py +9 -0
  288. package/templates/react-fastapi-shadcn/backend/migrations/versions/0001_initial.py +18 -0
  289. package/templates/react-fastapi-shadcn/backend/pyproject.toml +16 -0
  290. package/templates/react-fastapi-shadcn/backend/tests/test_api.py +27 -0
  291. package/templates/react-fastapi-shadcn/backend/uv.lock +1085 -0
  292. package/templates/react-fastapi-shadcn/compose.yaml +18 -0
  293. package/templates/react-fastapi-shadcn/design/guide.md +61 -0
  294. package/templates/react-fastapi-shadcn/design/layout.css +6 -0
  295. package/templates/react-fastapi-shadcn/design/structure.json +107 -0
  296. package/templates/react-fastapi-shadcn/design/tokens.json +171 -0
  297. package/templates/react-fastapi-shadcn/design/widgets.css +30 -0
  298. package/templates/react-fastapi-shadcn/design/widgets.json +233 -0
  299. package/templates/react-fastapi-shadcn/docs/PROJECT.md +9 -0
  300. package/templates/react-fastapi-shadcn/docs/api.d.ts +516 -0
  301. package/templates/react-fastapi-shadcn/docs/openapi.json +439 -0
  302. package/templates/react-fastapi-shadcn/gitignore.template +19 -0
  303. package/templates/react-fastapi-shadcn/licenses/fastapi.txt +21 -0
  304. package/templates/react-fastapi-shadcn/licenses/nest.txt +22 -0
  305. package/templates/react-fastapi-shadcn/licenses/next.txt +21 -0
  306. package/templates/react-fastapi-shadcn/licenses/shadcn.txt +21 -0
  307. package/templates/react-fastapi-shadcn/licenses/sources.json +27 -0
  308. package/templates/react-fastapi-shadcn/licenses/spring.txt +202 -0
  309. package/templates/react-fastapi-shadcn/package-lock.json +440 -0
  310. package/templates/react-fastapi-shadcn/package.json +21 -0
  311. package/templates/react-fastapi-shadcn/playwright.config.ts +3 -0
  312. package/templates/react-fastapi-shadcn/project.json +8 -0
  313. package/templates/react-fastapi-shadcn/scripts/design-coverage.mjs +20 -0
  314. package/templates/react-fastapi-shadcn/scripts/design-next-cleanup.mjs +13 -0
  315. package/templates/react-fastapi-shadcn/scripts/design-verify.mjs +154 -0
  316. package/templates/react-fastapi-shadcn/scripts/design.mjs +108 -0
  317. package/templates/react-fastapi-shadcn/scripts/project.mjs +118 -0
  318. package/templates/react-fastapi-shadcn/tests/contract.spec.ts +47 -0
  319. package/templates/react-fastapi-shadcn/tests/design/harness.tsx +63 -0
  320. package/templates/react-fastapi-shadcn/tests/ui.spec.ts +61 -0
  321. package/templates/react-fastapi-shadcn/web/bun.lock +413 -0
  322. package/templates/react-fastapi-shadcn/web/eslint.config.mjs +3 -0
  323. package/templates/react-fastapi-shadcn/web/index.html +1 -0
  324. package/templates/react-fastapi-shadcn/web/package.json +33 -0
  325. package/templates/react-fastapi-shadcn/web/src/App.tsx +30 -0
  326. package/templates/react-fastapi-shadcn/web/src/design-layout.css +7 -0
  327. package/templates/react-fastapi-shadcn/web/src/design-runtime.json +511 -0
  328. package/templates/react-fastapi-shadcn/web/src/design-tokens.css +168 -0
  329. package/templates/react-fastapi-shadcn/web/src/design-widgets.css +31 -0
  330. package/templates/react-fastapi-shadcn/web/src/main.tsx +6 -0
  331. package/templates/react-fastapi-shadcn/web/src/structure-view.tsx +16 -0
  332. package/templates/react-fastapi-shadcn/web/src/styles.css +3 -0
  333. package/templates/react-fastapi-shadcn/web/src/tailwind.css +2 -0
  334. package/templates/react-fastapi-shadcn/web/src/ui.tsx +13 -0
  335. package/templates/react-fastapi-shadcn/web/src/widget-icon.tsx +5 -0
  336. package/templates/react-fastapi-shadcn/web/src/widget-types.ts +13 -0
  337. package/templates/react-fastapi-shadcn/web/src/workspace-model.ts +85 -0
  338. package/templates/react-fastapi-shadcn/web/tsconfig.json +22 -0
  339. package/templates/react-fastapi-shadcn/web/vite.config.ts +4 -0
  340. package/templates/react-nest-antd/.agents/skills/design-contract/SKILL.md +23 -0
  341. package/templates/react-nest-antd/.agents/skills/project-work/SKILL.md +8 -0
  342. package/templates/react-nest-antd/.claude/skills/design-contract/SKILL.md +23 -0
  343. package/templates/react-nest-antd/.claude/skills/project-work/SKILL.md +8 -0
  344. package/templates/react-nest-antd/.dockerignore +18 -0
  345. package/templates/react-nest-antd/.env.example +13 -0
  346. package/templates/react-nest-antd/.grok/skills/design-contract/SKILL.md +23 -0
  347. package/templates/react-nest-antd/.grok/skills/project-work/SKILL.md +8 -0
  348. package/templates/react-nest-antd/.scaffold-checks.json +7 -0
  349. package/templates/react-nest-antd/AGENTS.md +11 -0
  350. package/templates/react-nest-antd/CLAUDE.md +1 -0
  351. package/templates/react-nest-antd/DESIGN.md +208 -0
  352. package/templates/react-nest-antd/LICENSE +21 -0
  353. package/templates/react-nest-antd/README.md +55 -0
  354. package/templates/react-nest-antd/THIRD_PARTY_NOTICES.md +14 -0
  355. package/templates/react-nest-antd/backend/Dockerfile +12 -0
  356. package/templates/react-nest-antd/backend/eslint.config.mjs +3 -0
  357. package/templates/react-nest-antd/backend/jest.config.cjs +1 -0
  358. package/templates/react-nest-antd/backend/package.json +40 -0
  359. package/templates/react-nest-antd/backend/pnpm-lock.yaml +5165 -0
  360. package/templates/react-nest-antd/backend/pnpm-workspace.yaml +6 -0
  361. package/templates/react-nest-antd/backend/prisma/migrations/202610190001_initial/migration.sql +3 -0
  362. package/templates/react-nest-antd/backend/prisma/migrations/migration_lock.toml +1 -0
  363. package/templates/react-nest-antd/backend/prisma/schema.prisma +25 -0
  364. package/templates/react-nest-antd/backend/scripts/seed.ts +4 -0
  365. package/templates/react-nest-antd/backend/src/app.module.ts +43 -0
  366. package/templates/react-nest-antd/backend/src/main.ts +6 -0
  367. package/templates/react-nest-antd/backend/src/password.ts +3 -0
  368. package/templates/react-nest-antd/backend/src/validation.ts +7 -0
  369. package/templates/react-nest-antd/backend/test/api.test.ts +25 -0
  370. package/templates/react-nest-antd/backend/tsconfig.build.json +15 -0
  371. package/templates/react-nest-antd/backend/tsconfig.json +17 -0
  372. package/templates/react-nest-antd/compose.yaml +18 -0
  373. package/templates/react-nest-antd/design/guide.md +61 -0
  374. package/templates/react-nest-antd/design/layout.css +6 -0
  375. package/templates/react-nest-antd/design/structure.json +107 -0
  376. package/templates/react-nest-antd/design/tokens.json +171 -0
  377. package/templates/react-nest-antd/design/widgets.css +30 -0
  378. package/templates/react-nest-antd/design/widgets.json +233 -0
  379. package/templates/react-nest-antd/docs/PROJECT.md +9 -0
  380. package/templates/react-nest-antd/docs/api.d.ts +516 -0
  381. package/templates/react-nest-antd/docs/openapi.json +439 -0
  382. package/templates/react-nest-antd/gitignore.template +19 -0
  383. package/templates/react-nest-antd/licenses/fastapi.txt +21 -0
  384. package/templates/react-nest-antd/licenses/nest.txt +22 -0
  385. package/templates/react-nest-antd/licenses/next.txt +21 -0
  386. package/templates/react-nest-antd/licenses/shadcn.txt +21 -0
  387. package/templates/react-nest-antd/licenses/sources.json +27 -0
  388. package/templates/react-nest-antd/licenses/spring.txt +202 -0
  389. package/templates/react-nest-antd/package-lock.json +440 -0
  390. package/templates/react-nest-antd/package.json +21 -0
  391. package/templates/react-nest-antd/playwright.config.ts +3 -0
  392. package/templates/react-nest-antd/project.json +8 -0
  393. package/templates/react-nest-antd/scripts/design-coverage.mjs +20 -0
  394. package/templates/react-nest-antd/scripts/design-next-cleanup.mjs +13 -0
  395. package/templates/react-nest-antd/scripts/design-verify.mjs +154 -0
  396. package/templates/react-nest-antd/scripts/design.mjs +108 -0
  397. package/templates/react-nest-antd/scripts/project.mjs +118 -0
  398. package/templates/react-nest-antd/tests/contract.spec.ts +47 -0
  399. package/templates/react-nest-antd/tests/design/harness.tsx +63 -0
  400. package/templates/react-nest-antd/tests/ui.spec.ts +61 -0
  401. package/templates/react-nest-antd/web/eslint.config.mjs +3 -0
  402. package/templates/react-nest-antd/web/index.html +1 -0
  403. package/templates/react-nest-antd/web/package.json +28 -0
  404. package/templates/react-nest-antd/web/pnpm-lock.yaml +2215 -0
  405. package/templates/react-nest-antd/web/src/App.tsx +29 -0
  406. package/templates/react-nest-antd/web/src/design-layout.css +7 -0
  407. package/templates/react-nest-antd/web/src/design-runtime.json +511 -0
  408. package/templates/react-nest-antd/web/src/design-tokens.css +168 -0
  409. package/templates/react-nest-antd/web/src/design-widgets.css +31 -0
  410. package/templates/react-nest-antd/web/src/main.tsx +6 -0
  411. package/templates/react-nest-antd/web/src/structure-view.tsx +16 -0
  412. package/templates/react-nest-antd/web/src/styles.css +3 -0
  413. package/templates/react-nest-antd/web/src/ui.tsx +30 -0
  414. package/templates/react-nest-antd/web/src/widget-icon.tsx +5 -0
  415. package/templates/react-nest-antd/web/src/widget-types.ts +13 -0
  416. package/templates/react-nest-antd/web/src/workspace-model.ts +85 -0
  417. package/templates/react-nest-antd/web/tsconfig.json +22 -0
  418. package/templates/react-nest-antd/web/vite.config.ts +3 -0
  419. package/templates/react-nest-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
  420. package/templates/react-nest-shadcn/.agents/skills/project-work/SKILL.md +8 -0
  421. package/templates/react-nest-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
  422. package/templates/react-nest-shadcn/.claude/skills/project-work/SKILL.md +8 -0
  423. package/templates/react-nest-shadcn/.dockerignore +18 -0
  424. package/templates/react-nest-shadcn/.env.example +13 -0
  425. package/templates/react-nest-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
  426. package/templates/react-nest-shadcn/.grok/skills/project-work/SKILL.md +8 -0
  427. package/templates/react-nest-shadcn/.scaffold-checks.json +7 -0
  428. package/templates/react-nest-shadcn/AGENTS.md +11 -0
  429. package/templates/react-nest-shadcn/CLAUDE.md +1 -0
  430. package/templates/react-nest-shadcn/DESIGN.md +208 -0
  431. package/templates/react-nest-shadcn/LICENSE +21 -0
  432. package/templates/react-nest-shadcn/README.md +55 -0
  433. package/templates/react-nest-shadcn/THIRD_PARTY_NOTICES.md +14 -0
  434. package/templates/react-nest-shadcn/backend/Dockerfile +12 -0
  435. package/templates/react-nest-shadcn/backend/eslint.config.mjs +3 -0
  436. package/templates/react-nest-shadcn/backend/jest.config.cjs +1 -0
  437. package/templates/react-nest-shadcn/backend/package.json +40 -0
  438. package/templates/react-nest-shadcn/backend/pnpm-lock.yaml +5165 -0
  439. package/templates/react-nest-shadcn/backend/pnpm-workspace.yaml +6 -0
  440. package/templates/react-nest-shadcn/backend/prisma/migrations/202610190001_initial/migration.sql +3 -0
  441. package/templates/react-nest-shadcn/backend/prisma/migrations/migration_lock.toml +1 -0
  442. package/templates/react-nest-shadcn/backend/prisma/schema.prisma +25 -0
  443. package/templates/react-nest-shadcn/backend/scripts/seed.ts +4 -0
  444. package/templates/react-nest-shadcn/backend/src/app.module.ts +43 -0
  445. package/templates/react-nest-shadcn/backend/src/main.ts +6 -0
  446. package/templates/react-nest-shadcn/backend/src/password.ts +3 -0
  447. package/templates/react-nest-shadcn/backend/src/validation.ts +7 -0
  448. package/templates/react-nest-shadcn/backend/test/api.test.ts +25 -0
  449. package/templates/react-nest-shadcn/backend/tsconfig.build.json +15 -0
  450. package/templates/react-nest-shadcn/backend/tsconfig.json +17 -0
  451. package/templates/react-nest-shadcn/compose.yaml +18 -0
  452. package/templates/react-nest-shadcn/design/guide.md +61 -0
  453. package/templates/react-nest-shadcn/design/layout.css +6 -0
  454. package/templates/react-nest-shadcn/design/structure.json +107 -0
  455. package/templates/react-nest-shadcn/design/tokens.json +171 -0
  456. package/templates/react-nest-shadcn/design/widgets.css +30 -0
  457. package/templates/react-nest-shadcn/design/widgets.json +233 -0
  458. package/templates/react-nest-shadcn/docs/PROJECT.md +9 -0
  459. package/templates/react-nest-shadcn/docs/api.d.ts +516 -0
  460. package/templates/react-nest-shadcn/docs/openapi.json +439 -0
  461. package/templates/react-nest-shadcn/gitignore.template +19 -0
  462. package/templates/react-nest-shadcn/licenses/fastapi.txt +21 -0
  463. package/templates/react-nest-shadcn/licenses/nest.txt +22 -0
  464. package/templates/react-nest-shadcn/licenses/next.txt +21 -0
  465. package/templates/react-nest-shadcn/licenses/shadcn.txt +21 -0
  466. package/templates/react-nest-shadcn/licenses/sources.json +27 -0
  467. package/templates/react-nest-shadcn/licenses/spring.txt +202 -0
  468. package/templates/react-nest-shadcn/package-lock.json +440 -0
  469. package/templates/react-nest-shadcn/package.json +21 -0
  470. package/templates/react-nest-shadcn/playwright.config.ts +3 -0
  471. package/templates/react-nest-shadcn/project.json +8 -0
  472. package/templates/react-nest-shadcn/scripts/design-coverage.mjs +20 -0
  473. package/templates/react-nest-shadcn/scripts/design-next-cleanup.mjs +13 -0
  474. package/templates/react-nest-shadcn/scripts/design-verify.mjs +154 -0
  475. package/templates/react-nest-shadcn/scripts/design.mjs +108 -0
  476. package/templates/react-nest-shadcn/scripts/project.mjs +118 -0
  477. package/templates/react-nest-shadcn/tests/contract.spec.ts +47 -0
  478. package/templates/react-nest-shadcn/tests/design/harness.tsx +63 -0
  479. package/templates/react-nest-shadcn/tests/ui.spec.ts +61 -0
  480. package/templates/react-nest-shadcn/web/eslint.config.mjs +3 -0
  481. package/templates/react-nest-shadcn/web/index.html +1 -0
  482. package/templates/react-nest-shadcn/web/package.json +33 -0
  483. package/templates/react-nest-shadcn/web/pnpm-lock.yaml +1788 -0
  484. package/templates/react-nest-shadcn/web/src/App.tsx +30 -0
  485. package/templates/react-nest-shadcn/web/src/design-layout.css +7 -0
  486. package/templates/react-nest-shadcn/web/src/design-runtime.json +511 -0
  487. package/templates/react-nest-shadcn/web/src/design-tokens.css +168 -0
  488. package/templates/react-nest-shadcn/web/src/design-widgets.css +31 -0
  489. package/templates/react-nest-shadcn/web/src/main.tsx +6 -0
  490. package/templates/react-nest-shadcn/web/src/structure-view.tsx +16 -0
  491. package/templates/react-nest-shadcn/web/src/styles.css +3 -0
  492. package/templates/react-nest-shadcn/web/src/tailwind.css +2 -0
  493. package/templates/react-nest-shadcn/web/src/ui.tsx +13 -0
  494. package/templates/react-nest-shadcn/web/src/widget-icon.tsx +5 -0
  495. package/templates/react-nest-shadcn/web/src/widget-types.ts +13 -0
  496. package/templates/react-nest-shadcn/web/src/workspace-model.ts +85 -0
  497. package/templates/react-nest-shadcn/web/tsconfig.json +22 -0
  498. package/templates/react-nest-shadcn/web/vite.config.ts +4 -0
  499. package/templates/react-spring-antd/.agents/skills/design-contract/SKILL.md +23 -0
  500. package/templates/react-spring-antd/.agents/skills/project-work/SKILL.md +8 -0
  501. package/templates/react-spring-antd/.claude/skills/design-contract/SKILL.md +23 -0
  502. package/templates/react-spring-antd/.claude/skills/project-work/SKILL.md +8 -0
  503. package/templates/react-spring-antd/.dockerignore +18 -0
  504. package/templates/react-spring-antd/.env.example +13 -0
  505. package/templates/react-spring-antd/.grok/skills/design-contract/SKILL.md +23 -0
  506. package/templates/react-spring-antd/.grok/skills/project-work/SKILL.md +8 -0
  507. package/templates/react-spring-antd/.scaffold-checks.json +7 -0
  508. package/templates/react-spring-antd/AGENTS.md +11 -0
  509. package/templates/react-spring-antd/CLAUDE.md +1 -0
  510. package/templates/react-spring-antd/DESIGN.md +208 -0
  511. package/templates/react-spring-antd/LICENSE +21 -0
  512. package/templates/react-spring-antd/README.md +55 -0
  513. package/templates/react-spring-antd/THIRD_PARTY_NOTICES.md +14 -0
  514. package/templates/react-spring-antd/backend/.mvn/wrapper/maven-wrapper.properties +3 -0
  515. package/templates/react-spring-antd/backend/Dockerfile +11 -0
  516. package/templates/react-spring-antd/backend/mvnw +295 -0
  517. package/templates/react-spring-antd/backend/pom.xml +15 -0
  518. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Api.java +38 -0
  519. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/AppUser.java +11 -0
  520. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Application.java +7 -0
  521. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Errors.java +13 -0
  522. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/PersonalRecord.java +15 -0
  523. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Records.java +14 -0
  524. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Security.java +28 -0
  525. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Seed.java +13 -0
  526. package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Users.java +5 -0
  527. package/templates/react-spring-antd/backend/src/main/resources/application.properties +17 -0
  528. package/templates/react-spring-antd/backend/src/main/resources/db/migration/V1__initial.sql +3 -0
  529. package/templates/react-spring-antd/backend/src/main/resources/openapi.json +439 -0
  530. package/templates/react-spring-antd/backend/src/test/java/dev/scaffold/app/ApiTest.java +28 -0
  531. package/templates/react-spring-antd/backend/src/test/java/dev/scaffold/app/SessionExpiryTest.java +37 -0
  532. package/templates/react-spring-antd/compose.yaml +18 -0
  533. package/templates/react-spring-antd/design/guide.md +61 -0
  534. package/templates/react-spring-antd/design/layout.css +6 -0
  535. package/templates/react-spring-antd/design/structure.json +107 -0
  536. package/templates/react-spring-antd/design/tokens.json +171 -0
  537. package/templates/react-spring-antd/design/widgets.css +30 -0
  538. package/templates/react-spring-antd/design/widgets.json +233 -0
  539. package/templates/react-spring-antd/docs/PROJECT.md +9 -0
  540. package/templates/react-spring-antd/docs/api.d.ts +516 -0
  541. package/templates/react-spring-antd/docs/openapi.json +439 -0
  542. package/templates/react-spring-antd/gitignore.template +19 -0
  543. package/templates/react-spring-antd/licenses/fastapi.txt +21 -0
  544. package/templates/react-spring-antd/licenses/nest.txt +22 -0
  545. package/templates/react-spring-antd/licenses/next.txt +21 -0
  546. package/templates/react-spring-antd/licenses/shadcn.txt +21 -0
  547. package/templates/react-spring-antd/licenses/sources.json +27 -0
  548. package/templates/react-spring-antd/licenses/spring.txt +202 -0
  549. package/templates/react-spring-antd/package-lock.json +440 -0
  550. package/templates/react-spring-antd/package.json +21 -0
  551. package/templates/react-spring-antd/playwright.config.ts +3 -0
  552. package/templates/react-spring-antd/project.json +8 -0
  553. package/templates/react-spring-antd/scripts/design-coverage.mjs +20 -0
  554. package/templates/react-spring-antd/scripts/design-next-cleanup.mjs +13 -0
  555. package/templates/react-spring-antd/scripts/design-verify.mjs +154 -0
  556. package/templates/react-spring-antd/scripts/design.mjs +108 -0
  557. package/templates/react-spring-antd/scripts/project.mjs +118 -0
  558. package/templates/react-spring-antd/tests/contract.spec.ts +47 -0
  559. package/templates/react-spring-antd/tests/design/harness.tsx +63 -0
  560. package/templates/react-spring-antd/tests/ui.spec.ts +61 -0
  561. package/templates/react-spring-antd/web/eslint.config.mjs +3 -0
  562. package/templates/react-spring-antd/web/index.html +1 -0
  563. package/templates/react-spring-antd/web/package.json +28 -0
  564. package/templates/react-spring-antd/web/pnpm-lock.yaml +2215 -0
  565. package/templates/react-spring-antd/web/src/App.tsx +29 -0
  566. package/templates/react-spring-antd/web/src/design-layout.css +7 -0
  567. package/templates/react-spring-antd/web/src/design-runtime.json +511 -0
  568. package/templates/react-spring-antd/web/src/design-tokens.css +168 -0
  569. package/templates/react-spring-antd/web/src/design-widgets.css +31 -0
  570. package/templates/react-spring-antd/web/src/main.tsx +6 -0
  571. package/templates/react-spring-antd/web/src/structure-view.tsx +16 -0
  572. package/templates/react-spring-antd/web/src/styles.css +3 -0
  573. package/templates/react-spring-antd/web/src/ui.tsx +30 -0
  574. package/templates/react-spring-antd/web/src/widget-icon.tsx +5 -0
  575. package/templates/react-spring-antd/web/src/widget-types.ts +13 -0
  576. package/templates/react-spring-antd/web/src/workspace-model.ts +85 -0
  577. package/templates/react-spring-antd/web/tsconfig.json +22 -0
  578. package/templates/react-spring-antd/web/vite.config.ts +3 -0
  579. package/templates/react-spring-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
  580. package/templates/react-spring-shadcn/.agents/skills/project-work/SKILL.md +8 -0
  581. package/templates/react-spring-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
  582. package/templates/react-spring-shadcn/.claude/skills/project-work/SKILL.md +8 -0
  583. package/templates/react-spring-shadcn/.dockerignore +18 -0
  584. package/templates/react-spring-shadcn/.env.example +13 -0
  585. package/templates/react-spring-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
  586. package/templates/react-spring-shadcn/.grok/skills/project-work/SKILL.md +8 -0
  587. package/templates/react-spring-shadcn/.scaffold-checks.json +7 -0
  588. package/templates/react-spring-shadcn/AGENTS.md +11 -0
  589. package/templates/react-spring-shadcn/CLAUDE.md +1 -0
  590. package/templates/react-spring-shadcn/DESIGN.md +208 -0
  591. package/templates/react-spring-shadcn/LICENSE +21 -0
  592. package/templates/react-spring-shadcn/README.md +55 -0
  593. package/templates/react-spring-shadcn/THIRD_PARTY_NOTICES.md +14 -0
  594. package/templates/react-spring-shadcn/backend/.mvn/wrapper/maven-wrapper.properties +3 -0
  595. package/templates/react-spring-shadcn/backend/Dockerfile +11 -0
  596. package/templates/react-spring-shadcn/backend/mvnw +295 -0
  597. package/templates/react-spring-shadcn/backend/pom.xml +15 -0
  598. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Api.java +38 -0
  599. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/AppUser.java +11 -0
  600. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Application.java +7 -0
  601. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Errors.java +13 -0
  602. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/PersonalRecord.java +15 -0
  603. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Records.java +14 -0
  604. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Security.java +28 -0
  605. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Seed.java +13 -0
  606. package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Users.java +5 -0
  607. package/templates/react-spring-shadcn/backend/src/main/resources/application.properties +17 -0
  608. package/templates/react-spring-shadcn/backend/src/main/resources/db/migration/V1__initial.sql +3 -0
  609. package/templates/react-spring-shadcn/backend/src/main/resources/openapi.json +439 -0
  610. package/templates/react-spring-shadcn/backend/src/test/java/dev/scaffold/app/ApiTest.java +28 -0
  611. package/templates/react-spring-shadcn/backend/src/test/java/dev/scaffold/app/SessionExpiryTest.java +37 -0
  612. package/templates/react-spring-shadcn/compose.yaml +18 -0
  613. package/templates/react-spring-shadcn/design/guide.md +61 -0
  614. package/templates/react-spring-shadcn/design/layout.css +6 -0
  615. package/templates/react-spring-shadcn/design/structure.json +107 -0
  616. package/templates/react-spring-shadcn/design/tokens.json +171 -0
  617. package/templates/react-spring-shadcn/design/widgets.css +30 -0
  618. package/templates/react-spring-shadcn/design/widgets.json +233 -0
  619. package/templates/react-spring-shadcn/docs/PROJECT.md +9 -0
  620. package/templates/react-spring-shadcn/docs/api.d.ts +516 -0
  621. package/templates/react-spring-shadcn/docs/openapi.json +439 -0
  622. package/templates/react-spring-shadcn/gitignore.template +19 -0
  623. package/templates/react-spring-shadcn/licenses/fastapi.txt +21 -0
  624. package/templates/react-spring-shadcn/licenses/nest.txt +22 -0
  625. package/templates/react-spring-shadcn/licenses/next.txt +21 -0
  626. package/templates/react-spring-shadcn/licenses/shadcn.txt +21 -0
  627. package/templates/react-spring-shadcn/licenses/sources.json +27 -0
  628. package/templates/react-spring-shadcn/licenses/spring.txt +202 -0
  629. package/templates/react-spring-shadcn/package-lock.json +440 -0
  630. package/templates/react-spring-shadcn/package.json +21 -0
  631. package/templates/react-spring-shadcn/playwright.config.ts +3 -0
  632. package/templates/react-spring-shadcn/project.json +8 -0
  633. package/templates/react-spring-shadcn/scripts/design-coverage.mjs +20 -0
  634. package/templates/react-spring-shadcn/scripts/design-next-cleanup.mjs +13 -0
  635. package/templates/react-spring-shadcn/scripts/design-verify.mjs +154 -0
  636. package/templates/react-spring-shadcn/scripts/design.mjs +108 -0
  637. package/templates/react-spring-shadcn/scripts/project.mjs +118 -0
  638. package/templates/react-spring-shadcn/tests/contract.spec.ts +47 -0
  639. package/templates/react-spring-shadcn/tests/design/harness.tsx +63 -0
  640. package/templates/react-spring-shadcn/tests/ui.spec.ts +61 -0
  641. package/templates/react-spring-shadcn/web/eslint.config.mjs +3 -0
  642. package/templates/react-spring-shadcn/web/index.html +1 -0
  643. package/templates/react-spring-shadcn/web/package.json +33 -0
  644. package/templates/react-spring-shadcn/web/pnpm-lock.yaml +1788 -0
  645. package/templates/react-spring-shadcn/web/src/App.tsx +30 -0
  646. package/templates/react-spring-shadcn/web/src/design-layout.css +7 -0
  647. package/templates/react-spring-shadcn/web/src/design-runtime.json +511 -0
  648. package/templates/react-spring-shadcn/web/src/design-tokens.css +168 -0
  649. package/templates/react-spring-shadcn/web/src/design-widgets.css +31 -0
  650. package/templates/react-spring-shadcn/web/src/main.tsx +6 -0
  651. package/templates/react-spring-shadcn/web/src/structure-view.tsx +16 -0
  652. package/templates/react-spring-shadcn/web/src/styles.css +3 -0
  653. package/templates/react-spring-shadcn/web/src/tailwind.css +2 -0
  654. package/templates/react-spring-shadcn/web/src/ui.tsx +13 -0
  655. package/templates/react-spring-shadcn/web/src/widget-icon.tsx +5 -0
  656. package/templates/react-spring-shadcn/web/src/widget-types.ts +13 -0
  657. package/templates/react-spring-shadcn/web/src/workspace-model.ts +85 -0
  658. package/templates/react-spring-shadcn/web/tsconfig.json +22 -0
  659. package/templates/react-spring-shadcn/web/vite.config.ts +4 -0
@@ -0,0 +1,38 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.web.bind.annotation.*;
3
+ import org.springframework.web.server.ResponseStatusException;
4
+ import org.springframework.http.HttpStatus;
5
+ import org.springframework.security.authentication.*;
6
+ import org.springframework.security.core.Authentication;
7
+ import org.springframework.security.core.context.SecurityContextHolder;
8
+ import org.springframework.security.core.AuthenticationException;
9
+ import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
10
+ import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
11
+ import org.springframework.data.domain.PageRequest;
12
+ import org.springframework.data.domain.Sort;
13
+ import org.springframework.transaction.annotation.Transactional;
14
+ import org.springframework.core.io.ClassPathResource;
15
+ import jakarta.servlet.http.*;
16
+ import java.util.*;
17
+ import java.time.Instant;
18
+ @RestController @RequestMapping("/api")
19
+ public class Api {
20
+ private final Users users;private final Records records;private final AuthenticationManager manager;
21
+ public Api(Users users,Records records,AuthenticationManager manager){this.users=users;this.records=records;this.manager=manager;}
22
+ private static ResponseStatusException invalid(){return new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);}
23
+ private static UUID id(String value){try{return UUID.fromString(value);}catch(IllegalArgumentException e){throw invalid();}}
24
+ private AppUser user(Authentication auth){return users.findByEmail(auth.getName()).orElseThrow(()->new ResponseStatusException(HttpStatus.UNAUTHORIZED));}
25
+ private static String[] input(Map<String,Object> body){if(!body.keySet().equals(Set.of("title","content"))||!(body.get("title") instanceof String)||!(body.get("content") instanceof String))throw invalid();String title=((String)body.get("title")).strip(),content=(String)body.get("content");int n=title.codePointCount(0,title.length());if(n<1||n>120||content.codePointCount(0,content.length())>10000)throw invalid();return new String[]{title,content};}
26
+ private static Map<String,Object> out(PersonalRecord r){return Map.of("id",r.id.toString(),"title",r.title,"content",r.content,"created_at",r.createdAt.toString(),"updated_at",r.updatedAt.toString());}
27
+ private PersonalRecord owned(UUID id,UUID owner){return records.findByIdAndOwnerId(id,owner).orElseThrow(()->new ResponseStatusException(HttpStatus.NOT_FOUND));}
28
+ @GetMapping("/health") public Map<String,String> health(){return Map.of("status","ok");}
29
+ @GetMapping(value="/openapi.json",produces="application/json") public ClassPathResource openapi(){return new ClassPathResource("openapi.json");}
30
+ @PostMapping("/auth/login") public Map<String,Object> login(@RequestBody Map<String,Object> body,HttpServletRequest request,HttpServletResponse response){if(!body.keySet().equals(Set.of("email","password"))||!(body.get("email") instanceof String)||!(body.get("password") instanceof String))throw invalid();try{var auth=manager.authenticate(UsernamePasswordAuthenticationToken.unauthenticated(((String)body.get("email")).strip().toLowerCase(Locale.ROOT),body.get("password")));var context=SecurityContextHolder.createEmptyContext();context.setAuthentication(auth);request.getSession(true);request.changeSessionId();SecurityContextHolder.setContext(context);new HttpSessionSecurityContextRepository().saveContext(context,request,response);var u=user(auth);return Map.of("user",Map.of("id",u.id.toString(),"email",u.email),"mode","session");}catch(AuthenticationException e){throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);}}
31
+ @GetMapping("/auth/me") public Map<String,Object> me(Authentication auth){var u=user(auth);return Map.of("user",Map.of("id",u.id.toString(),"email",u.email));}
32
+ @PostMapping("/auth/logout") @ResponseStatus(HttpStatus.NO_CONTENT) public void logout(HttpServletRequest req,HttpServletResponse res,Authentication auth){new SecurityContextLogoutHandler().logout(req,res,auth);}
33
+ @GetMapping("/records") public Map<String,Object> list(Authentication auth,@RequestParam(defaultValue="1") int page,@RequestParam(defaultValue="10") int pageSize){if(page<1||page>1000000||pageSize<1||pageSize>100)throw invalid();var rows=records.findByOwnerId(user(auth).id,PageRequest.of(page-1,pageSize,Sort.by(Sort.Direction.DESC,"createdAt","id")));return Map.of("items",rows.getContent().stream().map(Api::out).toList(),"total",rows.getTotalElements(),"page",page,"pageSize",pageSize);}
34
+ @PostMapping("/records") @ResponseStatus(HttpStatus.CREATED) public Map<String,Object> create(Authentication auth,@RequestBody Map<String,Object> body){var data=input(body);return out(records.saveAndFlush(new PersonalRecord(user(auth).id,data[0],data[1])));}
35
+ @GetMapping("/records/{recordId}") public Map<String,Object> detail(Authentication auth,@PathVariable String recordId){return out(owned(id(recordId),user(auth).id));}
36
+ @PutMapping("/records/{recordId}") @Transactional public Map<String,Object> update(Authentication auth,@PathVariable String recordId,@RequestBody Map<String,Object> body){var data=input(body);var owner=user(auth).id;var key=id(recordId);if(records.updateOwned(key,owner,data[0],data[1],Instant.now())==0)throw new ResponseStatusException(HttpStatus.NOT_FOUND);return out(owned(key,owner));}
37
+ @DeleteMapping("/records/{recordId}") @Transactional @ResponseStatus(HttpStatus.NO_CONTENT) public void delete(Authentication auth,@PathVariable String recordId){if(records.deleteOwned(id(recordId),user(auth).id)==0)throw new ResponseStatusException(HttpStatus.NOT_FOUND);}
38
+ }
@@ -0,0 +1,11 @@
1
+ package dev.scaffold.app;
2
+ import jakarta.persistence.*;
3
+ import java.util.UUID;
4
+ @Entity @Table(name="app_user")
5
+ public class AppUser {
6
+ @Id UUID id=UUID.randomUUID();
7
+ @Column(nullable=false,unique=true,length=320) String email;
8
+ @Column(nullable=false) String password;
9
+ protected AppUser(){}
10
+ AppUser(String email,String password){this.email=email;this.password=password;}
11
+ }
@@ -0,0 +1,7 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.boot.SpringApplication;
3
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
4
+ @SpringBootApplication
5
+ public class Application {
6
+ public static void main(String[] args) { var context=SpringApplication.run(Application.class,args);if(context.getEnvironment().getProperty("scaffold.migrate-only",Boolean.class,false)||context.getEnvironment().getProperty("scaffold.seed-only",Boolean.class,false)){SpringApplication.exit(context);}}
7
+ }
@@ -0,0 +1,13 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.web.bind.annotation.*;
3
+ import org.springframework.web.server.ResponseStatusException;
4
+ import org.springframework.http.ResponseEntity;
5
+ import org.springframework.http.converter.HttpMessageNotReadableException;
6
+ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
7
+ import java.util.Map;
8
+ @RestControllerAdvice
9
+ public class Errors {
10
+ @ExceptionHandler(ResponseStatusException.class) ResponseEntity<?> status(ResponseStatusException e){return error(e.getStatusCode().value());}
11
+ @ExceptionHandler({HttpMessageNotReadableException.class,MethodArgumentTypeMismatchException.class}) ResponseEntity<?> invalid(Exception e){return error(422);}
12
+ private ResponseEntity<?> error(int status){String message=switch(status){case 401->"请重新登录。";case 404->"记录不存在。";case 422->"输入不合法,请检查字段和长度。";default->"请求失败。";};return ResponseEntity.status(status).body(Map.of("error",Map.of("code",String.valueOf(status),"message",message)));}
13
+ }
@@ -0,0 +1,15 @@
1
+ package dev.scaffold.app;
2
+ import jakarta.persistence.*;
3
+ import java.time.Instant;
4
+ import java.util.UUID;
5
+ @Entity @Table(name="personal_record")
6
+ public class PersonalRecord {
7
+ @Id UUID id=UUID.randomUUID();
8
+ @Column(name="owner_id",nullable=false) UUID ownerId;
9
+ @Column(nullable=false,length=120) String title;
10
+ @Column(nullable=false,columnDefinition="text") String content;
11
+ @Column(name="created_at",nullable=false) Instant createdAt=Instant.now();
12
+ @Column(name="updated_at",nullable=false) Instant updatedAt=Instant.now();
13
+ protected PersonalRecord(){}
14
+ PersonalRecord(UUID ownerId,String title,String content){this.ownerId=ownerId;this.title=title;this.content=content;}
15
+ }
@@ -0,0 +1,14 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.data.jpa.repository.JpaRepository;
3
+ import org.springframework.data.jpa.repository.Modifying;
4
+ import org.springframework.data.jpa.repository.Query;
5
+ import org.springframework.data.domain.Page;
6
+ import org.springframework.data.domain.Pageable;
7
+ import java.util.Optional;
8
+ import java.util.UUID;
9
+ public interface Records extends JpaRepository<PersonalRecord,UUID>{
10
+ Page<PersonalRecord> findByOwnerId(UUID ownerId,Pageable page);
11
+ Optional<PersonalRecord> findByIdAndOwnerId(UUID id,UUID ownerId);
12
+ @Modifying @Query("delete from PersonalRecord r where r.id=:id and r.ownerId=:ownerId") int deleteOwned(UUID id,UUID ownerId);
13
+ @Modifying @Query("update PersonalRecord r set r.title=:title,r.content=:content,r.updatedAt=:now where r.id=:id and r.ownerId=:ownerId") int updateOwned(UUID id,UUID ownerId,String title,String content,java.time.Instant now);
14
+ }
@@ -0,0 +1,28 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.context.annotation.*;
3
+ import org.springframework.security.authentication.*;
4
+ import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
5
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6
+ import org.springframework.security.config.http.SessionCreationPolicy;
7
+ import org.springframework.security.core.userdetails.*;
8
+ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
9
+ import org.springframework.security.crypto.password.PasswordEncoder;
10
+ import org.springframework.security.web.SecurityFilterChain;
11
+ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
12
+ import org.springframework.web.filter.OncePerRequestFilter;
13
+ import jakarta.servlet.*;
14
+ import jakarta.servlet.http.*;
15
+ import java.io.IOException;
16
+ import java.util.Set;
17
+ @Configuration
18
+ public class Security {
19
+ @Bean PasswordEncoder encoder(){return new BCryptPasswordEncoder();}
20
+ @Bean UserDetailsService userDetails(Users users){return email->users.findByEmail(email).map(u->User.withUsername(u.email).password(u.password).roles("USER").build()).orElseThrow(()->new UsernameNotFoundException("Unknown account"));}
21
+ @Bean AuthenticationManager authenticationManager(UserDetailsService service,PasswordEncoder encoder){var provider=new DaoAuthenticationProvider(service);provider.setPasswordEncoder(encoder);return new ProviderManager(provider);}
22
+ @Bean SecurityFilterChain filter(HttpSecurity http) throws Exception {
23
+ String origin=System.getenv("APP_ORIGIN");if(origin==null)throw new IllegalStateException("APP_ORIGIN is required");
24
+ var originCheck=new OncePerRequestFilter(){protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)throws ServletException,IOException{if(!Set.of("GET","HEAD","OPTIONS").contains(request.getMethod())&&!origin.equals(request.getHeader("Origin"))){response.setStatus(403);response.setContentType("application/json");response.getWriter().write("{\"error\":{\"code\":\"403\",\"message\":\"Invalid request origin\"}}");return;}chain.doFilter(request,response);}};
25
+ http.csrf(csrf->csrf.disable()).addFilterBefore(originCheck,UsernamePasswordAuthenticationFilter.class).sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)).authorizeHttpRequests(a->a.requestMatchers("/api/health","/api/auth/login","/api/openapi.json","/error").permitAll().anyRequest().authenticated()).exceptionHandling(e->e.authenticationEntryPoint((req,res,ex)->{res.setStatus(401);res.setContentType("application/json");res.getWriter().write("{\"error\":{\"code\":\"401\",\"message\":\"Please sign in\"}}");}));
26
+ return http.build();
27
+ }
28
+ }
@@ -0,0 +1,13 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.boot.ApplicationRunner;
3
+ import org.springframework.boot.ApplicationArguments;
4
+ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5
+ import org.springframework.stereotype.Component;
6
+ import org.springframework.security.crypto.password.PasswordEncoder;
7
+ import java.util.Locale;
8
+ @Component @ConditionalOnProperty(name="scaffold.seed-only",havingValue="true")
9
+ public class Seed implements ApplicationRunner {
10
+ private final Users users;private final PasswordEncoder encoder;
11
+ public Seed(Users users,PasswordEncoder encoder){this.users=users;this.encoder=encoder;}
12
+ public void run(ApplicationArguments args){var password=System.getenv("SEED_PASSWORD");if(password==null||password.length()<12)throw new IllegalStateException("Provide an explicit seed password with 12+ characters");for(String key:new String[]{"SEED_A_EMAIL","SEED_B_EMAIL"}){var raw=System.getenv(key);if(raw==null)throw new IllegalStateException("Missing "+key);var email=raw.strip().toLowerCase(Locale.ROOT);if(users.findByEmail(email).isEmpty())users.saveAndFlush(new AppUser(email,encoder.encode(password)));}}
13
+ }
@@ -0,0 +1,5 @@
1
+ package dev.scaffold.app;
2
+ import org.springframework.data.jpa.repository.JpaRepository;
3
+ import java.util.Optional;
4
+ import java.util.UUID;
5
+ public interface Users extends JpaRepository<AppUser,UUID>{Optional<AppUser> findByEmail(String email);}
@@ -0,0 +1,17 @@
1
+ server.port=${PORT:8000}
2
+ server.address=127.0.0.1
3
+ server.servlet.session.timeout=15m
4
+ server.servlet.session.cookie.http-only=true
5
+ server.servlet.session.cookie.same-site=lax
6
+ server.servlet.session.cookie.secure=${SESSION_COOKIE_SECURE:true}
7
+ spring.datasource.url=${SPRING_DATASOURCE_URL}
8
+ spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
9
+ spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
10
+ spring.jpa.hibernate.ddl-auto=validate
11
+ spring.jpa.open-in-view=false
12
+ spring.jpa.show-sql=false
13
+ spring.jackson.deserialization.fail-on-unknown-properties=true
14
+ server.error.include-message=never
15
+ server.error.include-stacktrace=never
16
+ logging.level.root=WARN
17
+ spring.main.banner-mode=off
@@ -0,0 +1,3 @@
1
+ CREATE TABLE app_user (id UUID PRIMARY KEY, email VARCHAR(320) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL);
2
+ CREATE TABLE personal_record (id UUID PRIMARY KEY, owner_id UUID NOT NULL REFERENCES app_user(id), title VARCHAR(120) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL);
3
+ CREATE INDEX personal_record_owner_idx ON personal_record(owner_id);
@@ -0,0 +1,439 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "Personal Records",
5
+ "version": "1.0.0",
6
+ "description": "JWT or Session according to selected template. Session writes require the configured Origin."
7
+ },
8
+ "paths": {
9
+ "/api/health": {
10
+ "get": {
11
+ "responses": {
12
+ "200": {
13
+ "description": "Success",
14
+ "content": {
15
+ "application/json": {
16
+ "schema": {
17
+ "type": "object",
18
+ "properties": {
19
+ "status": {
20
+ "type": "string"
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ },
30
+ "/api/auth/login": {
31
+ "post": {
32
+ "requestBody": {
33
+ "required": true,
34
+ "content": {
35
+ "application/json": {
36
+ "schema": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": [
40
+ "email",
41
+ "password"
42
+ ],
43
+ "properties": {
44
+ "email": {
45
+ "type": "string"
46
+ },
47
+ "password": {
48
+ "type": "string",
49
+ "writeOnly": true
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "responses": {
57
+ "200": {
58
+ "description": "Success",
59
+ "content": {
60
+ "application/json": {
61
+ "schema": {
62
+ "type": "object",
63
+ "properties": {
64
+ "user": {
65
+ "type": "object",
66
+ "required": [
67
+ "id",
68
+ "email"
69
+ ],
70
+ "properties": {
71
+ "id": {
72
+ "type": "string"
73
+ },
74
+ "email": {
75
+ "type": "string"
76
+ }
77
+ }
78
+ },
79
+ "token": {
80
+ "type": "string"
81
+ },
82
+ "mode": {
83
+ "enum": [
84
+ "jwt",
85
+ "session"
86
+ ]
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ },
93
+ "401": {
94
+ "description": "Identity missing or expired"
95
+ },
96
+ "404": {
97
+ "description": "Record absent or owned by another user"
98
+ },
99
+ "422": {
100
+ "description": "Invalid input or protected field"
101
+ }
102
+ }
103
+ }
104
+ },
105
+ "/api/auth/me": {
106
+ "get": {
107
+ "responses": {
108
+ "200": {
109
+ "description": "Success",
110
+ "content": {
111
+ "application/json": {
112
+ "schema": {
113
+ "type": "object",
114
+ "properties": {
115
+ "user": {
116
+ "type": "object",
117
+ "required": [
118
+ "id",
119
+ "email"
120
+ ],
121
+ "properties": {
122
+ "id": {
123
+ "type": "string"
124
+ },
125
+ "email": {
126
+ "type": "string"
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ },
135
+ "401": {
136
+ "description": "Identity missing or expired"
137
+ },
138
+ "404": {
139
+ "description": "Record absent or owned by another user"
140
+ },
141
+ "422": {
142
+ "description": "Invalid input or protected field"
143
+ }
144
+ }
145
+ }
146
+ },
147
+ "/api/auth/logout": {
148
+ "post": {
149
+ "responses": {
150
+ "204": {
151
+ "description": "Logged out; JWT is cleared client-side"
152
+ },
153
+ "401": {
154
+ "description": "Identity missing or expired"
155
+ },
156
+ "404": {
157
+ "description": "Record absent or owned by another user"
158
+ },
159
+ "422": {
160
+ "description": "Invalid input or protected field"
161
+ }
162
+ }
163
+ }
164
+ },
165
+ "/api/records": {
166
+ "get": {
167
+ "parameters": [
168
+ {
169
+ "name": "page",
170
+ "in": "query",
171
+ "schema": {
172
+ "type": "integer",
173
+ "minimum": 1,
174
+ "maximum": 1000000,
175
+ "default": 1
176
+ }
177
+ },
178
+ {
179
+ "name": "pageSize",
180
+ "in": "query",
181
+ "schema": {
182
+ "type": "integer",
183
+ "minimum": 1,
184
+ "maximum": 100,
185
+ "default": 10
186
+ }
187
+ }
188
+ ],
189
+ "responses": {
190
+ "200": {
191
+ "description": "Success",
192
+ "content": {
193
+ "application/json": {
194
+ "schema": {
195
+ "type": "object",
196
+ "required": [
197
+ "items",
198
+ "total",
199
+ "page",
200
+ "pageSize"
201
+ ],
202
+ "properties": {
203
+ "items": {
204
+ "type": "array",
205
+ "items": {
206
+ "$ref": "#/components/schemas/Record"
207
+ }
208
+ },
209
+ "total": {
210
+ "type": "integer"
211
+ },
212
+ "page": {
213
+ "type": "integer"
214
+ },
215
+ "pageSize": {
216
+ "type": "integer"
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+ },
223
+ "401": {
224
+ "description": "Identity missing or expired"
225
+ },
226
+ "404": {
227
+ "description": "Record absent or owned by another user"
228
+ },
229
+ "422": {
230
+ "description": "Invalid input or protected field"
231
+ }
232
+ }
233
+ },
234
+ "post": {
235
+ "requestBody": {
236
+ "required": true,
237
+ "content": {
238
+ "application/json": {
239
+ "schema": {
240
+ "type": "object",
241
+ "additionalProperties": false,
242
+ "required": [
243
+ "title",
244
+ "content"
245
+ ],
246
+ "properties": {
247
+ "title": {
248
+ "type": "string",
249
+ "minLength": 1,
250
+ "maxLength": 120
251
+ },
252
+ "content": {
253
+ "type": "string",
254
+ "maxLength": 10000
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+ },
261
+ "responses": {
262
+ "201": {
263
+ "description": "Success",
264
+ "content": {
265
+ "application/json": {
266
+ "schema": {
267
+ "$ref": "#/components/schemas/Record"
268
+ }
269
+ }
270
+ }
271
+ },
272
+ "401": {
273
+ "description": "Identity missing or expired"
274
+ },
275
+ "404": {
276
+ "description": "Record absent or owned by another user"
277
+ },
278
+ "422": {
279
+ "description": "Invalid input or protected field"
280
+ }
281
+ }
282
+ }
283
+ },
284
+ "/api/records/{id}": {
285
+ "parameters": [
286
+ {
287
+ "name": "id",
288
+ "in": "path",
289
+ "required": true,
290
+ "schema": {
291
+ "type": "string",
292
+ "format": "uuid"
293
+ }
294
+ }
295
+ ],
296
+ "get": {
297
+ "responses": {
298
+ "200": {
299
+ "description": "Success",
300
+ "content": {
301
+ "application/json": {
302
+ "schema": {
303
+ "$ref": "#/components/schemas/Record"
304
+ }
305
+ }
306
+ }
307
+ },
308
+ "401": {
309
+ "description": "Identity missing or expired"
310
+ },
311
+ "404": {
312
+ "description": "Record absent or owned by another user"
313
+ },
314
+ "422": {
315
+ "description": "Invalid input or protected field"
316
+ }
317
+ }
318
+ },
319
+ "put": {
320
+ "requestBody": {
321
+ "required": true,
322
+ "content": {
323
+ "application/json": {
324
+ "schema": {
325
+ "type": "object",
326
+ "additionalProperties": false,
327
+ "required": [
328
+ "title",
329
+ "content"
330
+ ],
331
+ "properties": {
332
+ "title": {
333
+ "type": "string",
334
+ "minLength": 1,
335
+ "maxLength": 120
336
+ },
337
+ "content": {
338
+ "type": "string",
339
+ "maxLength": 10000
340
+ }
341
+ }
342
+ }
343
+ }
344
+ }
345
+ },
346
+ "responses": {
347
+ "200": {
348
+ "description": "Success",
349
+ "content": {
350
+ "application/json": {
351
+ "schema": {
352
+ "$ref": "#/components/schemas/Record"
353
+ }
354
+ }
355
+ }
356
+ },
357
+ "401": {
358
+ "description": "Identity missing or expired"
359
+ },
360
+ "404": {
361
+ "description": "Record absent or owned by another user"
362
+ },
363
+ "422": {
364
+ "description": "Invalid input or protected field"
365
+ }
366
+ }
367
+ },
368
+ "delete": {
369
+ "responses": {
370
+ "204": {
371
+ "description": "Deleted"
372
+ },
373
+ "401": {
374
+ "description": "Identity missing or expired"
375
+ },
376
+ "404": {
377
+ "description": "Record absent or owned by another user"
378
+ },
379
+ "422": {
380
+ "description": "Invalid input or protected field"
381
+ }
382
+ }
383
+ }
384
+ }
385
+ },
386
+ "components": {
387
+ "schemas": {
388
+ "Record": {
389
+ "type": "object",
390
+ "required": [
391
+ "id",
392
+ "title",
393
+ "content",
394
+ "created_at",
395
+ "updated_at"
396
+ ],
397
+ "properties": {
398
+ "id": {
399
+ "type": "string",
400
+ "format": "uuid"
401
+ },
402
+ "title": {
403
+ "type": "string"
404
+ },
405
+ "content": {
406
+ "type": "string"
407
+ },
408
+ "created_at": {
409
+ "type": "string",
410
+ "format": "date-time"
411
+ },
412
+ "updated_at": {
413
+ "type": "string",
414
+ "format": "date-time"
415
+ }
416
+ }
417
+ },
418
+ "RecordInput": {
419
+ "type": "object",
420
+ "additionalProperties": false,
421
+ "required": [
422
+ "title",
423
+ "content"
424
+ ],
425
+ "properties": {
426
+ "title": {
427
+ "type": "string",
428
+ "minLength": 1,
429
+ "maxLength": 120
430
+ },
431
+ "content": {
432
+ "type": "string",
433
+ "maxLength": 10000
434
+ }
435
+ }
436
+ }
437
+ }
438
+ }
439
+ }
@@ -0,0 +1,28 @@
1
+ package dev.scaffold.app;
2
+ import org.junit.jupiter.api.Test;
3
+ import org.springframework.beans.factory.annotation.Autowired;
4
+ import org.springframework.boot.test.context.SpringBootTest;
5
+ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
6
+ import org.springframework.test.web.servlet.MockMvc;
7
+ import org.springframework.mock.web.MockHttpSession;
8
+ import com.fasterxml.jackson.databind.ObjectMapper;
9
+ import java.util.Map;
10
+ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
11
+ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
12
+ @SpringBootTest @AutoConfigureMockMvc
13
+ class ApiTest {
14
+ @Autowired MockMvc mvc;@Autowired ObjectMapper json;
15
+ String origin=System.getenv("APP_ORIGIN");
16
+ MockHttpSession login(String key)throws Exception{return (MockHttpSession)mvc.perform(post("/api/auth/login").header("Origin",origin).contentType("application/json").content(json.writeValueAsString(Map.of("email",System.getenv(key),"password",System.getenv("SEED_PASSWORD"))))).andExpect(status().isOk()).andReturn().getRequest().getSession();}
17
+ @Test void ownershipAndLogout()throws Exception{
18
+ mvc.perform(get("/api/records")).andExpect(status().isUnauthorized());var a=login("SEED_A_EMAIL");var b=login("SEED_B_EMAIL");
19
+ mvc.perform(post("/api/records").session(a).header("Origin",origin).contentType("application/json").content("{\"title\":\"x\",\"content\":\"\",\"owner_id\":\"fake\"}")).andExpect(status().isUnprocessableEntity());
20
+ var result=mvc.perform(post("/api/records").session(a).header("Origin",origin).contentType("application/json").content("{\"title\":\"native test\",\"content\":\"saved\"}")).andExpect(status().isCreated()).andReturn();
21
+ var id=json.readTree(result.getResponse().getContentAsString()).get("id").asText();var path="/api/records/"+id;
22
+ mvc.perform(get(path).session(b)).andExpect(status().isNotFound());mvc.perform(delete(path).session(b).header("Origin",origin)).andExpect(status().isNotFound());
23
+ mvc.perform(get(path).session(a)).andExpect(jsonPath("$.content").value("saved"));
24
+ mvc.perform(delete(path).session(a).header("Origin",origin)).andExpect(status().isNoContent());
25
+ mvc.perform(post("/api/auth/logout").session(a).header("Origin",origin)).andExpect(status().isNoContent());
26
+ mvc.perform(get("/api/records")).andExpect(status().isUnauthorized());
27
+ }
28
+ }