@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,29 @@
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
+ "typecheck": "tsc --noEmit",
11
+ "test": "voltro test"
12
+ },
13
+ "dependencies": {
14
+ "@voltro/cli": "0.1.0",
15
+ "@voltro/client": "0.1.0",
16
+ "@voltro/env": "0.1.0",
17
+ "@voltro/i18n": "0.1.0",
18
+ "@voltro/ui-shadcn": "0.1.0",
19
+ "@voltro/web": "0.1.0",
20
+ "react": "^19.0.0",
21
+ "react-dom": "^19.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/react": "^19.0.0",
25
+ "@types/react-dom": "^19.0.0",
26
+ "typescript": "^5.7.0",
27
+ "vitest": "^3.0.0"
28
+ }
29
+ }
@@ -0,0 +1,8 @@
1
+ // The brand name shown in the marketing header + dashboard sidebar.
2
+ //
3
+ // A plain constant — not `publicEnv` — so the template typechecks BEFORE
4
+ // `voltro dev` generates the env types. `VOLTRO_PUBLIC_APP_NAME` is still
5
+ // declared in app.config.ts (validated + in the env manifest); to read it
6
+ // typed instead, after one `voltro dev` swap this for
7
+ // `publicEnv.VOLTRO_PUBLIC_APP_NAME` from '@voltro/env/public'.
8
+ export const APP_NAME = '{{capProjectName}}'
@@ -0,0 +1,72 @@
1
+ /* Plain CSS — no Tailwind, so there's no @source scanner to configure.
2
+ Swap in @voltro/ui-shadcn or Tailwind later if you want; see AGENTS.md. */
3
+ :root {
4
+ --bg: #ffffff;
5
+ --fg: #0a0a0a;
6
+ --muted: #6b7280;
7
+ --accent: #4f46e5;
8
+ --border: #e5e7eb;
9
+ --panel: #f9fafb;
10
+ }
11
+ :root.dark {
12
+ --bg: #0a0a0a;
13
+ --fg: #fafafa;
14
+ --muted: #9ca3af;
15
+ --accent: #818cf8;
16
+ --border: #1f2937;
17
+ --panel: #111827;
18
+ }
19
+
20
+ * { box-sizing: border-box; }
21
+ body {
22
+ margin: 0;
23
+ background: var(--bg);
24
+ color: var(--fg);
25
+ font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
26
+ line-height: 1.55;
27
+ }
28
+ a { color: var(--accent); }
29
+
30
+ /* Marketing */
31
+ .marketing { max-width: 44rem; margin: 0 auto; padding: 2.5rem 1.25rem; }
32
+ .marketing header { display: flex; gap: 1rem; align-items: center; margin-bottom: 2rem; }
33
+ .marketing header .brand { font-weight: 700; }
34
+ .marketing header .spacer { flex: 1; }
35
+ .hero h1 { font-size: 2rem; margin: 0 0 0.5rem; }
36
+ .btn {
37
+ display: inline-block;
38
+ background: var(--accent);
39
+ color: #fff;
40
+ padding: 0.55rem 1rem;
41
+ border-radius: 8px;
42
+ border: 0;
43
+ font: inherit;
44
+ font-weight: 600;
45
+ cursor: pointer;
46
+ text-decoration: none;
47
+ }
48
+
49
+ /* Dashboard shell */
50
+ .dash { display: grid; grid-template-columns: 14rem 1fr; min-height: 100vh; }
51
+ .dash aside {
52
+ border-right: 1px solid var(--border);
53
+ background: var(--panel);
54
+ padding: 1.25rem 1rem;
55
+ }
56
+ .dash aside .brand { font-weight: 700; margin-bottom: 1.25rem; }
57
+ .dash nav { display: flex; flex-direction: column; gap: 0.25rem; }
58
+ .dash nav a { color: var(--fg); text-decoration: none; padding: 0.4rem 0.6rem; border-radius: 6px; }
59
+ .dash nav a:hover { background: color-mix(in oklab, var(--fg) 7%, transparent); }
60
+ .dash nav a[aria-current='page'] { background: color-mix(in oklab, var(--accent) 16%, transparent); color: var(--accent); font-weight: 600; }
61
+ .dash main { padding: 1.75rem; }
62
+ .dash .topbar { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem; }
63
+ .dash .topbar .spacer { flex: 1; }
64
+
65
+ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1rem; }
66
+ .card { border: 1px solid var(--border); border-radius: 10px; padding: 1rem; background: var(--panel); }
67
+ .card .label { color: var(--muted); font-size: 0.8rem; }
68
+ .card .value { font-size: 1.6rem; font-weight: 700; }
69
+
70
+ .muted { color: var(--muted); }
71
+ .skeleton { border: 1px solid var(--border); border-radius: 10px; height: 5rem; background: linear-gradient(90deg, var(--panel), color-mix(in oklab, var(--panel) 60%, var(--bg)), var(--panel)); }
72
+ code { background: color-mix(in oklab, var(--fg) 8%, transparent); padding: 0.1em 0.35em; border-radius: 4px; }
@@ -0,0 +1,6 @@
1
+ // Ambient declarations.
2
+ //
3
+ // `declare module '*.css'`: TypeScript with `moduleResolution: Bundler`
4
+ // rejects a bare `import './globals.css'` unless the asset module is
5
+ // declared. Vite resolves it at build time; the declaration is type-only.
6
+ declare module '*.css'
@@ -0,0 +1,27 @@
1
+ // The demo auth gate. This is intentionally a COOKIE-ONLY stand-in so the
2
+ // template boots with zero backend — `login` writes the cookie, the
3
+ // dashboard layout loader reads it. Swap `isSignedIn` for a real check
4
+ // (verify a signed session, call your api) when you wire auth for real.
5
+
6
+ export const SESSION_COOKIE = 'demo_session'
7
+
8
+ // Browser-safe cookie parse — NO `node:*` import, so it's safe in the page
9
+ // module graph. It runs in BOTH places the gate needs it:
10
+ // - SSR: the loader's `headers['cookie']` (raw Cookie request header)
11
+ // - client nav: `document.cookie` (the loader's `headers` is undefined
12
+ // on the client, so the gate falls back to this)
13
+ export const readCookie = (
14
+ header: string | null | undefined,
15
+ name: string,
16
+ ): string | undefined => {
17
+ if (!header) return undefined
18
+ const match = new RegExp(`(?:^|;\\s*)${name}=([^;]*)`).exec(header)
19
+ return match ? decodeURIComponent(match[1]!) : undefined
20
+ }
21
+
22
+ // `headers` is populated server-side (SSR); on the client it's undefined, so
23
+ // fall back to document.cookie. Either way: is there a session cookie?
24
+ export const isSignedIn = (headers: Record<string, string | undefined> | undefined): boolean => {
25
+ const cookieHeader = headers?.['cookie'] ?? (typeof document === 'undefined' ? '' : document.cookie)
26
+ return readCookie(cookieHeader, SESSION_COOKIE) !== undefined
27
+ }
@@ -0,0 +1,49 @@
1
+ // German catalog. Mirrors every key in `en.ts` — `defineLocale<typeof en>()`
2
+ // fails the build if a key is missing or misspelled. Translate the prose only;
3
+ // keep ICU placeholders (`{plan}`) and rich tags (`<code>`, `<dash>`, `<login>`)
4
+ // identical to `en.ts`.
5
+
6
+ import { defineLocale } from '@voltro/i18n'
7
+ import en from './en'
8
+
9
+ export default defineLocale<typeof en>()({
10
+ 'meta.landing.title': 'Willkommen',
11
+ 'meta.landing.description': 'Ein Voltro-Dashboard-Starter — öffentliche Marketing-Seiten + eine auth-geschützte App-Hülle.',
12
+ 'meta.login.title': 'Anmelden',
13
+ 'meta.overview.title': 'Übersicht',
14
+ 'meta.settings.title': 'Einstellungen',
15
+
16
+ 'nav.dashboard': 'Dashboard',
17
+ 'nav.signIn': 'Anmelden',
18
+ 'lang.label': 'Sprache',
19
+
20
+ 'landing.heading': 'Deine App, mit den lästigen Teilen erledigt.',
21
+ 'landing.body': 'Diese Vorlage liefert einen öffentlichen Marketing-Bereich (eine stille <code>(marketing)</code>-Routengruppe) und einen <code>/dashboard</code>-Bereich, der durch einen Layout-Loader geschützt ist — öffne <dash>/dashboard</dash> im abgemeldeten Zustand und du wirst zu <login>/login</login> weitergeleitet.',
22
+ 'landing.cta': 'Anmelden, um fortzufahren →',
23
+
24
+ 'login.heading': 'Anmelden',
25
+ 'login.body': 'Keine echte Authentifizierung hier — dieser Button setzt lediglich ein Demo-Session-Cookie, damit du siehst, wie das Dashboard-Gate dich durchlässt.',
26
+ 'login.cta': 'Als Demo-Benutzer fortfahren →',
27
+
28
+ 'dash.planSuffix': '· Tarif {plan}',
29
+ 'dash.nav.overview': 'Übersicht',
30
+ 'dash.nav.settings': 'Einstellungen',
31
+ 'dash.nav.backToSite': '← Zurück zur Seite',
32
+
33
+ 'overview.heading': 'Übersicht',
34
+ 'overview.intro': 'Du bist durch das Gate — diese Seite wird nur für angemeldete Besucher gerendert.',
35
+ 'overview.stat.projects': 'Projekte',
36
+ 'overview.stat.members': 'Mitglieder',
37
+ 'overview.stat.issues': 'Offene Vorgänge',
38
+ 'overview.stat.uptime': 'Verfügbarkeit',
39
+
40
+ 'settings.heading': 'Einstellungen',
41
+ 'settings.intro': 'Kontospezifische Einstellungen würden hier stehen.',
42
+ 'settings.signOut': 'Abmelden',
43
+
44
+ 'error.heading': 'Etwas ist schiefgelaufen',
45
+ 'error.retry': 'Erneut versuchen',
46
+ 'notFound.heading': 'Nicht gefunden',
47
+ 'notFound.body': 'Diese Dashboard-Seite existiert nicht.',
48
+ 'notFound.back': '← Zurück zur Übersicht',
49
+ })
@@ -0,0 +1,60 @@
1
+ // Base catalog — the source of truth for this app's UI strings. Every key here
2
+ // MUST be mirrored in `de.ts` (and any other locale); `defineLocale<typeof en>()`
3
+ // enforces that parity at build time, so a missing translation fails typecheck
4
+ // rather than silently falling back.
5
+ //
6
+ // Messages use ICU syntax: `{name}` placeholders, `{n, plural, …}`, and rich
7
+ // tags like `<code>…</code>` (rendered by passing a matching function to
8
+ // `<T values={{ code: (c) => <code>{c}</code> }} />`).
9
+
10
+ import { defineCatalog } from '@voltro/i18n'
11
+
12
+ export default defineCatalog({
13
+ // Browser tab titles + description — locale-aware via each page's `meta({ locale })`.
14
+ 'meta.landing.title': 'Welcome',
15
+ 'meta.landing.description': 'A Voltro dashboard starter — public marketing pages + an auth-gated app shell.',
16
+ 'meta.login.title': 'Sign in',
17
+ 'meta.overview.title': 'Overview',
18
+ 'meta.settings.title': 'Settings',
19
+
20
+ // ---- Marketing header ((marketing)/layout.tsx) ----
21
+ 'nav.dashboard': 'Dashboard',
22
+ 'nav.signIn': 'Sign in',
23
+ 'lang.label': 'Language',
24
+
25
+ // ---- Public landing ((marketing)/index.tsx) ----
26
+ 'landing.heading': 'Your app, with the boring parts done.',
27
+ 'landing.body': 'This template ships a public marketing area (a silent <code>(marketing)</code> route group) and a <code>/dashboard</code> area gated by a layout loader — try opening <dash>/dashboard</dash> while signed out and you’ll be redirected to <login>/login</login>.',
28
+ 'landing.cta': 'Sign in to continue →',
29
+
30
+ // ---- Public sign-in ((marketing)/login.tsx) ----
31
+ 'login.heading': 'Sign in',
32
+ 'login.body': 'No real auth here — this button just sets a demo session cookie so you can see the dashboard gate let you through.',
33
+ 'login.cta': 'Continue as Demo User →',
34
+
35
+ // ---- Dashboard shell (dashboard/layout.tsx) ----
36
+ 'dash.planSuffix': '· {plan} plan',
37
+ 'dash.nav.overview': 'Overview',
38
+ 'dash.nav.settings': 'Settings',
39
+ 'dash.nav.backToSite': '← Back to site',
40
+
41
+ // ---- Dashboard overview (dashboard/index.tsx) ----
42
+ 'overview.heading': 'Overview',
43
+ 'overview.intro': 'You’re past the gate — this page only renders for a signed-in visitor.',
44
+ 'overview.stat.projects': 'Projects',
45
+ 'overview.stat.members': 'Members',
46
+ 'overview.stat.issues': 'Open issues',
47
+ 'overview.stat.uptime': 'Uptime',
48
+
49
+ // ---- Settings (dashboard/settings.tsx) ----
50
+ 'settings.heading': 'Settings',
51
+ 'settings.intro': 'Per-account settings would live here.',
52
+ 'settings.signOut': 'Sign out',
53
+
54
+ // ---- Scoped fallbacks (dashboard/error.tsx, not-found.tsx) ----
55
+ 'error.heading': 'Something went wrong',
56
+ 'error.retry': 'Try again',
57
+ 'notFound.heading': 'Not found',
58
+ 'notFound.body': 'That dashboard page doesn’t exist.',
59
+ 'notFound.back': '← Back to overview',
60
+ } as const)
@@ -0,0 +1,15 @@
1
+ // Catalog lookup OUTSIDE React — for a page's `meta({ locale })` locale-aware
2
+ // <title>. This app is cookie-i18n (no `/<locale>` URL prefix), so @voltro/web
3
+ // hands `meta` the active locale from the `voltro:lang` cookie. Inside React,
4
+ // use `<T>` / `useT()` via the framework's auto-wired <I18nProvider> instead.
5
+
6
+ import en from './en'
7
+ import de from './de'
8
+
9
+ // Both catalogs share `en`'s keys (defineLocale enforces the mirror), so a
10
+ // known-key lookup returns `string` — not `string | undefined` — which is what
11
+ // `PageMeta.title` requires under exactOptionalPropertyTypes.
12
+ export type Messages = Record<keyof typeof en, string>
13
+
14
+ export const getCatalog = (locale?: string): Messages =>
15
+ (locale === 'de' ? de : en) as Messages
@@ -0,0 +1,55 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/` public landing — a static page with fixed content. Assert its render-mode
4
+ // + meta config and the hero copy / links.
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: Landing, meta, renderMode } = await import('./index')
13
+
14
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
15
+
16
+ let container: HTMLDivElement
17
+ let root: Root
18
+
19
+ // The page uses <T>, so it needs an <I18nProvider> (the framework auto-wires
20
+ // this in the running app). Wrap with the real English catalog.
21
+ const render = (node: ReactNode): void => {
22
+ container = document.createElement('div')
23
+ document.body.appendChild(container)
24
+ act(() => {
25
+ root = createRoot(container)
26
+ root.render(
27
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
28
+ )
29
+ })
30
+ }
31
+
32
+ afterEach(() => {
33
+ if (root) act(() => root.unmount())
34
+ container?.remove()
35
+ document.body.innerHTML = ''
36
+ })
37
+
38
+ describe('landing — config', () => {
39
+ test('pre-renders as a static page with title + description meta', () => {
40
+ expect(renderMode).toBe('static')
41
+ expect(meta({ locale: 'en' }).title).toBe('Welcome')
42
+ expect(meta({ locale: 'en' }).description).toContain('marketing')
43
+ })
44
+ })
45
+
46
+ describe('landing — render', () => {
47
+ test('renders the hero heading and a sign-in call to action', () => {
48
+ render(createElement(Landing))
49
+ expect(container.querySelector('h1')!.textContent).toContain('boring parts')
50
+ const cta = Array.from(container.querySelectorAll('a')).find(
51
+ (a) => a.getAttribute('href') === '/login' && (a.textContent ?? '').includes('Sign in'),
52
+ )
53
+ expect(cta).toBeTruthy()
54
+ })
55
+ })
@@ -0,0 +1,34 @@
1
+ // Public landing — URL `/` (the `(marketing)` group is silent). Pure static
2
+ // content, so it pre-renders to flat HTML and ships zero JS by default.
3
+ import type { ReactNode } from 'react'
4
+ import type { PageMeta } from '@voltro/web'
5
+ import { T } from '@voltro/i18n'
6
+ import { getCatalog } from '../../locales'
7
+
8
+ export const renderMode = 'static' as const
9
+
10
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
11
+ title: getCatalog(locale)['meta.landing.title'],
12
+ description: getCatalog(locale)['meta.landing.description'],
13
+ })
14
+
15
+ export default function Landing(): ReactNode {
16
+ return (
17
+ <section className="hero">
18
+ <h1><T id="landing.heading" /></h1>
19
+ <p className="muted">
20
+ <T
21
+ id="landing.body"
22
+ values={{
23
+ code: (c: ReactNode) => <code>{c}</code>,
24
+ dash: (c: ReactNode) => <a href="/dashboard">{c}</a>,
25
+ login: (c: ReactNode) => <a href="/login">{c}</a>,
26
+ }}
27
+ />
28
+ </p>
29
+ <p style={{ marginTop: '1.5rem' }}>
30
+ <a className="btn" href="/login"><T id="landing.cta" /></a>
31
+ </p>
32
+ </section>
33
+ )
34
+ }
@@ -0,0 +1,32 @@
1
+ // Layout for the SILENT route group `(marketing)/`. The parens mean the
2
+ // directory name never appears in a URL — the pages inside are `/` and
3
+ // `/login`, NOT `/(marketing)/...`. A route group exists purely to organise
4
+ // files + scope a shared layout to a set of pages without inventing a URL
5
+ // segment for it. Here it gives the public pages a marketing header/footer
6
+ // distinct from the dashboard's sidebar shell.
7
+ import type { ReactNode } from 'react'
8
+ import { T, useLocale, useT } from '@voltro/i18n'
9
+ import { LocaleSwitcher } from '@voltro/ui-shadcn'
10
+ import { APP_NAME } from '../../config'
11
+
12
+ const LOCALES = [
13
+ { code: 'en', label: 'English' },
14
+ { code: 'de', label: 'Deutsch' },
15
+ ]
16
+
17
+ export default function MarketingLayout({ children }: { readonly children: ReactNode }): ReactNode {
18
+ const locale = useLocale()
19
+ const langLabel = useT('lang.label')
20
+ return (
21
+ <div className="marketing">
22
+ <header>
23
+ <a className="brand" href="/">{APP_NAME}</a>
24
+ <span className="spacer" />
25
+ <a href="/dashboard"><T id="nav.dashboard" /></a>
26
+ <a href="/login"><T id="nav.signIn" /></a>
27
+ <LocaleSwitcher locales={LOCALES} current={locale} ariaLabel={langLabel} />
28
+ </header>
29
+ {children}
30
+ </div>
31
+ )
32
+ }
@@ -0,0 +1,74 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/login` demo sign-in. Clicking "Continue" sets the demo session cookie and
4
+ // navigates to `?from=` (defaulting to /dashboard). We mock useNavigate from
5
+ // @voltro/web and drive the click, asserting cookie + navigation target.
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
+
11
+ import { I18nProvider } from '@voltro/i18n'
12
+ import enCatalog from '../../locales/en'
13
+
14
+ const navigate = vi.fn<(to: string) => void>()
15
+ vi.mock('@voltro/web', () => ({ useNavigate: () => navigate }))
16
+
17
+ const { default: Login, meta, renderMode } = await import('./login')
18
+
19
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
20
+
21
+ let container: HTMLDivElement
22
+ let root: Root
23
+
24
+ // The page uses <T>, so wrap the render in an <I18nProvider> (auto-wired in app).
25
+ const render = (node: ReactNode): void => {
26
+ container = document.createElement('div')
27
+ document.body.appendChild(container)
28
+ act(() => {
29
+ root = createRoot(container)
30
+ root.render(
31
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
32
+ )
33
+ })
34
+ }
35
+
36
+ const clickContinue = (): void => {
37
+ const btn = container.querySelector('button')!
38
+ act(() => { btn.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
39
+ }
40
+
41
+ beforeEach(() => {
42
+ navigate.mockReset()
43
+ // Clear any stale cookie between tests.
44
+ document.cookie = 'demo_session=; path=/; max-age=0'
45
+ })
46
+
47
+ afterEach(() => {
48
+ if (root) act(() => root.unmount())
49
+ container?.remove()
50
+ document.body.innerHTML = ''
51
+ })
52
+
53
+ describe('login — config', () => {
54
+ test('is a static page titled Sign in', () => {
55
+ expect(renderMode).toBe('static')
56
+ expect(meta({ locale: 'en' }).title).toBe('Sign in')
57
+ })
58
+ })
59
+
60
+ describe('login — sign in', () => {
61
+ test('sets the session cookie and navigates to /dashboard by default', () => {
62
+ render(createElement(Login))
63
+ clickContinue()
64
+ expect(document.cookie).toContain('demo_session=ok')
65
+ expect(navigate).toHaveBeenCalledWith('/dashboard')
66
+ })
67
+
68
+ test('honours the ?from= redirect target', () => {
69
+ window.history.replaceState({}, '', '/login?from=/dashboard/settings')
70
+ render(createElement(Login))
71
+ clickContinue()
72
+ expect(navigate).toHaveBeenCalledWith('/dashboard/settings')
73
+ })
74
+ })
@@ -0,0 +1,40 @@
1
+ // Public sign-in page — URL `/login`. The shell pre-renders (`static`) and
2
+ // hydrates for the button. This is a DEMO login: it just writes the cookie
3
+ // the dashboard gate looks for. A real app POSTs credentials to an api that
4
+ // returns a signed, HttpOnly session cookie — see AGENTS.md › Auth.
5
+ import type { ReactNode } from 'react'
6
+ import type { PageMeta } from '@voltro/web'
7
+ import { useNavigate } from '@voltro/web'
8
+ import { T } from '@voltro/i18n'
9
+ import { getCatalog } from '../../locales'
10
+ import { SESSION_COOKIE } from '../../lib/auth'
11
+
12
+ export const renderMode = 'static' as const
13
+
14
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
15
+ title: getCatalog(locale)['meta.login.title'],
16
+ })
17
+
18
+ export default function Login(): ReactNode {
19
+ const navigate = useNavigate()
20
+
21
+ const onSignIn = (): void => {
22
+ // Set the demo session cookie, then go where the gate sent us (the
23
+ // RedirectError carries `?from=`), defaulting to the dashboard.
24
+ document.cookie = `${SESSION_COOKIE}=ok; path=/; max-age=86400; samesite=lax`
25
+ const from = new URLSearchParams(window.location.search).get('from') ?? '/dashboard'
26
+ navigate(from)
27
+ }
28
+
29
+ return (
30
+ <section className="hero">
31
+ <h1><T id="login.heading" /></h1>
32
+ <p className="muted"><T id="login.body" /></p>
33
+ <p style={{ marginTop: '1.5rem' }}>
34
+ <button type="button" className="btn" onClick={onSignIn}>
35
+ <T id="login.cta" />
36
+ </button>
37
+ </p>
38
+ </section>
39
+ )
40
+ }
@@ -0,0 +1,21 @@
1
+ // Error boundary scoped to the /dashboard subtree. A render error (or a
2
+ // loader rejection that ISN'T a RedirectError / NotFoundError) in any
3
+ // dashboard page bubbles to the nearest `error.tsx` — this one — instead of
4
+ // the router's default. `reset` re-runs the failed segment.
5
+ import type { ReactNode } from 'react'
6
+ import type { ErrorBoundaryProps } from '@voltro/web'
7
+ import { T } from '@voltro/i18n'
8
+
9
+ export default function DashboardError({ error, reset }: ErrorBoundaryProps): ReactNode {
10
+ return (
11
+ <div className="dash">
12
+ <main>
13
+ <h1><T id="error.heading" /></h1>
14
+ <p className="muted">{String(error)}</p>
15
+ <p style={{ marginTop: '1rem' }}>
16
+ <button type="button" className="btn" onClick={reset}><T id="error.retry" /></button>
17
+ </p>
18
+ </main>
19
+ </div>
20
+ )
21
+ }
@@ -0,0 +1,68 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // Render smokes for the /dashboard subtree's scoped fallbacks: error.tsx
4
+ // (message + reset button), loading.tsx (skeleton), not-found.tsx (message +
5
+ // back link). These are pure presentational components with no framework hooks.
6
+
7
+ import { afterEach, 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
+ const { default: DashboardError } = await import('./error')
14
+ const { default: DashboardLoading } = await import('./loading')
15
+ const { default: DashboardNotFound } = await import('./not-found')
16
+
17
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
18
+
19
+ let container: HTMLDivElement
20
+ let root: Root
21
+
22
+ // error.tsx / not-found.tsx use <T>, so wrap renders in the framework's
23
+ // <I18nProvider> (auto-wired in the running app).
24
+ const render = (node: ReactNode): void => {
25
+ container = document.createElement('div')
26
+ document.body.appendChild(container)
27
+ act(() => {
28
+ root = createRoot(container)
29
+ root.render(
30
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
31
+ )
32
+ })
33
+ }
34
+
35
+ afterEach(() => {
36
+ if (root) act(() => root.unmount())
37
+ container?.remove()
38
+ document.body.innerHTML = ''
39
+ })
40
+
41
+ describe('dashboard error boundary', () => {
42
+ test('renders the error text and calls reset when Try again is clicked', () => {
43
+ const reset = vi.fn()
44
+ render(createElement(DashboardError, { error: new Error('kaboom'), reset }))
45
+ expect(container.textContent).toContain('kaboom')
46
+ const btn = container.querySelector('button')!
47
+ act(() => { btn.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
48
+ expect(reset).toHaveBeenCalledTimes(1)
49
+ })
50
+ })
51
+
52
+ describe('dashboard loading', () => {
53
+ test('renders skeleton placeholders', () => {
54
+ render(createElement(DashboardLoading))
55
+ expect(container.querySelectorAll('.skeleton').length).toBeGreaterThan(0)
56
+ })
57
+ })
58
+
59
+ describe('dashboard not-found', () => {
60
+ test('renders the not-found message and a link back to the overview', () => {
61
+ render(createElement(DashboardNotFound))
62
+ expect(container.textContent).toContain('Not found')
63
+ const back = Array.from(container.querySelectorAll('a')).find(
64
+ (a) => a.getAttribute('href') === '/dashboard',
65
+ )
66
+ expect(back).toBeTruthy()
67
+ })
68
+ })
@@ -0,0 +1,55 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/dashboard` overview — the SSR overview page. It has no loader/hooks; it
4
+ // renders a fixed set of stat cards + declares its render mode + meta. We assert
5
+ // those config exports and the rendered card structure.
6
+
7
+ import { afterEach, describe, expect, test } 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
+ const { default: Overview, meta, renderMode } = await import('./index')
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
+ // The page uses <T>, so wrap renders in the framework's <I18nProvider>.
21
+ const render = (node: ReactNode): void => {
22
+ container = document.createElement('div')
23
+ document.body.appendChild(container)
24
+ act(() => {
25
+ root = createRoot(container)
26
+ root.render(
27
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
28
+ )
29
+ })
30
+ }
31
+
32
+ afterEach(() => {
33
+ if (root) act(() => root.unmount())
34
+ container?.remove()
35
+ document.body.innerHTML = ''
36
+ })
37
+
38
+ describe('dashboard overview — config', () => {
39
+ test('is an SSR page (so the parent gate runs per request) with an Overview title', () => {
40
+ expect(renderMode).toBe('ssr')
41
+ expect(meta({ locale: 'en' }).title).toBe('Overview')
42
+ })
43
+ })
44
+
45
+ describe('dashboard overview — render', () => {
46
+ test('renders one card per stat with its label and value', () => {
47
+ render(createElement(Overview))
48
+ const cards = Array.from(container.querySelectorAll('.card'))
49
+ expect(cards).toHaveLength(4)
50
+ expect(container.textContent).toContain('Projects')
51
+ expect(container.textContent).toContain('12')
52
+ expect(container.textContent).toContain('Uptime')
53
+ expect(container.textContent).toContain('99.9%')
54
+ })
55
+ })