@voltro/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (626) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +57 -0
  3. package/README.md +26 -0
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +20236 -0
  6. package/bin/voltro.mjs +43 -0
  7. package/dist/bin.d.ts +1 -0
  8. package/dist/bin.js +9 -0
  9. package/dist/commands-CfPH2Wf4.js +18061 -0
  10. package/dist/frameworkInspectState-CX2250XB.js +86 -0
  11. package/dist/index.d.ts +48 -0
  12. package/dist/index.js +5 -0
  13. package/dist/inspectState.d.ts +116 -0
  14. package/dist/inspectState.js +2 -0
  15. package/dist/startup.d.ts +26 -0
  16. package/dist/startup.js +2 -0
  17. package/dist/startupRunner-CRhuUl91.js +71 -0
  18. package/package.json +88 -0
  19. package/templates/AGENTS.core.md +258 -0
  20. package/templates/AGENTS.md +351 -0
  21. package/templates/agent-docs/_index.md +93 -0
  22. package/templates/agent-docs/_manifest.json +655 -0
  23. package/templates/agent-docs/ai.md +1845 -0
  24. package/templates/agent-docs/authentication.md +1788 -0
  25. package/templates/agent-docs/caching.md +624 -0
  26. package/templates/agent-docs/cli.md +1650 -0
  27. package/templates/agent-docs/configuration.md +295 -0
  28. package/templates/agent-docs/data.md +2172 -0
  29. package/templates/agent-docs/database/advancedqueries.md +1583 -0
  30. package/templates/agent-docs/database/columntypes.md +1200 -0
  31. package/templates/agent-docs/database/hosting.md +881 -0
  32. package/templates/agent-docs/database/migrations.md +2938 -0
  33. package/templates/agent-docs/database/misc.md +270 -0
  34. package/templates/agent-docs/database/overview.md +108 -0
  35. package/templates/agent-docs/database/querying.md +1622 -0
  36. package/templates/agent-docs/database/scaling.md +331 -0
  37. package/templates/agent-docs/database/schema.md +1458 -0
  38. package/templates/agent-docs/database/seedsdialects.md +1235 -0
  39. package/templates/agent-docs/database/transactions.md +285 -0
  40. package/templates/agent-docs/deployment.md +999 -0
  41. package/templates/agent-docs/internationalization.md +359 -0
  42. package/templates/agent-docs/introduction.md +438 -0
  43. package/templates/agent-docs/multi-tenancy.md +610 -0
  44. package/templates/agent-docs/observability.md +350 -0
  45. package/templates/agent-docs/plugins.md +1273 -0
  46. package/templates/agent-docs/reference.md +978 -0
  47. package/templates/agent-docs/routing.md +1553 -0
  48. package/templates/agent-docs/scheduling.md +666 -0
  49. package/templates/agent-docs/schema-driven-ui.md +607 -0
  50. package/templates/agent-docs/security.md +42 -0
  51. package/templates/agent-docs/templates/apibackends.md +3214 -0
  52. package/templates/agent-docs/templates/appshells.md +2062 -0
  53. package/templates/agent-docs/templates/custom.md +128 -0
  54. package/templates/agent-docs/templates/overview.md +122 -0
  55. package/templates/agent-docs/templates/serverless.md +315 -0
  56. package/templates/agent-docs/testing.md +376 -0
  57. package/templates/agent-docs/workflows.md +1351 -0
  58. package/templates/apps/api-ai/README.md +105 -0
  59. package/templates/apps/api-ai/actions/summarize.action.server.tsx +32 -0
  60. package/templates/apps/api-ai/actions/summarize.action.ts +33 -0
  61. package/templates/apps/api-ai/agents/support.agent.server.tsx +31 -0
  62. package/templates/apps/api-ai/agents/support.agent.tsx +27 -0
  63. package/templates/apps/api-ai/app.config.ts +57 -0
  64. package/templates/apps/api-ai/database/schema.ts +67 -0
  65. package/templates/apps/api-ai/package.json +27 -0
  66. package/templates/apps/api-ai/seeds/docs.seed.ts +67 -0
  67. package/templates/apps/api-ai/template.json +6 -0
  68. package/templates/apps/api-ai/tests/summarize.test.ts +50 -0
  69. package/templates/apps/api-ai/tools/searchDocs.tool.tsx +60 -0
  70. package/templates/apps/api-ai/tsconfig.json +5 -0
  71. package/templates/apps/api-auth/.env +17 -0
  72. package/templates/apps/api-auth/README.md +109 -0
  73. package/templates/apps/api-auth/actions/me.action.server.ts +20 -0
  74. package/templates/apps/api-auth/actions/me.action.ts +19 -0
  75. package/templates/apps/api-auth/app.config.ts +59 -0
  76. package/templates/apps/api-auth/database/schema.ts +26 -0
  77. package/templates/apps/api-auth/package.json +28 -0
  78. package/templates/apps/api-auth/template.json +6 -0
  79. package/templates/apps/api-auth/tests/me.test.ts +37 -0
  80. package/templates/apps/api-auth/tsconfig.json +5 -0
  81. package/templates/apps/api-backend/README.md +25 -0
  82. package/templates/apps/api-backend/app.config.ts +39 -0
  83. package/templates/apps/api-backend/database/schema.ts +57 -0
  84. package/templates/apps/api-backend/mutations/notes.create.mutation.server.ts +19 -0
  85. package/templates/apps/api-backend/mutations/notes.create.mutation.ts +37 -0
  86. package/templates/apps/api-backend/package.json +28 -0
  87. package/templates/apps/api-backend/queries/notes.query.server.ts +14 -0
  88. package/templates/apps/api-backend/queries/notes.query.ts +20 -0
  89. package/templates/apps/api-backend/template.json +6 -0
  90. package/templates/apps/api-backend/tests/notes.create.test.ts +50 -0
  91. package/templates/apps/api-backend/tsconfig.json +5 -0
  92. package/templates/apps/api-backend-deactivation/README.md +49 -0
  93. package/templates/apps/api-backend-deactivation/actions/users.get.action.server.ts +17 -0
  94. package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +18 -0
  95. package/templates/apps/api-backend-deactivation/app.config.ts +20 -0
  96. package/templates/apps/api-backend-deactivation/database/schema.ts +41 -0
  97. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.server.ts +6 -0
  98. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +16 -0
  99. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.server.ts +10 -0
  100. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +19 -0
  101. package/templates/apps/api-backend-deactivation/package.json +28 -0
  102. package/templates/apps/api-backend-deactivation/template.json +6 -0
  103. package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +47 -0
  104. package/templates/apps/api-backend-deactivation/tsconfig.json +5 -0
  105. package/templates/apps/api-backend-mail/README.md +39 -0
  106. package/templates/apps/api-backend-mail/actions/sendWelcome.action.server.ts +15 -0
  107. package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +21 -0
  108. package/templates/apps/api-backend-mail/app.config.ts +34 -0
  109. package/templates/apps/api-backend-mail/database/schema.ts +57 -0
  110. package/templates/apps/api-backend-mail/emails/welcome.email.tsx +106 -0
  111. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.server.ts +19 -0
  112. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +37 -0
  113. package/templates/apps/api-backend-mail/package.json +30 -0
  114. package/templates/apps/api-backend-mail/queries/notes.query.server.ts +14 -0
  115. package/templates/apps/api-backend-mail/queries/notes.query.ts +20 -0
  116. package/templates/apps/api-backend-mail/template.json +6 -0
  117. package/templates/apps/api-backend-mail/tests/notes.create.test.ts +50 -0
  118. package/templates/apps/api-backend-mail/tsconfig.json +5 -0
  119. package/templates/apps/api-backend-mariadb/.env.example +35 -0
  120. package/templates/apps/api-backend-mariadb/README.md +31 -0
  121. package/templates/apps/api-backend-mariadb/app.config.ts +68 -0
  122. package/templates/apps/api-backend-mariadb/database/schema.ts +57 -0
  123. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.server.ts +19 -0
  124. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +37 -0
  125. package/templates/apps/api-backend-mariadb/package.json +30 -0
  126. package/templates/apps/api-backend-mariadb/queries/notes.query.server.ts +14 -0
  127. package/templates/apps/api-backend-mariadb/queries/notes.query.ts +20 -0
  128. package/templates/apps/api-backend-mariadb/template.json +6 -0
  129. package/templates/apps/api-backend-mariadb/tests/notes.create.test.ts +50 -0
  130. package/templates/apps/api-backend-mariadb/tsconfig.json +5 -0
  131. package/templates/apps/api-backend-storage/README.md +86 -0
  132. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.server.ts +21 -0
  133. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +21 -0
  134. package/templates/apps/api-backend-storage/actions/uploadDocument.action.server.ts +21 -0
  135. package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +20 -0
  136. package/templates/apps/api-backend-storage/app.config.ts +38 -0
  137. package/templates/apps/api-backend-storage/database/schema.ts +57 -0
  138. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.server.ts +19 -0
  139. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +37 -0
  140. package/templates/apps/api-backend-storage/package.json +27 -0
  141. package/templates/apps/api-backend-storage/queries/notes.query.server.ts +14 -0
  142. package/templates/apps/api-backend-storage/queries/notes.query.ts +20 -0
  143. package/templates/apps/api-backend-storage/template.json +6 -0
  144. package/templates/apps/api-backend-storage/tests/notes.create.test.ts +50 -0
  145. package/templates/apps/api-backend-storage/tsconfig.json +5 -0
  146. package/templates/apps/api-data-advanced/.env +17 -0
  147. package/templates/apps/api-data-advanced/README.md +88 -0
  148. package/templates/apps/api-data-advanced/app.config.ts +56 -0
  149. package/templates/apps/api-data-advanced/database/actors.entity.ts +14 -0
  150. package/templates/apps/api-data-advanced/database/authors.entity.ts +30 -0
  151. package/templates/apps/api-data-advanced/database/authors.relations.ts +15 -0
  152. package/templates/apps/api-data-advanced/database/books.entity.ts +59 -0
  153. package/templates/apps/api-data-advanced/database/books.relations.ts +10 -0
  154. package/templates/apps/api-data-advanced/database/index.ts +23 -0
  155. package/templates/apps/api-data-advanced/database/tenants.entity.ts +11 -0
  156. package/templates/apps/api-data-advanced/package.json +28 -0
  157. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.server.ts +18 -0
  158. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +40 -0
  159. package/templates/apps/api-data-advanced/queries/books.search.query.server.ts +17 -0
  160. package/templates/apps/api-data-advanced/queries/books.search.query.ts +39 -0
  161. package/templates/apps/api-data-advanced/seeds/catalog.seed.ts +101 -0
  162. package/templates/apps/api-data-advanced/template.json +6 -0
  163. package/templates/apps/api-data-advanced/tests/queries.test.ts +124 -0
  164. package/templates/apps/api-data-advanced/tsconfig.json +5 -0
  165. package/templates/apps/api-durable/README.md +81 -0
  166. package/templates/apps/api-durable/aggregates/orderStats.aggregate.ts +49 -0
  167. package/templates/apps/api-durable/app.config.ts +41 -0
  168. package/templates/apps/api-durable/database/schema.ts +65 -0
  169. package/templates/apps/api-durable/mutations/orders.approve.mutation.server.ts +43 -0
  170. package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +23 -0
  171. package/templates/apps/api-durable/mutations/orders.place.mutation.server.ts +45 -0
  172. package/templates/apps/api-durable/mutations/orders.place.mutation.ts +40 -0
  173. package/templates/apps/api-durable/package.json +28 -0
  174. package/templates/apps/api-durable/schedules/nightlyReport.cron.tsx +37 -0
  175. package/templates/apps/api-durable/startup/warm.startup.tsx +33 -0
  176. package/templates/apps/api-durable/subscribers/orderChanges.subscribe.ts +27 -0
  177. package/templates/apps/api-durable/template.json +6 -0
  178. package/templates/apps/api-durable/tests/orders.place.test.ts +91 -0
  179. package/templates/apps/api-durable/triggers/order.placed.trigger.tsx +21 -0
  180. package/templates/apps/api-durable/tsconfig.json +5 -0
  181. package/templates/apps/api-durable/workflows/order.fulfill.workflow.server.tsx +103 -0
  182. package/templates/apps/api-durable/workflows/order.fulfill.workflow.tsx +25 -0
  183. package/templates/apps/api-feature-flags/README.md +63 -0
  184. package/templates/apps/api-feature-flags/actions/notes.export.action.server.ts +11 -0
  185. package/templates/apps/api-feature-flags/actions/notes.export.action.ts +18 -0
  186. package/templates/apps/api-feature-flags/app.config.ts +41 -0
  187. package/templates/apps/api-feature-flags/database/schema.ts +37 -0
  188. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.server.ts +29 -0
  189. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +28 -0
  190. package/templates/apps/api-feature-flags/package.json +29 -0
  191. package/templates/apps/api-feature-flags/template.json +6 -0
  192. package/templates/apps/api-feature-flags/tests/notes.create.test.ts +67 -0
  193. package/templates/apps/api-feature-flags/tsconfig.json +5 -0
  194. package/templates/apps/api-governance/.env +4 -0
  195. package/templates/apps/api-governance/README.md +61 -0
  196. package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -0
  197. package/templates/apps/api-governance/actions/profiles.get.action.ts +17 -0
  198. package/templates/apps/api-governance/app.config.ts +35 -0
  199. package/templates/apps/api-governance/database/schema.ts +41 -0
  200. package/templates/apps/api-governance/mutations/profiles.create.mutation.server.ts +17 -0
  201. package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +21 -0
  202. package/templates/apps/api-governance/package.json +29 -0
  203. package/templates/apps/api-governance/template.json +6 -0
  204. package/templates/apps/api-governance/tests/profiles.create.test.ts +59 -0
  205. package/templates/apps/api-governance/tsconfig.json +5 -0
  206. package/templates/apps/api-kv/README.md +100 -0
  207. package/templates/apps/api-kv/actions/sync.pull.action.server.ts +75 -0
  208. package/templates/apps/api-kv/actions/sync.pull.action.ts +25 -0
  209. package/templates/apps/api-kv/actions/sync.reset.action.server.ts +25 -0
  210. package/templates/apps/api-kv/actions/sync.reset.action.ts +22 -0
  211. package/templates/apps/api-kv/actions/sync.status.action.server.ts +28 -0
  212. package/templates/apps/api-kv/actions/sync.status.action.ts +17 -0
  213. package/templates/apps/api-kv/app.config.ts +48 -0
  214. package/templates/apps/api-kv/database/schema.ts +62 -0
  215. package/templates/apps/api-kv/package.json +28 -0
  216. package/templates/apps/api-kv/queries/events.list.query.server.ts +14 -0
  217. package/templates/apps/api-kv/queries/events.list.query.ts +23 -0
  218. package/templates/apps/api-kv/template.json +6 -0
  219. package/templates/apps/api-kv/tests/sync.test.ts +103 -0
  220. package/templates/apps/api-kv/tsconfig.json +5 -0
  221. package/templates/apps/api-moderation/README.md +46 -0
  222. package/templates/apps/api-moderation/app.config.ts +33 -0
  223. package/templates/apps/api-moderation/database/schema.ts +45 -0
  224. package/templates/apps/api-moderation/mutations/comments.create.mutation.server.ts +8 -0
  225. package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +20 -0
  226. package/templates/apps/api-moderation/mutations/posts.create.mutation.server.ts +9 -0
  227. package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +25 -0
  228. package/templates/apps/api-moderation/package.json +29 -0
  229. package/templates/apps/api-moderation/template.json +6 -0
  230. package/templates/apps/api-moderation/tests/posts.create.test.ts +79 -0
  231. package/templates/apps/api-moderation/tsconfig.json +5 -0
  232. package/templates/apps/api-observability/README.md +106 -0
  233. package/templates/apps/api-observability/app.config.ts +32 -0
  234. package/templates/apps/api-observability/database/schema.ts +38 -0
  235. package/templates/apps/api-observability/mutations/notes.create.mutation.server.ts +33 -0
  236. package/templates/apps/api-observability/mutations/notes.create.mutation.ts +15 -0
  237. package/templates/apps/api-observability/package.json +29 -0
  238. package/templates/apps/api-observability/queries/notes.list.query.server.ts +7 -0
  239. package/templates/apps/api-observability/queries/notes.list.query.ts +14 -0
  240. package/templates/apps/api-observability/template.json +6 -0
  241. package/templates/apps/api-observability/tests/notes.create.test.ts +36 -0
  242. package/templates/apps/api-observability/tsconfig.json +5 -0
  243. package/templates/apps/api-ratelimit/README.md +49 -0
  244. package/templates/apps/api-ratelimit/app.config.ts +42 -0
  245. package/templates/apps/api-ratelimit/database/schema.ts +37 -0
  246. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.server.ts +16 -0
  247. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +34 -0
  248. package/templates/apps/api-ratelimit/package.json +29 -0
  249. package/templates/apps/api-ratelimit/template.json +6 -0
  250. package/templates/apps/api-ratelimit/tests/notes.create.test.ts +69 -0
  251. package/templates/apps/api-ratelimit/tsconfig.json +5 -0
  252. package/templates/apps/api-rbac/README.md +59 -0
  253. package/templates/apps/api-rbac/app.config.ts +48 -0
  254. package/templates/apps/api-rbac/database/schema.ts +37 -0
  255. package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +22 -0
  256. package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +26 -0
  257. package/templates/apps/api-rbac/package.json +29 -0
  258. package/templates/apps/api-rbac/template.json +6 -0
  259. package/templates/apps/api-rbac/tests/notes.create.test.ts +80 -0
  260. package/templates/apps/api-rbac/tsconfig.json +5 -0
  261. package/templates/apps/api-rest/README.md +85 -0
  262. package/templates/apps/api-rest/app.config.ts +70 -0
  263. package/templates/apps/api-rest/database/schema.ts +52 -0
  264. package/templates/apps/api-rest/lib/product.ts +30 -0
  265. package/templates/apps/api-rest/package.json +27 -0
  266. package/templates/apps/api-rest/routes/v1/products.create.route.tsx +45 -0
  267. package/templates/apps/api-rest/routes/v1/products.delete.route.tsx +25 -0
  268. package/templates/apps/api-rest/routes/v1/products.get.route.tsx +29 -0
  269. package/templates/apps/api-rest/routes/v1/products.list.route.tsx +43 -0
  270. package/templates/apps/api-rest/template.json +6 -0
  271. package/templates/apps/api-rest/tests/products.create.test.ts +53 -0
  272. package/templates/apps/api-rest/tsconfig.json +5 -0
  273. package/templates/apps/api-saas/README.md +106 -0
  274. package/templates/apps/api-saas/app.config.ts +51 -0
  275. package/templates/apps/api-saas/database/schema.ts +50 -0
  276. package/templates/apps/api-saas/mutations/projects.create.mutation.server.ts +52 -0
  277. package/templates/apps/api-saas/mutations/projects.create.mutation.ts +18 -0
  278. package/templates/apps/api-saas/package.json +31 -0
  279. package/templates/apps/api-saas/queries/projects.list.query.server.ts +7 -0
  280. package/templates/apps/api-saas/queries/projects.list.query.ts +18 -0
  281. package/templates/apps/api-saas/template.json +6 -0
  282. package/templates/apps/api-saas/tests/projects.create.test.ts +47 -0
  283. package/templates/apps/api-saas/tsconfig.json +5 -0
  284. package/templates/apps/api-search/README.md +68 -0
  285. package/templates/apps/api-search/app.config.ts +31 -0
  286. package/templates/apps/api-search/database/schema.ts +47 -0
  287. package/templates/apps/api-search/lib/search.ts +27 -0
  288. package/templates/apps/api-search/mutations/articles.create.mutation.server.ts +19 -0
  289. package/templates/apps/api-search/mutations/articles.create.mutation.ts +35 -0
  290. package/templates/apps/api-search/package.json +29 -0
  291. package/templates/apps/api-search/queries/articles.list.query.server.ts +14 -0
  292. package/templates/apps/api-search/queries/articles.list.query.ts +19 -0
  293. package/templates/apps/api-search/seeds/articles.seed.ts +41 -0
  294. package/templates/apps/api-search/startup/searchBackfill.startup.tsx +24 -0
  295. package/templates/apps/api-search/template.json +6 -0
  296. package/templates/apps/api-search/tests/articles.create.test.ts +69 -0
  297. package/templates/apps/api-search/tsconfig.json +5 -0
  298. package/templates/apps/api-versioning/README.md +51 -0
  299. package/templates/apps/api-versioning/actions/documents.asOf.action.server.ts +13 -0
  300. package/templates/apps/api-versioning/actions/documents.asOf.action.ts +14 -0
  301. package/templates/apps/api-versioning/actions/documents.history.action.server.ts +15 -0
  302. package/templates/apps/api-versioning/actions/documents.history.action.ts +17 -0
  303. package/templates/apps/api-versioning/app.config.ts +24 -0
  304. package/templates/apps/api-versioning/database/schema.ts +38 -0
  305. package/templates/apps/api-versioning/mutations/documents.create.mutation.server.ts +8 -0
  306. package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +21 -0
  307. package/templates/apps/api-versioning/mutations/documents.update.mutation.server.ts +9 -0
  308. package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +21 -0
  309. package/templates/apps/api-versioning/package.json +29 -0
  310. package/templates/apps/api-versioning/template.json +6 -0
  311. package/templates/apps/api-versioning/tests/documents.create.test.ts +37 -0
  312. package/templates/apps/api-versioning/tsconfig.json +5 -0
  313. package/templates/apps/api-webhooks/.env +6 -0
  314. package/templates/apps/api-webhooks/README.md +106 -0
  315. package/templates/apps/api-webhooks/app.config.ts +16 -0
  316. package/templates/apps/api-webhooks/database/schema.ts +49 -0
  317. package/templates/apps/api-webhooks/events/order.completed.webhook.tsx +22 -0
  318. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.server.ts +37 -0
  319. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +15 -0
  320. package/templates/apps/api-webhooks/package.json +28 -0
  321. package/templates/apps/api-webhooks/queries/orders.list.query.server.ts +7 -0
  322. package/templates/apps/api-webhooks/queries/orders.list.query.ts +15 -0
  323. package/templates/apps/api-webhooks/template.json +6 -0
  324. package/templates/apps/api-webhooks/tests/orders.fulfill.test.ts +51 -0
  325. package/templates/apps/api-webhooks/tsconfig.json +5 -0
  326. package/templates/apps/api-webhooks/webhooks/orders.webhook.tsx +35 -0
  327. package/templates/apps/changelog/README.md +77 -0
  328. package/templates/apps/changelog/app.config.ts +27 -0
  329. package/templates/apps/changelog/content/releases/0.1.0.mdx +19 -0
  330. package/templates/apps/changelog/content/releases/0.2.0.mdx +28 -0
  331. package/templates/apps/changelog/package.json +30 -0
  332. package/templates/apps/changelog/scripts/generate-rss.mjs +38 -0
  333. package/templates/apps/changelog/src/globals.css +66 -0
  334. package/templates/apps/changelog/src/globals.d.ts +16 -0
  335. package/templates/apps/changelog/src/lib/locale.test.ts +72 -0
  336. package/templates/apps/changelog/src/lib/locale.ts +55 -0
  337. package/templates/apps/changelog/src/lib/releases.ts +21 -0
  338. package/templates/apps/changelog/src/locales/de.ts +22 -0
  339. package/templates/apps/changelog/src/locales/en.ts +30 -0
  340. package/templates/apps/changelog/src/pages/[locale]/[slug].tsx +24 -0
  341. package/templates/apps/changelog/src/pages/[locale]/index.tsx +13 -0
  342. package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +95 -0
  343. package/templates/apps/changelog/src/pages/[slug].test.tsx +127 -0
  344. package/templates/apps/changelog/src/pages/[slug].tsx +52 -0
  345. package/templates/apps/changelog/src/pages/index.test.tsx +112 -0
  346. package/templates/apps/changelog/src/pages/index.tsx +55 -0
  347. package/templates/apps/changelog/src/pages/layout.tsx +84 -0
  348. package/templates/apps/changelog/template.json +6 -0
  349. package/templates/apps/changelog/tsconfig.json +11 -0
  350. package/templates/apps/edge-functions/README.md +55 -0
  351. package/templates/apps/edge-functions/functions/aiComplete.serverless.ts +58 -0
  352. package/templates/apps/edge-functions/functions/currencyConvert.serverless.ts +47 -0
  353. package/templates/apps/edge-functions/functions/geoGreeting.serverless.ts +44 -0
  354. package/templates/apps/edge-functions/functions/health.serverless.ts +29 -0
  355. package/templates/apps/edge-functions/functions/resolveLink.serverless.ts +32 -0
  356. package/templates/apps/edge-functions/functions/shareLink.serverless.ts +30 -0
  357. package/templates/apps/edge-functions/functions/slackNotify.serverless.ts +40 -0
  358. package/templates/apps/edge-functions/functions/verifySignature.serverless.ts +52 -0
  359. package/templates/apps/edge-functions/package.json +21 -0
  360. package/templates/apps/edge-functions/template.json +6 -0
  361. package/templates/apps/edge-functions/tsconfig.json +10 -0
  362. package/templates/apps/frontend-admin/README.md +40 -0
  363. package/templates/apps/frontend-admin/app.config.ts +37 -0
  364. package/templates/apps/frontend-admin/package.json +30 -0
  365. package/templates/apps/frontend-admin/src/config.ts +8 -0
  366. package/templates/apps/frontend-admin/src/globals.css +76 -0
  367. package/templates/apps/frontend-admin/src/globals.d.ts +6 -0
  368. package/templates/apps/frontend-admin/src/lib/admin.ts +16 -0
  369. package/templates/apps/frontend-admin/src/lib/auth.ts +24 -0
  370. package/templates/apps/frontend-admin/src/locales/de.ts +67 -0
  371. package/templates/apps/frontend-admin/src/locales/en.ts +79 -0
  372. package/templates/apps/frontend-admin/src/locales/index.ts +15 -0
  373. package/templates/apps/frontend-admin/src/pages/(marketing)/index.test.tsx +55 -0
  374. package/templates/apps/frontend-admin/src/pages/(marketing)/index.tsx +32 -0
  375. package/templates/apps/frontend-admin/src/pages/(marketing)/layout.tsx +29 -0
  376. package/templates/apps/frontend-admin/src/pages/(marketing)/login.test.tsx +73 -0
  377. package/templates/apps/frontend-admin/src/pages/(marketing)/login.tsx +35 -0
  378. package/templates/apps/frontend-admin/src/pages/admin/[entity].tsx +121 -0
  379. package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +119 -0
  380. package/templates/apps/frontend-admin/src/pages/admin/error.tsx +20 -0
  381. package/templates/apps/frontend-admin/src/pages/admin/fallbacks.test.tsx +68 -0
  382. package/templates/apps/frontend-admin/src/pages/admin/index.test.tsx +88 -0
  383. package/templates/apps/frontend-admin/src/pages/admin/index.tsx +65 -0
  384. package/templates/apps/frontend-admin/src/pages/admin/layout.test.tsx +114 -0
  385. package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +97 -0
  386. package/templates/apps/frontend-admin/src/pages/admin/loading.tsx +15 -0
  387. package/templates/apps/frontend-admin/src/pages/admin/not-found.tsx +15 -0
  388. package/templates/apps/frontend-admin/src/pages/layout.tsx +12 -0
  389. package/templates/apps/frontend-admin/src/pages/layouts.test.tsx +54 -0
  390. package/templates/apps/frontend-admin/template.json +6 -0
  391. package/templates/apps/frontend-admin/tsconfig.json +11 -0
  392. package/templates/apps/frontend-app/README.md +98 -0
  393. package/templates/apps/frontend-app/app.config.ts +43 -0
  394. package/templates/apps/frontend-app/package.json +30 -0
  395. package/templates/apps/frontend-app/src/locales/de.ts +36 -0
  396. package/templates/apps/frontend-app/src/locales/en.ts +43 -0
  397. package/templates/apps/frontend-app/src/locales/index.ts +15 -0
  398. package/templates/apps/frontend-app/src/pages/index.test.tsx +167 -0
  399. package/templates/apps/frontend-app/src/pages/index.tsx +136 -0
  400. package/templates/apps/frontend-app/src/pages/layout.tsx +41 -0
  401. package/templates/apps/frontend-app/src/pages/schema-ui.test.tsx +99 -0
  402. package/templates/apps/frontend-app/src/pages/schema-ui.tsx +74 -0
  403. package/templates/apps/frontend-app/template.json +6 -0
  404. package/templates/apps/frontend-app/tsconfig.json +11 -0
  405. package/templates/apps/frontend-blank/README.md +18 -0
  406. package/templates/apps/frontend-blank/app.config.ts +29 -0
  407. package/templates/apps/frontend-blank/package.json +29 -0
  408. package/templates/apps/frontend-blank/src/locales/de.ts +15 -0
  409. package/templates/apps/frontend-blank/src/locales/en.ts +22 -0
  410. package/templates/apps/frontend-blank/src/locales/index.ts +15 -0
  411. package/templates/apps/frontend-blank/src/pages/index.test.tsx +55 -0
  412. package/templates/apps/frontend-blank/src/pages/index.tsx +27 -0
  413. package/templates/apps/frontend-blank/src/pages/layout.test.tsx +54 -0
  414. package/templates/apps/frontend-blank/src/pages/layout.tsx +35 -0
  415. package/templates/apps/frontend-blank/template.json +6 -0
  416. package/templates/apps/frontend-blank/tsconfig.json +11 -0
  417. package/templates/apps/frontend-contact/README.md +65 -0
  418. package/templates/apps/frontend-contact/app.config.ts +25 -0
  419. package/templates/apps/frontend-contact/functions/sendMessage.serverless.ts +69 -0
  420. package/templates/apps/frontend-contact/package.json +33 -0
  421. package/templates/apps/frontend-contact/src/components/ContactForm.island.test.tsx +142 -0
  422. package/templates/apps/frontend-contact/src/components/ContactForm.island.tsx +104 -0
  423. package/templates/apps/frontend-contact/src/config.ts +12 -0
  424. package/templates/apps/frontend-contact/src/globals.css +84 -0
  425. package/templates/apps/frontend-contact/src/lib/locale.ts +55 -0
  426. package/templates/apps/frontend-contact/src/locales/de.ts +26 -0
  427. package/templates/apps/frontend-contact/src/locales/en.ts +29 -0
  428. package/templates/apps/frontend-contact/src/pages/[locale]/index.tsx +14 -0
  429. package/templates/apps/frontend-contact/src/pages/index.test.tsx +70 -0
  430. package/templates/apps/frontend-contact/src/pages/index.tsx +63 -0
  431. package/templates/apps/frontend-contact/src/pages/layout.tsx +65 -0
  432. package/templates/apps/frontend-contact/template.json +6 -0
  433. package/templates/apps/frontend-contact/tsconfig.json +11 -0
  434. package/templates/apps/frontend-dashboard/README.md +54 -0
  435. package/templates/apps/frontend-dashboard/app.config.ts +39 -0
  436. package/templates/apps/frontend-dashboard/package.json +29 -0
  437. package/templates/apps/frontend-dashboard/src/config.ts +8 -0
  438. package/templates/apps/frontend-dashboard/src/globals.css +72 -0
  439. package/templates/apps/frontend-dashboard/src/globals.d.ts +6 -0
  440. package/templates/apps/frontend-dashboard/src/lib/auth.ts +27 -0
  441. package/templates/apps/frontend-dashboard/src/locales/de.ts +49 -0
  442. package/templates/apps/frontend-dashboard/src/locales/en.ts +60 -0
  443. package/templates/apps/frontend-dashboard/src/locales/index.ts +15 -0
  444. package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.test.tsx +55 -0
  445. package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.tsx +34 -0
  446. package/templates/apps/frontend-dashboard/src/pages/(marketing)/layout.tsx +32 -0
  447. package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.test.tsx +74 -0
  448. package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.tsx +40 -0
  449. package/templates/apps/frontend-dashboard/src/pages/dashboard/error.tsx +21 -0
  450. package/templates/apps/frontend-dashboard/src/pages/dashboard/fallbacks.test.tsx +68 -0
  451. package/templates/apps/frontend-dashboard/src/pages/dashboard/index.test.tsx +55 -0
  452. package/templates/apps/frontend-dashboard/src/pages/dashboard/index.tsx +38 -0
  453. package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.test.tsx +88 -0
  454. package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.tsx +69 -0
  455. package/templates/apps/frontend-dashboard/src/pages/dashboard/loading.tsx +21 -0
  456. package/templates/apps/frontend-dashboard/src/pages/dashboard/not-found.tsx +19 -0
  457. package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.test.tsx +69 -0
  458. package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.tsx +35 -0
  459. package/templates/apps/frontend-dashboard/src/pages/layout.tsx +12 -0
  460. package/templates/apps/frontend-dashboard/src/pages/layouts.test.tsx +54 -0
  461. package/templates/apps/frontend-dashboard/template.json +6 -0
  462. package/templates/apps/frontend-dashboard/tsconfig.json +11 -0
  463. package/templates/apps/frontend-docs/README.md +19 -0
  464. package/templates/apps/frontend-docs/app.config.ts +25 -0
  465. package/templates/apps/frontend-docs/package.json +29 -0
  466. package/templates/apps/frontend-docs/src/globals.css +32 -0
  467. package/templates/apps/frontend-docs/src/lib/locale.test.ts +72 -0
  468. package/templates/apps/frontend-docs/src/lib/locale.ts +56 -0
  469. package/templates/apps/frontend-docs/src/locales/de.ts +24 -0
  470. package/templates/apps/frontend-docs/src/locales/en.ts +28 -0
  471. package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug].tsx +18 -0
  472. package/templates/apps/frontend-docs/src/pages/[locale]/index.tsx +13 -0
  473. package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +67 -0
  474. package/templates/apps/frontend-docs/src/pages/docs/[...slug].test.tsx +115 -0
  475. package/templates/apps/frontend-docs/src/pages/docs/[...slug].tsx +82 -0
  476. package/templates/apps/frontend-docs/src/pages/index.test.tsx +90 -0
  477. package/templates/apps/frontend-docs/src/pages/index.tsx +45 -0
  478. package/templates/apps/frontend-docs/src/pages/layout.test.tsx +84 -0
  479. package/templates/apps/frontend-docs/src/pages/layout.tsx +66 -0
  480. package/templates/apps/frontend-docs/template.json +6 -0
  481. package/templates/apps/frontend-docs/tsconfig.json +11 -0
  482. package/templates/apps/frontend-i18n/README.md +61 -0
  483. package/templates/apps/frontend-i18n/app.config.ts +33 -0
  484. package/templates/apps/frontend-i18n/package.json +28 -0
  485. package/templates/apps/frontend-i18n/src/globals.css +46 -0
  486. package/templates/apps/frontend-i18n/src/globals.d.ts +6 -0
  487. package/templates/apps/frontend-i18n/src/lib/locale.test.ts +72 -0
  488. package/templates/apps/frontend-i18n/src/lib/locale.ts +55 -0
  489. package/templates/apps/frontend-i18n/src/locales/de.ts +24 -0
  490. package/templates/apps/frontend-i18n/src/locales/en.ts +25 -0
  491. package/templates/apps/frontend-i18n/src/pages/[locale]/about.tsx +11 -0
  492. package/templates/apps/frontend-i18n/src/pages/[locale]/index.tsx +13 -0
  493. package/templates/apps/frontend-i18n/src/pages/[locale]/mirrors.test.tsx +50 -0
  494. package/templates/apps/frontend-i18n/src/pages/about.test.tsx +75 -0
  495. package/templates/apps/frontend-i18n/src/pages/about.tsx +31 -0
  496. package/templates/apps/frontend-i18n/src/pages/index.test.tsx +102 -0
  497. package/templates/apps/frontend-i18n/src/pages/index.tsx +43 -0
  498. package/templates/apps/frontend-i18n/src/pages/layout.test.tsx +86 -0
  499. package/templates/apps/frontend-i18n/src/pages/layout.tsx +70 -0
  500. package/templates/apps/frontend-i18n/template.json +6 -0
  501. package/templates/apps/frontend-i18n/tsconfig.json +11 -0
  502. package/templates/apps/frontend-landing/README.md +17 -0
  503. package/templates/apps/frontend-landing/app.config.ts +25 -0
  504. package/templates/apps/frontend-landing/package.json +29 -0
  505. package/templates/apps/frontend-landing/src/globals.css +23 -0
  506. package/templates/apps/frontend-landing/src/lib/locale.test.ts +72 -0
  507. package/templates/apps/frontend-landing/src/lib/locale.ts +55 -0
  508. package/templates/apps/frontend-landing/src/locales/de.ts +24 -0
  509. package/templates/apps/frontend-landing/src/locales/en.ts +26 -0
  510. package/templates/apps/frontend-landing/src/pages/[locale]/index.tsx +13 -0
  511. package/templates/apps/frontend-landing/src/pages/[locale]/mirrors.test.tsx +37 -0
  512. package/templates/apps/frontend-landing/src/pages/index.test.tsx +110 -0
  513. package/templates/apps/frontend-landing/src/pages/index.tsx +75 -0
  514. package/templates/apps/frontend-landing/src/pages/layout.test.tsx +84 -0
  515. package/templates/apps/frontend-landing/src/pages/layout.tsx +66 -0
  516. package/templates/apps/frontend-landing/template.json +6 -0
  517. package/templates/apps/frontend-landing/tsconfig.json +11 -0
  518. package/templates/apps/frontend-spa/README.md +45 -0
  519. package/templates/apps/frontend-spa/app.config.ts +27 -0
  520. package/templates/apps/frontend-spa/package.json +29 -0
  521. package/templates/apps/frontend-spa/src/globals.css +84 -0
  522. package/templates/apps/frontend-spa/src/locales/de.ts +22 -0
  523. package/templates/apps/frontend-spa/src/locales/en.ts +29 -0
  524. package/templates/apps/frontend-spa/src/locales/index.ts +15 -0
  525. package/templates/apps/frontend-spa/src/pages/index.test.tsx +137 -0
  526. package/templates/apps/frontend-spa/src/pages/index.tsx +123 -0
  527. package/templates/apps/frontend-spa/src/pages/layout.tsx +27 -0
  528. package/templates/apps/frontend-spa/template.json +6 -0
  529. package/templates/apps/frontend-spa/tsconfig.json +11 -0
  530. package/templates/apps/frontend-ssr/README.md +68 -0
  531. package/templates/apps/frontend-ssr/app.config.ts +32 -0
  532. package/templates/apps/frontend-ssr/package.json +29 -0
  533. package/templates/apps/frontend-ssr/src/globals.css +67 -0
  534. package/templates/apps/frontend-ssr/src/locales/de.ts +41 -0
  535. package/templates/apps/frontend-ssr/src/locales/en.ts +54 -0
  536. package/templates/apps/frontend-ssr/src/locales/index.ts +16 -0
  537. package/templates/apps/frontend-ssr/src/pages/feed-swr.test.tsx +69 -0
  538. package/templates/apps/frontend-ssr/src/pages/feed-swr.tsx +54 -0
  539. package/templates/apps/frontend-ssr/src/pages/feed.test.tsx +73 -0
  540. package/templates/apps/frontend-ssr/src/pages/feed.tsx +64 -0
  541. package/templates/apps/frontend-ssr/src/pages/index.test.tsx +89 -0
  542. package/templates/apps/frontend-ssr/src/pages/index.tsx +72 -0
  543. package/templates/apps/frontend-ssr/src/pages/layout.tsx +37 -0
  544. package/templates/apps/frontend-ssr/template.json +6 -0
  545. package/templates/apps/frontend-ssr/tsconfig.json +11 -0
  546. package/templates/apps/frontend-ssr-api/README.md +50 -0
  547. package/templates/apps/frontend-ssr-api/app.config.ts +43 -0
  548. package/templates/apps/frontend-ssr-api/package.json +30 -0
  549. package/templates/apps/frontend-ssr-api/src/globals.css +38 -0
  550. package/templates/apps/frontend-ssr-api/src/globals.d.ts +6 -0
  551. package/templates/apps/frontend-ssr-api/src/locales/de.ts +20 -0
  552. package/templates/apps/frontend-ssr-api/src/locales/en.ts +31 -0
  553. package/templates/apps/frontend-ssr-api/src/locales/index.ts +16 -0
  554. package/templates/apps/frontend-ssr-api/src/pages/index.test.tsx +105 -0
  555. package/templates/apps/frontend-ssr-api/src/pages/index.tsx +83 -0
  556. package/templates/apps/frontend-ssr-api/src/pages/layout.tsx +28 -0
  557. package/templates/apps/frontend-ssr-api/template.json +6 -0
  558. package/templates/apps/frontend-ssr-api/tsconfig.json +11 -0
  559. package/templates/apps/frontend-static-blog/README.md +49 -0
  560. package/templates/apps/frontend-static-blog/app.config.ts +34 -0
  561. package/templates/apps/frontend-static-blog/package.json +28 -0
  562. package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.test.tsx +65 -0
  563. package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.tsx +35 -0
  564. package/templates/apps/frontend-static-blog/src/content/posts.ts +64 -0
  565. package/templates/apps/frontend-static-blog/src/globals.css +75 -0
  566. package/templates/apps/frontend-static-blog/src/lib/locale.test.ts +72 -0
  567. package/templates/apps/frontend-static-blog/src/lib/locale.ts +55 -0
  568. package/templates/apps/frontend-static-blog/src/locales/de.ts +19 -0
  569. package/templates/apps/frontend-static-blog/src/locales/en.ts +26 -0
  570. package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug].tsx +20 -0
  571. package/templates/apps/frontend-static-blog/src/pages/[locale]/index.tsx +13 -0
  572. package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +62 -0
  573. package/templates/apps/frontend-static-blog/src/pages/blog/[slug].test.tsx +116 -0
  574. package/templates/apps/frontend-static-blog/src/pages/blog/[slug].tsx +69 -0
  575. package/templates/apps/frontend-static-blog/src/pages/index.test.tsx +100 -0
  576. package/templates/apps/frontend-static-blog/src/pages/index.tsx +58 -0
  577. package/templates/apps/frontend-static-blog/src/pages/layout.tsx +63 -0
  578. package/templates/apps/frontend-static-blog/template.json +6 -0
  579. package/templates/apps/frontend-static-blog/tsconfig.json +11 -0
  580. package/templates/baselines/bare/.env.example +37 -0
  581. package/templates/baselines/bare/README.md +47 -0
  582. package/templates/baselines/bare/baseline.json +31 -0
  583. package/templates/baselines/bare/deploy/README.md +43 -0
  584. package/templates/baselines/bare/deploy/voltro.service.example +36 -0
  585. package/templates/baselines/compose/.env.example +46 -0
  586. package/templates/baselines/compose/README.md +69 -0
  587. package/templates/baselines/compose/baseline.json +51 -0
  588. package/templates/baselines/compose/docker/.dockerignore +38 -0
  589. package/templates/baselines/compose/docker/api.Dockerfile +57 -0
  590. package/templates/baselines/compose/docker/dev.Dockerfile +35 -0
  591. package/templates/baselines/compose/docker/web.Dockerfile +59 -0
  592. package/templates/baselines/compose/docker-compose.dev.yml +89 -0
  593. package/templates/baselines/compose/docker-compose.prod.yml +87 -0
  594. package/templates/baselines/compose/docker-compose.yml +41 -0
  595. package/templates/baselines/compose-mariadb/.env.example +57 -0
  596. package/templates/baselines/compose-mariadb/README.md +78 -0
  597. package/templates/baselines/compose-mariadb/baseline.json +51 -0
  598. package/templates/baselines/compose-mariadb/docker/.dockerignore +38 -0
  599. package/templates/baselines/compose-mariadb/docker/api.Dockerfile +57 -0
  600. package/templates/baselines/compose-mariadb/docker/dev.Dockerfile +35 -0
  601. package/templates/baselines/compose-mariadb/docker/mariadb-init.sql +6 -0
  602. package/templates/baselines/compose-mariadb/docker/web.Dockerfile +59 -0
  603. package/templates/baselines/compose-mariadb/docker-compose.dev.yml +117 -0
  604. package/templates/baselines/compose-mariadb/docker-compose.prod.yml +114 -0
  605. package/templates/baselines/compose-mariadb/docker-compose.yml +79 -0
  606. package/templates/baselines/helm/.env.example +39 -0
  607. package/templates/baselines/helm/README.md +98 -0
  608. package/templates/baselines/helm/baseline.json +53 -0
  609. package/templates/baselines/helm/charts/voltro-app/.helmignore +10 -0
  610. package/templates/baselines/helm/charts/voltro-app/Chart.yaml +10 -0
  611. package/templates/baselines/helm/charts/voltro-app/templates/_helpers.tpl +36 -0
  612. package/templates/baselines/helm/charts/voltro-app/templates/configmap.yaml +13 -0
  613. package/templates/baselines/helm/charts/voltro-app/templates/deployment-api.yaml +120 -0
  614. package/templates/baselines/helm/charts/voltro-app/templates/deployment-web.yaml +45 -0
  615. package/templates/baselines/helm/charts/voltro-app/templates/ingress.yaml +37 -0
  616. package/templates/baselines/helm/charts/voltro-app/templates/postgres-service.yaml +19 -0
  617. package/templates/baselines/helm/charts/voltro-app/templates/postgres-statefulset.yaml +73 -0
  618. package/templates/baselines/helm/charts/voltro-app/templates/secret.yaml +33 -0
  619. package/templates/baselines/helm/charts/voltro-app/templates/service-api.yaml +19 -0
  620. package/templates/baselines/helm/charts/voltro-app/templates/service-web.yaml +19 -0
  621. package/templates/baselines/helm/charts/voltro-app/values-dev.yaml +21 -0
  622. package/templates/baselines/helm/charts/voltro-app/values-prod.yaml +58 -0
  623. package/templates/baselines/helm/charts/voltro-app/values-staging.yaml +25 -0
  624. package/templates/baselines/helm/charts/voltro-app/values.yaml +109 -0
  625. package/templates/baselines/helm/deploy/README.md +94 -0
  626. package/templates/patches/@effect__cluster@0.59.0.patch +262 -0
@@ -0,0 +1,88 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/admin` overview — renders one card per discovered entity (from the api
4
+ // capability map), an error banner if the map can't be reached, and a skeleton
5
+ // while loading. We mock @voltro/client so the three states are driveable.
6
+
7
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
8
+ import { act, createElement, type ReactNode } from 'react'
9
+ import { createRoot, type Root } from 'react-dom/client'
10
+ import { I18nProvider } from '@voltro/i18n'
11
+ import enCatalog from '../../locales/en'
12
+
13
+ interface ManifestState { manifest: unknown; loading: boolean; error?: unknown }
14
+ const capabilityManifest = vi.fn<() => ManifestState>()
15
+ const entityAdmins = vi.fn<() => Array<Record<string, unknown>>>()
16
+
17
+ vi.mock('@voltro/client', () => ({
18
+ useCapabilityManifest: () => capabilityManifest(),
19
+ deriveEntityAdmins: () => entityAdmins(),
20
+ }))
21
+
22
+ const { default: AdminOverview, meta, renderMode } = await import('./index')
23
+
24
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
25
+
26
+ let container: HTMLDivElement
27
+ let root: Root
28
+
29
+ // AdminOverview uses <T>, so wrap renders in the framework's <I18nProvider>.
30
+ const render = (node: ReactNode): void => {
31
+ container = document.createElement('div')
32
+ document.body.appendChild(container)
33
+ act(() => {
34
+ root = createRoot(container)
35
+ root.render(
36
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
37
+ )
38
+ })
39
+ }
40
+
41
+ beforeEach(() => {
42
+ capabilityManifest.mockReset()
43
+ entityAdmins.mockReset()
44
+ })
45
+
46
+ afterEach(() => {
47
+ if (root) act(() => root.unmount())
48
+ container?.remove()
49
+ document.body.innerHTML = ''
50
+ })
51
+
52
+ describe('admin overview — config', () => {
53
+ test('is an SSR page titled Overview', () => {
54
+ expect(renderMode).toBe('ssr')
55
+ expect(meta({ locale: 'en' }).title).toBe('Overview')
56
+ })
57
+ })
58
+
59
+ describe('admin overview — render', () => {
60
+ test('renders a linked card per entity with its column count and ops', () => {
61
+ capabilityManifest.mockReturnValue({ manifest: {}, loading: false })
62
+ entityAdmins.mockReturnValue([
63
+ { table: 'todos', columns: ['id', 'title'], reactive: true, listTag: 'todos.list', createTag: 'todos.create' },
64
+ { table: 'notes', columns: ['id'], reactive: false, listTag: 'notes.list' },
65
+ ])
66
+
67
+ render(createElement(AdminOverview))
68
+ const cards = Array.from(container.querySelectorAll('a.card'))
69
+ expect(cards.map((c) => c.getAttribute('href'))).toEqual(['/admin/todos', '/admin/notes'])
70
+ expect(container.textContent).toContain('2 columns · reactive')
71
+ expect(container.textContent).toContain('1 column')
72
+ expect(container.textContent).toContain('list · create')
73
+ })
74
+
75
+ test('shows the error banner when the capability map is unreachable', () => {
76
+ capabilityManifest.mockReturnValue({ manifest: undefined, loading: false, error: 'boom' })
77
+ entityAdmins.mockReturnValue([])
78
+ render(createElement(AdminOverview))
79
+ expect(container.querySelector('.banner')!.textContent).toContain('Couldn’t reach')
80
+ })
81
+
82
+ test('shows skeleton cards while the manifest is loading', () => {
83
+ capabilityManifest.mockReturnValue({ manifest: undefined, loading: true })
84
+ entityAdmins.mockReturnValue([])
85
+ render(createElement(AdminOverview))
86
+ expect(container.querySelectorAll('.skeleton').length).toBeGreaterThan(0)
87
+ })
88
+ })
@@ -0,0 +1,65 @@
1
+ // Admin overview — URL `/admin`. `renderMode: 'ssr'` so the parent layout's
2
+ // auth gate runs per request. Renders one card per discovered entity, each
3
+ // linking to its CRUD page. The whole list comes from the api's capability map
4
+ // — there's no hard-coded entity list.
5
+ import type { ReactNode } from 'react'
6
+ import type { PageMeta } from '@voltro/web'
7
+ import { useCapabilityManifest, deriveEntityAdmins } from '@voltro/client'
8
+ import { T } from '@voltro/i18n'
9
+ import { getCatalog } from '../../locales'
10
+
11
+ export const renderMode = 'ssr' as const
12
+
13
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
14
+ title: getCatalog(locale)['meta.overview.title'],
15
+ })
16
+
17
+ export default function AdminOverview(): ReactNode {
18
+ const { manifest, loading, error } = useCapabilityManifest('app')
19
+ const entities = manifest ? deriveEntityAdmins(manifest) : []
20
+
21
+ return (
22
+ <section>
23
+ <h1><T id="overview.heading" /></h1>
24
+ <p className="muted">
25
+ <T id="overview.intro" values={{ code: (c: ReactNode) => <code>{c}</code> }} />
26
+ </p>
27
+
28
+ {error ? (
29
+ <p className="banner" style={{ marginTop: '1rem' }}>
30
+ <T id="overview.error" />
31
+ </p>
32
+ ) : null}
33
+
34
+ {loading && entities.length === 0 ? (
35
+ <div className="cards" style={{ marginTop: '1.25rem' }} aria-hidden="true">
36
+ <div className="skeleton" /><div className="skeleton" /><div className="skeleton" />
37
+ </div>
38
+ ) : (
39
+ <div className="cards" style={{ marginTop: '1.25rem' }}>
40
+ {entities.map((e) => {
41
+ const ops = [
42
+ e.listTag && 'list',
43
+ e.createTag && 'create',
44
+ e.updateTag && 'edit',
45
+ e.deleteTag && 'delete',
46
+ ].filter(Boolean)
47
+ return (
48
+ <a className="card" key={e.table} href={`/admin/${e.table}`}>
49
+ <div className="value">{e.table}</div>
50
+ <div className="label">
51
+ <T id="overview.columns" values={{ count: e.columns.length }} />
52
+ {e.reactive ? <T id="overview.reactiveSuffix" /> : null}
53
+ </div>
54
+ <div className="meta">{ops.length > 0 ? ops.join(' · ') : <T id="overview.readonly" />}</div>
55
+ </a>
56
+ )
57
+ })}
58
+ {entities.length === 0 && !loading ? (
59
+ <p className="muted"><T id="overview.empty" /></p>
60
+ ) : null}
61
+ </div>
62
+ )}
63
+ </section>
64
+ )
65
+ }
@@ -0,0 +1,114 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // The admin shell + AUTH GATE. The loader redirects an unauthenticated request
4
+ // and otherwise returns the shared user. The rendered shell derives its nav
5
+ // from the api capability map (useCapabilityManifest + deriveEntityAdmins) and
6
+ // wraps an undo/redo bar (useUndoLog). We mock @voltro/client so those hooks are
7
+ // deterministic, mock the framework hooks, and import the REAL RedirectError.
8
+
9
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
10
+ import { act, createElement, type ReactNode } from 'react'
11
+ import { createRoot, type Root } from 'react-dom/client'
12
+ import { RedirectError } from '@voltro/web'
13
+ import { I18nProvider } from '@voltro/i18n'
14
+ import enCatalog from '../../locales/en'
15
+
16
+ const loaderData = vi.fn<() => unknown>()
17
+ const location = vi.fn<() => string>()
18
+
19
+ vi.mock('@voltro/web', async () => {
20
+ const actual = await vi.importActual<typeof import('@voltro/web')>('@voltro/web')
21
+ return { ...actual, useLoaderData: () => loaderData(), useLocation: () => location() }
22
+ })
23
+
24
+ interface ManifestState { manifest: unknown; loading: boolean }
25
+ const capabilityManifest = vi.fn<() => ManifestState>()
26
+ const entityAdmins = vi.fn<() => Array<{ table: string }>>()
27
+ const undoLog = vi.fn(() => ({
28
+ canUndo: false,
29
+ canRedo: false,
30
+ undoLast: vi.fn(),
31
+ redoLast: vi.fn(),
32
+ }))
33
+
34
+ vi.mock('@voltro/client', () => ({
35
+ useCapabilityManifest: () => capabilityManifest(),
36
+ deriveEntityAdmins: () => entityAdmins(),
37
+ useUndoLog: () => undoLog(),
38
+ PermissionProvider: ({ children }: { children?: ReactNode }) => children,
39
+ }))
40
+
41
+ const { default: AdminLayout, loader } = await import('./layout')
42
+
43
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
44
+
45
+ let container: HTMLDivElement
46
+ let root: Root
47
+
48
+ // AdminLayout uses <T>/useLocale + <LocaleSwitcher>, so wrap renders in the
49
+ // framework's <I18nProvider> (auto-wired in the running app).
50
+ const render = (node: ReactNode): void => {
51
+ container = document.createElement('div')
52
+ document.body.appendChild(container)
53
+ act(() => {
54
+ root = createRoot(container)
55
+ root.render(
56
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
57
+ )
58
+ })
59
+ }
60
+
61
+ beforeEach(() => {
62
+ loaderData.mockReset()
63
+ location.mockReset()
64
+ capabilityManifest.mockReset()
65
+ entityAdmins.mockReset()
66
+ undoLog.mockClear()
67
+ })
68
+
69
+ afterEach(() => {
70
+ if (root) act(() => root.unmount())
71
+ container?.remove()
72
+ document.body.innerHTML = ''
73
+ })
74
+
75
+ describe('admin layout — loader (auth gate)', () => {
76
+ test('redirects to /login (remembering the destination) when unauthenticated', async () => {
77
+ const err = await Promise.resolve(loader({ headers: {} } as never)).catch((e: unknown) => e)
78
+ expect(err).toBeInstanceOf(RedirectError)
79
+ expect((err as RedirectError).location).toBe('/login?from=/admin')
80
+ })
81
+
82
+ test('returns the shared user for a signed-in request', async () => {
83
+ const data = await loader({ headers: { cookie: 'demo_session=ok' } } as never)
84
+ expect(data.user.name).toBe('Demo Admin')
85
+ })
86
+ })
87
+
88
+ describe('admin layout — render', () => {
89
+ test('renders a nav item per discovered entity plus the Overview link', () => {
90
+ loaderData.mockReturnValue({ user: { name: 'Root Admin' } })
91
+ location.mockReturnValue('/admin')
92
+ capabilityManifest.mockReturnValue({ manifest: {}, loading: false })
93
+ entityAdmins.mockReturnValue([{ table: 'todos' }, { table: 'projects' }])
94
+
95
+ render(createElement(AdminLayout, { children: createElement('p', null, 'admin body') }))
96
+
97
+ expect(container.textContent).toContain('Root Admin')
98
+ const hrefs = Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
99
+ expect(hrefs).toContain('/admin')
100
+ expect(hrefs).toContain('/admin/todos')
101
+ expect(hrefs).toContain('/admin/projects')
102
+ expect(container.querySelector('main')!.textContent).toContain('admin body')
103
+ })
104
+
105
+ test('shows the discovering hint before the manifest arrives', () => {
106
+ loaderData.mockReturnValue({ user: { name: 'Root Admin' } })
107
+ location.mockReturnValue('/admin')
108
+ capabilityManifest.mockReturnValue({ manifest: undefined, loading: true })
109
+ entityAdmins.mockReturnValue([])
110
+
111
+ render(createElement(AdminLayout, { children: null }))
112
+ expect(container.textContent).toContain('discovering…')
113
+ })
114
+ })
@@ -0,0 +1,97 @@
1
+ // The admin shell — and the AUTH GATE. This nested layout wraps every page
2
+ // under `/admin`, and its `loader` runs server-side BEFORE the page renders, so
3
+ // it's the right seam to validate the session. Throwing RedirectError
4
+ // short-circuits the subtree (303 + Location on SSR; replace-nav on the client).
5
+ // Pages under here are `renderMode: 'ssr'` so the gate runs per request.
6
+ //
7
+ // The sidebar is DRIVEN BY THE API'S CAPABILITY MAP: useCapabilityManifest +
8
+ // deriveEntityAdmins discover every entity at runtime, so point the admin at any
9
+ // api and the nav adapts — no per-entity code. The undo bar wraps the
10
+ // __voltro.undo.* built-ins (requires undo capture on; the dev default).
11
+ import type { ReactNode } from 'react'
12
+ import { RedirectError, useLoaderData, useLocation, type LoaderFn } from '@voltro/web'
13
+ import {
14
+ useCapabilityManifest,
15
+ deriveEntityAdmins,
16
+ useUndoLog,
17
+ PermissionProvider,
18
+ } from '@voltro/client'
19
+ import { T, useLocale, useT } from '@voltro/i18n'
20
+ import { LocaleSwitcher } from '@voltro/ui-shadcn'
21
+ import { APP_NAME } from '../../config'
22
+ import { isSignedIn } from '../../lib/auth'
23
+ import { DEMO_SCOPES } from '../../lib/admin'
24
+
25
+ const LOCALES = [
26
+ { code: 'en', label: 'English' },
27
+ { code: 'de', label: 'Deutsch' },
28
+ ]
29
+
30
+ export const renderMode = 'ssr' as const
31
+
32
+ interface AdminData {
33
+ readonly user: { readonly name: string }
34
+ }
35
+
36
+ export const loader: LoaderFn<AdminData> = async ({ headers }) => {
37
+ if (!isSignedIn(headers)) {
38
+ throw new RedirectError('/login?from=/admin')
39
+ }
40
+ return { user: { name: 'Demo Admin' } }
41
+ }
42
+
43
+ // The undo bar — split out so a deployment running with VOLTRO_UNDO=off (no
44
+ // __voltro.undo.* built-ins) can delete just these lines.
45
+ const UndoBar = (): ReactNode => {
46
+ const undo = useUndoLog('app')
47
+ return (
48
+ <>
49
+ <button type="button" className="btn ghost" disabled={!undo.canUndo} onClick={() => void undo.undoLast()}>
50
+ <T id="admin.undo" />
51
+ </button>
52
+ <button type="button" className="btn ghost" disabled={!undo.canRedo} onClick={() => void undo.redoLast()}>
53
+ <T id="admin.redo" />
54
+ </button>
55
+ </>
56
+ )
57
+ }
58
+
59
+ export default function AdminLayout({ children }: { readonly children: ReactNode }): ReactNode {
60
+ const { user } = useLoaderData<AdminData>()
61
+ const pathname = useLocation()
62
+ const locale = useLocale()
63
+ const langLabel = useT('lang.label')
64
+ const { manifest, loading } = useCapabilityManifest('app')
65
+ const entities = manifest ? deriveEntityAdmins(manifest) : []
66
+
67
+ const navItem = (href: string, label: ReactNode): ReactNode => (
68
+ <a key={href} href={href} aria-current={pathname === href ? 'page' : undefined}>{label}</a>
69
+ )
70
+
71
+ return (
72
+ // PermissionProvider feeds the current subject's scopes to useCan across the
73
+ // admin. DEMO scopes here — swap for your session's scopes (see lib/admin.ts).
74
+ <PermissionProvider scopes={DEMO_SCOPES}>
75
+ <div className="admin">
76
+ <aside>
77
+ <div className="brand">{APP_NAME}</div>
78
+ <nav>
79
+ {navItem('/admin', <T id="admin.nav.overview" />)}
80
+ {loading && entities.length === 0 ? <span className="muted" style={{ padding: '0.35rem 0.6rem', fontSize: '0.85rem' }}><T id="admin.nav.discovering" /></span> : null}
81
+ {entities.map((e) => navItem(`/admin/${e.table}`, e.table))}
82
+ <a href="/"><T id="admin.nav.backToSite" /></a>
83
+ </nav>
84
+ </aside>
85
+ <main>
86
+ <div className="topbar">
87
+ <strong>{user.name}</strong>
88
+ <span className="spacer" />
89
+ <UndoBar />
90
+ <LocaleSwitcher locales={LOCALES} current={locale} ariaLabel={langLabel} />
91
+ </div>
92
+ {children}
93
+ </main>
94
+ </div>
95
+ </PermissionProvider>
96
+ )
97
+ }
@@ -0,0 +1,15 @@
1
+ // OPT-IN loading skeleton for /admin pages. Suits a data-backed admin where the
2
+ // loader (auth gate) + the first capability-map fetch take a beat.
3
+ import type { ReactNode } from 'react'
4
+
5
+ export default function AdminLoading(): ReactNode {
6
+ return (
7
+ <div className="admin">
8
+ <main>
9
+ <div className="cards" aria-hidden="true">
10
+ <div className="skeleton" /><div className="skeleton" /><div className="skeleton" />
11
+ </div>
12
+ </main>
13
+ </div>
14
+ )
15
+ }
@@ -0,0 +1,15 @@
1
+ // Scoped 404 for the /admin subtree (e.g. /admin/nope when no page matches).
2
+ import type { ReactNode } from 'react'
3
+ import { T } from '@voltro/i18n'
4
+
5
+ export default function AdminNotFound(): ReactNode {
6
+ return (
7
+ <div className="admin">
8
+ <main>
9
+ <h1><T id="notFound.heading" /></h1>
10
+ <p className="muted"><T id="notFound.body" /></p>
11
+ <p style={{ marginTop: '1rem' }}><a href="/admin"><T id="notFound.back" /></a></p>
12
+ </main>
13
+ </div>
14
+ )
15
+ }
@@ -0,0 +1,12 @@
1
+ // Root layout — wraps EVERY page (marketing + admin). Intentionally thin: it
2
+ // loads the stylesheet and lets each AREA layout ((marketing)/layout.tsx,
3
+ // admin/layout.tsx) supply its own chrome. Layouts nest, so an admin page is
4
+ // wrapped root → admin.
5
+ //
6
+ // Don't render <html>/<head>/<body> here — the framework shell owns them.
7
+ import type { ReactNode } from 'react'
8
+ import '../globals.css'
9
+
10
+ export default function RootLayout({ children }: { readonly children: ReactNode }): ReactNode {
11
+ return <>{children}</>
12
+ }
@@ -0,0 +1,54 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // Render smokes for the root layout (passes children through) and the
4
+ // (marketing) group layout (brand header + nav links wrapping the children).
5
+
6
+ import { afterEach, describe, expect, test } from 'vitest'
7
+ import { act, createElement, type ReactNode } from 'react'
8
+ import { createRoot, type Root } from 'react-dom/client'
9
+ import { I18nProvider } from '@voltro/i18n'
10
+ import enCatalog from '../locales/en'
11
+
12
+ const { default: RootLayout } = await import('./layout')
13
+ const { default: MarketingLayout } = await import('./(marketing)/layout')
14
+
15
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
16
+
17
+ let container: HTMLDivElement
18
+ let root: Root
19
+
20
+ // MarketingLayout uses <T>/useLocale + <LocaleSwitcher>, so wrap renders in the
21
+ // framework's <I18nProvider> (auto-wired in the running app).
22
+ const render = (node: ReactNode): void => {
23
+ container = document.createElement('div')
24
+ document.body.appendChild(container)
25
+ act(() => {
26
+ root = createRoot(container)
27
+ root.render(
28
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
29
+ )
30
+ })
31
+ }
32
+
33
+ afterEach(() => {
34
+ if (root) act(() => root.unmount())
35
+ container?.remove()
36
+ document.body.innerHTML = ''
37
+ })
38
+
39
+ describe('root layout', () => {
40
+ test('renders its children unchanged', () => {
41
+ render(createElement(RootLayout, { children: createElement('p', null, 'hello') }))
42
+ expect(container.textContent).toContain('hello')
43
+ })
44
+ })
45
+
46
+ describe('marketing layout', () => {
47
+ test('renders the header nav (Admin + Sign in) around the children', () => {
48
+ render(createElement(MarketingLayout, { children: createElement('p', null, 'body') }))
49
+ const hrefs = Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
50
+ expect(hrefs).toContain('/admin')
51
+ expect(hrefs).toContain('/login')
52
+ expect(container.textContent).toContain('body')
53
+ })
54
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "frontend-admin",
3
+ "kind": "web",
4
+ "summary": "An auto-admin back-office that DISCOVERS your api's entities at runtime (capability map) and renders a live, reactive <DataTable> + <AutoForm> per entity — permission-gated with useCan, with a per-row provenance drawer and universal undo/redo. Editable template code, not a sealed generated cage. Pairs with any api: scaffold both with `create-project --api=api-backend --web=frontend-admin`.",
5
+ "tags": ["web", "frontend", "admin", "back-office", "schema-driven", "datatable", "autoform", "rbac", "undo", "provenance", "reactive"]
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "lib": ["ES2024", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "moduleResolution": "Bundler"
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist", ".framework"]
11
+ }
@@ -0,0 +1,98 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro frontend scaffold (template: **frontend-app**).
4
+
5
+ The **reactive end-to-end loop** — the framework's headline feature, in one
6
+ page. A live notes list (`useSubscription`) plus a create form
7
+ (`useMutation`) with **zero-boilerplate auto-optimistic** updates. This is the
8
+ only template that wires a web frontend to an api; every other `frontend-*`
9
+ template is backend-less.
10
+
11
+ ## Scaffold the pair
12
+
13
+ `frontend-app` consumes a sibling api — it is meant to be scaffolded **together
14
+ with [`api-backend`](../api-backend)** (which exposes the `notes.list` query +
15
+ `notes.create` mutation this page subscribes to / calls):
16
+
17
+ ```bash
18
+ voltro create-project demo --api=api-backend --web=frontend-app
19
+ cd demo
20
+ pnpm install
21
+ pnpm dev # boots BOTH apps (api on :4000, web on its portRange port)
22
+ ```
23
+
24
+ Open the web app, add a note, and watch it appear in the list **instantly** —
25
+ no refetch, no polling. Open a second browser tab: a note added in one tab
26
+ shows up live in the other.
27
+
28
+ ## How the loop works
29
+
30
+ ```
31
+ Browser api (api-backend)
32
+ ─────── ─────────────────
33
+ useSubscription('app', notes.list (defineQuery, source: 'notes')
34
+ 'notes.list') ───WS────► └─ streams a fresh snapshot/delta on every
35
+ ▲ write to the tenant's `notes` rows
36
+ │ delta (WebSocket)
37
+
38
+ useMutation('app', notes.create (defineMutation,
39
+ 'notes.create') ──rpc──► target: { table:'notes', op:'insert' })
40
+ .mutate({...}) └─ one atomic DB write → commit → delta
41
+ ```
42
+
43
+ 1. **`useSubscription('app', 'notes.list')`** opens ONE live WebSocket
44
+ subscription. `data` is the current rows; it re-renders whenever the
45
+ `notes` table changes — from THIS tab, another tab, a workflow, or an
46
+ out-of-band DB write.
47
+ 2. **`useMutation('app', 'notes.create').mutate({...})`** invokes the
48
+ mutation. Because the descriptor declares `target: { table:'notes',
49
+ op:'insert' }`, the framework **auto-prepends an optimistic row** to the
50
+ subscription the instant you submit — then replaces it with the real row
51
+ (or reverts it) when the rpc resolves. No `.withOptimistic`, no
52
+ `useOptimistic`, no `startTransition`.
53
+
54
+ Optimistic rows carry `optimistic: true`; the page renders them faintly until
55
+ the server delta supersedes them (see `src/pages/index.tsx`).
56
+
57
+ ## The `apis` wiring
58
+
59
+ ```ts
60
+ // app.config.ts
61
+ apis: {
62
+ app: { package: '@{{projectName}}/api' }, // the sibling api in this project
63
+ }
64
+ ```
65
+
66
+ The map key (`'app'`) is the **lookup name** every hook takes as its first
67
+ argument — `useSubscription('app', …)`, `useMutation('app', …)`. The
68
+ `package` resolves the sibling api workspace package; its port is
69
+ auto-discovered from its own `app.config.ts`, and codegen pulls its typed rpc
70
+ surface. Consume more apis by adding more entries (each gets its own
71
+ WebSocket + reconnect cycle).
72
+
73
+ ## Files
74
+
75
+ ```
76
+ app.config.ts type:web + the `apis: { app }` wiring
77
+ package.json depends on @{{projectName}}/api (the sibling) + @voltro/client
78
+ src/pages/
79
+ layout.tsx root shell (header + <main>)
80
+ index.tsx the reactive notes page — useSubscription + useMutation
81
+ ```
82
+
83
+ ## Pairing with a different api
84
+
85
+ This page is hard-wired to api-backend's `notes` domain. To point it at your
86
+ own api, change `app.config.ts`'s `apis.app.package`, then swap the rpc tags +
87
+ the `Note` type in `src/pages/index.tsx` to match your query/mutation
88
+ descriptors. The hook shapes (`useSubscription` / `useMutation`) are identical
89
+ for any api.
90
+
91
+ ## Multi-tenancy note
92
+
93
+ The dev `AuthMiddleware` resolves the tenant from the `x-tenant` header,
94
+ defaulting to `'acme'` (the `TENANT` constant in `index.tsx`). The `notes`
95
+ table carries the `tenant()` mixin, so reads are auto-scoped and
96
+ `notes.create` guards that the submitted `tenantId` matches the caller's —
97
+ a typed `TenantMismatch` otherwise. Wire real auth before production (see the
98
+ authentication docs).
@@ -0,0 +1,43 @@
1
+ // Web app for the {{projectName}} project. Read by `voltro dev` / `voltro start`.
2
+ //
3
+ // This is the FULLSTACK template — a web frontend wired to an api so you can
4
+ // see the framework's headline feature: the reactive end-to-end loop. The web
5
+ // client subscribes to a server-side query; when a mutation writes the table,
6
+ // the server pushes a delta over WebSocket and the React tree re-renders. No
7
+ // `refetch`, no polling.
8
+ //
9
+ // `port` is allocated by `voltro create-project` / `voltro add-app` from the
10
+ // project's portRange (in project.json), hard-pinned per app.
11
+ import { defineEnv, envVar } from '@voltro/env'
12
+
13
+ // Typed PUBLIC environment — public vars are validated + baked into the browser
14
+ // bundle at build time and read via `publicEnv` from '@voltro/env/public'.
15
+ // NEVER put a secret here (it ships to every visitor) — declare secrets on the
16
+ // api instead. Run `voltro env` for the manifest.
17
+ export const env = defineEnv({
18
+ VOLTRO_PUBLIC_APP_NAME: envVar.string({ access: 'public', default: '{{capProjectName}}' }),
19
+ })
20
+
21
+ export default {
22
+ type: 'web' as const,
23
+ name: '{{capProjectName}}{{capAppName}}',
24
+ port: {{port}},
25
+ env,
26
+ // Bilingual by default. The framework auto-wires a cookie-driven
27
+ // <I18nProvider> from these codes and loads the matching
28
+ // `src/locales/<code>.ts` catalog — so `<T id="…" />` / `useT()` /
29
+ // `useLocale()` work app-wide with no manual setup. The <LocaleSwitcher>
30
+ // in the layout writes the `voltro:lang` cookie + reloads. Grow the app to
31
+ // more languages by adding a code here + a `src/locales/<code>.ts`.
32
+ locales: ['en', 'de'] as const,
33
+ defaultLocale: 'en' as const,
34
+ // The api this frontend consumes. The NAME ('app') is the lookup key the
35
+ // hooks use — `useSubscription('app', 'notes.list')`, `useMutation('app',
36
+ // 'notes.create')`. The `package` resolves the sibling api in this project
37
+ // (scaffold it with `--api=api-backend`); its port is auto-discovered from
38
+ // its own app.config.ts, and codegen pulls its typed rpc surface so the
39
+ // hooks are end-to-end typed. Add more entries to consume more apis.
40
+ apis: {
41
+ app: { package: '@{{projectName}}/api' },
42
+ },
43
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@{{projectName}}/{{appName}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "voltro dev .",
8
+ "build": "voltro build .",
9
+ "start": "voltro start .",
10
+ "test": "voltro test",
11
+ "typecheck": "tsc --noEmit"
12
+ },
13
+ "dependencies": {
14
+ "@{{projectName}}/api": "0.1.0",
15
+ "@voltro/cli": "0.1.0",
16
+ "@voltro/client": "0.1.0",
17
+ "@voltro/env": "0.1.0",
18
+ "@voltro/i18n": "0.1.0",
19
+ "@voltro/ui-shadcn": "0.1.0",
20
+ "@voltro/web": "0.1.0",
21
+ "react": "^19.0.0",
22
+ "react-dom": "^19.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/react": "^19.0.0",
26
+ "@types/react-dom": "^19.0.0",
27
+ "typescript": "^5.7.0",
28
+ "vitest": "^3.0.0"
29
+ }
30
+ }