@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,11 @@
1
+ // Core table — the multi-tenancy boundary. Every row in a `tenant()`-marked
2
+ // table carries `tenantId` pointing here. Unlike `actors`, you DECLARE this
3
+ // one (it's app-shaped — add the fields your org/tenant needs).
4
+
5
+ import { id, table, text, timestamp } from '@voltro/database'
6
+
7
+ export const tenants = table('tenants', {
8
+ id: id(),
9
+ name: text(),
10
+ createdAt: timestamp().default('now'),
11
+ })
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@{{projectName}}/{{appName}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "voltro dev .",
8
+ "test": "voltro test",
9
+ "typecheck": "tsc --noEmit"
10
+ },
11
+ "dependencies": {
12
+ "@effect/platform": "^0.96.1",
13
+ "@effect/rpc": "^0.75.1",
14
+ "@voltro/cli": "0.1.0",
15
+ "@voltro/database": "0.1.0",
16
+ "@voltro/env": "0.1.0",
17
+ "@voltro/plugin-governance": "0.1.0",
18
+ "@voltro/plugin-multitenancy": "0.1.0",
19
+ "@voltro/protocol": "0.1.0",
20
+ "@voltro/runtime": "0.1.0",
21
+ "effect": "^3.21.2"
22
+ },
23
+ "devDependencies": {
24
+ "@voltro/testing": "0.1.0",
25
+ "typescript": "^5.7.0",
26
+ "vitest": "^3.0.0"
27
+ }
28
+ }
@@ -0,0 +1,18 @@
1
+ // EXECUTOR (server-only): returns a query builder with an eager `.with(...)`
2
+ // spec. `.with({ books: true })` attaches each author's books as an array on
3
+ // the row — compiled into ONE SQL roundtrip via the dialect's JSON-aggregation
4
+ // idiom (postgres jsonb_agg, sqlite json_group_array, mysql JSON_ARRAYAGG,
5
+ // mssql FOR JSON PATH). The per-branch `limit`/`orderBy` apply PER author.
6
+ //
7
+ // `authors` carries `tenant()`, so the runtime scopes the root read to the
8
+ // caller's tenant automatically.
9
+
10
+ import type { AppContext } from '@voltro/runtime'
11
+ import { database } from '../database/index'
12
+
13
+ const execute = (_input: Record<string, never>, _ctx: AppContext) =>
14
+ database.authors.with({
15
+ books: { orderBy: [{ column: 'title', direction: 'asc' }], limit: 50 },
16
+ })
17
+
18
+ export default execute
@@ -0,0 +1,40 @@
1
+ // Authors with their books eager-loaded — demonstrates `.with({ books: true })`.
2
+ //
3
+ // DESCRIPTOR (browser-safe). The `output` shape includes the nested `books`
4
+ // array the eager spec attaches to each author row (the relation registered
5
+ // in authors.relations.ts).
6
+ //
7
+ // `source: ['authors', 'books']` makes the reactive subscription re-run when
8
+ // EITHER table changes — a new book under an author pushes a fresh snapshot.
9
+ // No `cache` here: this is a join-shaped result; we let the live dispatcher
10
+ // keep it fresh rather than cache a snapshot.
11
+
12
+ import { defineQuery } from '@voltro/protocol'
13
+ import { Schema } from 'effect'
14
+
15
+ const Book = Schema.Struct({
16
+ id: Schema.String,
17
+ authorId: Schema.String,
18
+ title: Schema.String,
19
+ summary: Schema.String,
20
+ genre: Schema.String,
21
+ tags: Schema.Array(Schema.String),
22
+ slug: Schema.String,
23
+ tenantId: Schema.String,
24
+ })
25
+
26
+ export const authorsWithBooks = defineQuery({
27
+ name: 'authors.withBooks',
28
+ source: ['authors', 'books'],
29
+ input: Schema.Struct({}),
30
+ output: Schema.Struct({
31
+ id: Schema.String,
32
+ name: Schema.String,
33
+ // `bio` is the `.encrypted()` column — handlers (and the wire) see
34
+ // plaintext; it's ciphertext only on disk. Nullable in the seed/data.
35
+ bio: Schema.NullOr(Schema.String),
36
+ tenantId: Schema.String,
37
+ // Eager-loaded relation: each author carries an array of their books.
38
+ books: Schema.Array(Book),
39
+ }),
40
+ })
@@ -0,0 +1,17 @@
1
+ // EXECUTOR (server-only): returns a query builder. `.matching('bookSearch',
2
+ // input.q)` compiles to the dialect's FTS predicate (postgres tsvector,
3
+ // mysql/mariadb MATCH…AGAINST, sqlite FTS5, mssql ranked-LIKE) — resolving
4
+ // the index's covered columns + config from the `bookSearch` declaration on
5
+ // the `books` table.
6
+ //
7
+ // We do NOT add a tenant filter by hand — `books` carries the `tenant()`
8
+ // mixin, so the runtime AND-merges `eq('tenantId', subject.tenantId)` into
9
+ // the predicate automatically.
10
+
11
+ import type { AppContext } from '@voltro/runtime'
12
+ import { database } from '../database/index'
13
+
14
+ const execute = (input: { q: string }, _ctx: AppContext) =>
15
+ database.books.matching('bookSearch', input.q).limit(50)
16
+
17
+ export default execute
@@ -0,0 +1,39 @@
1
+ // Full-text book search — demonstrates `.matching(...)` FTS + declarative
2
+ // query result caching.
3
+ //
4
+ // DESCRIPTOR (browser-safe): NO node/database/server imports. The codegen
5
+ // pulls this into rpcGroup.generated.ts, which the web client loads
6
+ // value-level — so it must stay free of server-only modules.
7
+ //
8
+ // `cache` opts into server-side snapshot caching with auto-invalidation: the
9
+ // framework caches the snapshot and drops it whenever a mutation writes any
10
+ // table the query depends on (here, `books`). `scope` is REQUIRED and is a
11
+ // security decision — this query is tenant-filtered (the `tenant()` mixin on
12
+ // `books` AND-merges the caller's tenantId), so it depends on the caller →
13
+ // `scope: 'subject'` (the cache key includes the subject id, no cross-tenant
14
+ // leak). NEVER `global` on a subject-filtered query.
15
+ //
16
+ // The `cache` field is backend-agnostic: this snapshot lives in the
17
+ // in-process `memory` cache by default and in Redis (cross-instance) the
18
+ // moment you flip `CACHE_BACKEND=redis` / app.config `cache: 'redis'` — the
19
+ // query code below does not change. `voltro add redis` wires that for you.
20
+
21
+ import { defineQuery } from '@voltro/protocol'
22
+ import { Schema } from 'effect'
23
+
24
+ export const searchBooks = defineQuery({
25
+ name: 'books.search',
26
+ source: 'books',
27
+ input: Schema.Struct({ q: Schema.String }),
28
+ output: Schema.Struct({
29
+ id: Schema.String,
30
+ authorId: Schema.String,
31
+ title: Schema.String,
32
+ summary: Schema.String,
33
+ genre: Schema.String,
34
+ tags: Schema.Array(Schema.String),
35
+ slug: Schema.String,
36
+ tenantId: Schema.String,
37
+ }),
38
+ cache: { ttl: '30s', swr: '5m', scope: 'subject' },
39
+ })
@@ -0,0 +1,101 @@
1
+ // Boot-lifecycle seed — a couple of authors + their books so the catalog has
2
+ // data the moment `voltro dev` boots. Idempotent via `upsertByUnique`, so
3
+ // re-running on every boot is safe (the fingerprint ledger also dedupes).
4
+ //
5
+ // NOTE: the seed store is the RAW store — it has no authenticated subject, so
6
+ // the `tenant()` auto-fill doesn't fire. We pass `tenantId` explicitly here
7
+ // (and seed the demo tenant row first). The dev AuthMiddleware default resolves
8
+ // the `acme` tenant from the `x-tenant` header, so seeding under `acme` lines
9
+ // up with what queries see out of the box.
10
+ //
11
+ // `bio` is the `.encrypted()` column — we pass plaintext; the store middleware
12
+ // encrypts it on write (requires governancePlugin({ fieldEncryption: true })).
13
+ // `tags` is the `array(text())` column — pass a plain JS array. `slug` is the
14
+ // DB-computed `.generatedAs(...)` column — DON'T pass it; the engine fills it.
15
+
16
+ import { defineSeed } from '@voltro/database'
17
+
18
+ const TENANT_ID = 'acme'
19
+
20
+ export default defineSeed({
21
+ id: 'catalog',
22
+ name: 'Library catalog demo data',
23
+ lifecycle: 'boot',
24
+ steps: ({ step }) => [
25
+ step('tenant', async ({ upsertByUnique }) => {
26
+ await upsertByUnique(
27
+ 'tenants',
28
+ { id: TENANT_ID },
29
+ { id: TENANT_ID, name: 'Acme Library', createdAt: new Date() },
30
+ )
31
+ return { rowsTouched: 1 }
32
+ }),
33
+
34
+ step('authors-and-books', async ({ upsertByUnique }) => {
35
+ let touched = 0
36
+
37
+ const ursula = await upsertByUnique(
38
+ 'authors',
39
+ { id: 'author_leguin' },
40
+ {
41
+ id: 'author_leguin',
42
+ name: 'Ursula K. Le Guin',
43
+ bio: 'American author best known for works of speculative fiction.',
44
+ tenantId: TENANT_ID,
45
+ },
46
+ )
47
+ touched += 1
48
+
49
+ const carl = await upsertByUnique(
50
+ 'authors',
51
+ { id: 'author_sagan' },
52
+ {
53
+ id: 'author_sagan',
54
+ name: 'Carl Sagan',
55
+ bio: 'Astronomer and science communicator.',
56
+ tenantId: TENANT_ID,
57
+ },
58
+ )
59
+ touched += 1
60
+
61
+ const books = [
62
+ {
63
+ id: 'book_leftHand',
64
+ authorId: ursula.row['id'] as string,
65
+ title: 'The Left Hand of Darkness',
66
+ summary: 'A lone envoy on a frozen world where inhabitants have no fixed sex.',
67
+ genre: 'sciFi',
68
+ tags: ['classic', 'gender', 'winter'],
69
+ tenantId: TENANT_ID,
70
+ },
71
+ {
72
+ id: 'book_earthsea',
73
+ authorId: ursula.row['id'] as string,
74
+ title: 'A Wizard of Earthsea',
75
+ summary: 'A young mage learns the true cost of power and names.',
76
+ genre: 'fantasy',
77
+ tags: ['magic', 'coming-of-age'],
78
+ tenantId: TENANT_ID,
79
+ },
80
+ {
81
+ id: 'book_cosmos',
82
+ authorId: carl.row['id'] as string,
83
+ title: 'Cosmos',
84
+ summary: 'A sweeping tour of the universe and our place in it.',
85
+ genre: 'nonfiction',
86
+ tags: ['astronomy', 'science'],
87
+ tenantId: TENANT_ID,
88
+ },
89
+ ]
90
+
91
+ for (const book of books) {
92
+ // `slug` is omitted — the `.generatedAs(...)` STORED column is filled
93
+ // by the DB engine from `title`.
94
+ await upsertByUnique('books', { id: book.id }, book)
95
+ touched += 1
96
+ }
97
+
98
+ return { rowsTouched: touched }
99
+ }),
100
+ ],
101
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "api-data-advanced",
3
+ "kind": "api",
4
+ "summary": "Advanced schema modeling: *.entity.ts/*.relations.ts split with relations + eager loading, full-text search, dbEnum, array + generated + encrypted columns, and declarative query caching. A small library/catalog (authors + books).",
5
+ "tags": ["api", "backend", "schema", "relations", "fts", "enum", "encryption", "cache", "advanced"]
6
+ }
@@ -0,0 +1,124 @@
1
+ // Unit tests with `@voltro/testing` — no database, no running server.
2
+ //
3
+ // 1. `authors.withBooks` — the runnable primitive. The executor returns a
4
+ // `database.authors.with({ books: … })` query BUILDER; we run its
5
+ // `.descriptor` through `ctx.store.query`, which (a) resolves the eager
6
+ // `books` relation against the in-memory store and (b) AND-merges the
7
+ // caller's tenant scope — the exact isolation the runtime applies. So we
8
+ // assert both eager-loading AND tenant isolation.
9
+ // 2. `books.search` — descriptor-pinned. Its executor calls `.matching(...)`
10
+ // (dialect FTS: postgres tsvector / mysql MATCH…AGAINST / sqlite FTS5).
11
+ // The in-memory test store does NOT evaluate `descriptor.fullTextSearch`,
12
+ // so a run there would silently return UNFILTERED rows — a misleading
13
+ // assertion. FTS behavior is proven by an integration test against a real
14
+ // dialect; here we pin the wire contract (name / source / input+output
15
+ // decode) instead of faking a search.
16
+ //
17
+ // Run with `voltro test` (vitest).
18
+
19
+ import { describe, it, expect, beforeAll } from 'vitest'
20
+ import { Schema } from 'effect'
21
+ import { registerCoreTables, registerRelations } from '@voltro/database'
22
+ import { makeTestContext, mockStore } from '@voltro/testing'
23
+ import { database, actors, tenants } from '../database/index' // registers authors / books (tables)
24
+ import { authorsRelations } from '../database/authors.relations'
25
+ import { booksRelations } from '../database/books.relations'
26
+ import authorsWithBooksExecute from '../queries/authors.withBooks.query.server'
27
+ import { searchBooks } from '../queries/books.search.query'
28
+
29
+ // Two boot steps `voltro dev` runs that the unit harness (`voltro test`) does
30
+ // NOT, both needed for the eager-load walker:
31
+ // 1. registerCoreTables — the audit()/tenant() mixins add createdBy/updatedBy/
32
+ // tenantId reference() columns whose thunks resolve `actors`/`tenants` via
33
+ // this registry. `inferForeignKey` walks EVERY reference() column on `books`
34
+ // to find the FK back to `authors`, so it dereferences those mixin columns —
35
+ // which throw unless the core tables are registered.
36
+ // 2. registerRelations — `*.relations.ts` files only DEFINE specs; runtime
37
+ // module discovery (registerDiscoveredRelations) is what REGISTERS them.
38
+ // We do both here — the exact wiring the dev/serve dispatcher does at boot — so
39
+ // `.with({ books })` resolves against the in-memory store just as at runtime.
40
+ beforeAll(() => {
41
+ registerCoreTables({ actors: () => actors, tenants: () => tenants })
42
+ registerRelations(authorsRelations)
43
+ registerRelations(booksRelations)
44
+ })
45
+
46
+ // `bio` is an `.encrypted()` column. We seed it `null` (the descriptor allows
47
+ // NullOr) — a plaintext/null value passes the read cipher through untouched, so
48
+ // no governance cipher needs wiring for these reads.
49
+ const book = (over: Partial<Record<string, unknown>> & { id: string; authorId: string; tenantId: string }) => ({
50
+ title: 'Untitled',
51
+ summary: '',
52
+ genre: 'fiction',
53
+ tags: [] as ReadonlyArray<string>,
54
+ slug: 'untitled',
55
+ ...over,
56
+ })
57
+
58
+ describe('authors.withBooks', () => {
59
+ it('returns the tenant’s authors with their books eager-loaded', async () => {
60
+ const ctx = makeTestContext({
61
+ subject: { type: 'user', id: 'user_1', tenantId: 'acme' },
62
+ store: mockStore({
63
+ authors: [{ id: 'author_1', name: 'Ada', bio: null, tenantId: 'acme' }],
64
+ books: [
65
+ book({ id: 'book_1', authorId: 'author_1', tenantId: 'acme', title: 'Analytical Engine' }),
66
+ book({ id: 'book_2', authorId: 'author_1', tenantId: 'acme', title: 'Notes' }),
67
+ ],
68
+ }),
69
+ })
70
+
71
+ const rows = await ctx.store.query(authorsWithBooksExecute({}, ctx).descriptor)
72
+
73
+ expect(rows).toHaveLength(1)
74
+ const ada = rows[0] as { id: string; name: string; books: ReadonlyArray<{ title: string }> }
75
+ expect(ada.name).toBe('Ada')
76
+ expect(ada.books.map((b) => b.title).sort()).toEqual(['Analytical Engine', 'Notes'])
77
+ })
78
+
79
+ it('isolates tenants — t2 never sees t1 authors (REAL tenant scoping)', async () => {
80
+ const ctx = makeTestContext({
81
+ subject: { type: 'user', id: 'u1', tenantId: 't1' },
82
+ store: mockStore({
83
+ authors: [{ id: 'author_t1', name: 'Secret', bio: null, tenantId: 't1' }],
84
+ books: [book({ id: 'book_t1', authorId: 'author_t1', tenantId: 't1' })],
85
+ }),
86
+ })
87
+
88
+ // Same store, re-scoped to t2 — the runtime AND-merges eq('tenantId','t2'),
89
+ // so t1's author is invisible.
90
+ const seenByT2 = await ctx.withTenant('t2', (c) =>
91
+ c.store.query(authorsWithBooksExecute({}, c).descriptor),
92
+ )
93
+ expect(seenByT2).toHaveLength(0)
94
+ })
95
+ })
96
+
97
+ describe('books.search (query descriptor)', () => {
98
+ it('declares the expected wire name + source table', () => {
99
+ expect(searchBooks.name).toBe('books.search')
100
+ expect(searchBooks.source).toBe('books')
101
+ })
102
+
103
+ it('accepts a valid { q } input and rejects a malformed one', () => {
104
+ const decode = Schema.decodeUnknownSync(searchBooks.input)
105
+ expect(decode({ q: 'effect' })).toEqual({ q: 'effect' })
106
+ expect(() => decode({})).toThrow() // missing q
107
+ })
108
+
109
+ it('decodes a well-formed book row against the output schema', () => {
110
+ const decode = Schema.decodeUnknownSync(searchBooks.output)
111
+ const row = decode({
112
+ id: 'book_1',
113
+ authorId: 'author_1',
114
+ title: 'Effect in Action',
115
+ summary: 'A book.',
116
+ genre: 'nonfiction',
117
+ tags: ['effect', 'ts'],
118
+ slug: 'effect-in-action',
119
+ tenantId: 'acme',
120
+ })
121
+ expect(row.tags).toEqual(['effect', 'ts'])
122
+ expect(() => decode({ id: 'book_1' })).toThrow() // missing required fields
123
+ })
124
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "exclude": ["node_modules", "dist"]
5
+ }
@@ -0,0 +1,81 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro backend scaffold (template: **api-durable**).
4
+
5
+ A cohesive **order-fulfillment** domain that exercises the framework's
6
+ entire **durable-execution surface** in one app — durable workflows with
7
+ a human-approval gate, event triggers, a cron schedule, a table
8
+ subscriber, a materialized aggregate, and a run-once startup hook. It
9
+ boots with **zero infrastructure** (`store: 'memory'`).
10
+
11
+ ## Boot
12
+
13
+ ```bash
14
+ pnpm install # at the repo root
15
+ pnpm --filter @{{projectName}}/{{appName}} dev
16
+ # → http://localhost:4000
17
+ # → ws://localhost:4000/ws
18
+ ```
19
+
20
+ No env or services required. `store: 'memory'` resets on every
21
+ supervised restart — switch `app.config.ts` to `store: 'postgres'`
22
+ (and `docker compose up` from the repo root) when you want durable
23
+ state + multi-instance cluster workflow runners.
24
+
25
+ ## What it demonstrates
26
+
27
+ | File | Primitive | Role |
28
+ |---|---|---|
29
+ | `app.config.ts` | app config | `store: 'memory'`, zero-infra boot. |
30
+ | `database/schema.ts` | schema | core `actors`/`tenants` + an `orders` table (`tenant()` + `.reactive()`). |
31
+ | `mutations/orders.place.mutation.*` | mutation | insert an order, then **emit `order.placed`** post-commit via `ctx.events.emit`. Tenant write-guard. |
32
+ | `triggers/order.placed.trigger.tsx` | event trigger | maps event `order.placed` → **start** the `orders.fulfill` workflow. |
33
+ | `workflows/order.fulfill.workflow.*` | durable workflow | `step('reserve-stock')` (with **`withCompensation`** saga rollback) → `sleep` → **`awaitSignal('approval')`** human gate → `step('ship')` / mark rejected. |
34
+ | `mutations/orders.approve.mutation.*` | mutation | inject the `approval` signal into the parked run via `ctx.workflows.signal(...)`. |
35
+ | `schedules/nightlyReport.cron.tsx` | schedule | `defineSchedule` cron `0 2 * * *` (UTC), tallies open orders. |
36
+ | `subscribers/orderChanges.subscribe.ts` | subscriber | `defineSubscriber({ table: 'orders', on: 'any' })` post-commit reaction. |
37
+ | `aggregates/orderStats.aggregate.ts` | aggregate | `defineAggregate` materialized per-tenant/per-status order roll-up, refreshed every minute. |
38
+ | `startup/warm.startup.tsx` | startup hook | run-once boot hook holding a resource + `onShutdown` teardown. |
39
+
40
+ ## The end-to-end flow
41
+
42
+ 1. **Place an order** → `orders.place` inserts the row and emits
43
+ `order.placed` *after the transaction commits* (so a rollback never
44
+ starts a workflow for a non-existent order).
45
+ 2. **The trigger fires** → `order.placed.trigger.tsx` starts the durable
46
+ `orders.fulfill` workflow with `{ orderId, tenantId }`.
47
+ 3. **The workflow runs durably** → reserves stock, waits a (short)
48
+ journaled delay, then **parks on `awaitSignal('approval')`**.
49
+ 4. **A human approves** → `orders.approve` derives the workflow's
50
+ deterministic executionId (from its `idempotencyKey`) and injects the
51
+ `approval` signal; the parked run wakes (sub-second) and either ships
52
+ or marks the order rejected.
53
+
54
+ Meanwhile the **subscriber** logs every `orders` write, the **aggregate**
55
+ keeps a live per-status tally, the **schedule** reports nightly, and the
56
+ **startup hook** holds a process-lifetime resource.
57
+
58
+ ## Try it
59
+
60
+ Over the rpc surface (e.g. from a `voltro dev` web client, or
61
+ `POST /rpc` / the inspect `invoke` endpoint):
62
+
63
+ ```jsonc
64
+ // 1. place — starts the fulfillment workflow via order.placed
65
+ { "tag": "orders.place", "input": { "tenantId": "acme", "customerName": "Ada", "amountCents": 4200 } }
66
+ // 2. approve — wakes the parked awaitSignal('approval') gate
67
+ { "tag": "orders.approve", "input": { "tenantId": "acme", "orderId": "order_…", "approved": true } }
68
+ ```
69
+
70
+ Watch the run in the dashboard's **Workflows** tab (the `awaitSignal`
71
+ gate also has a "Send signal…" button), and the order's status walk
72
+ `placed → reserved → shipped` live.
73
+
74
+ ## Notes
75
+
76
+ - All primitives are **auto-discovered by file convention** — nothing is
77
+ registered in `app.config.ts`.
78
+ - `query` / `mutation` / `action` / `workflow` keep the **descriptor /
79
+ executor split**: the browser-safe `*.ts` / `*.tsx` descriptor never
80
+ imports `@voltro/database`, `@voltro/runtime`, `node:*`, or the
81
+ workflow executor's server graph. The `.server.*` executors do.
@@ -0,0 +1,49 @@
1
+ // `orderStats` — a materialized aggregate (`*.aggregate.ts`).
2
+ //
3
+ // The framework owns the lifecycle: it runs `build` on the `refresh`
4
+ // interval, stores the rows in an auto-managed backing table, and serves
5
+ // them via `ctx.aggregates.orderStats.read(...)`. Use an aggregate when
6
+ // the SOURCE query is expensive but the RESULT is small + bounded — a
7
+ // per-status order roll-up here.
8
+ //
9
+ // `output` MUST match each returned row's shape. `build` runs as the
10
+ // system (no per-request subject), so it reads across every tenant; the
11
+ // `tenantId` column is part of the grouping so reads stay per-tenant.
12
+
13
+ import { defineAggregate } from '@voltro/runtime'
14
+ import { column, count } from '@voltro/database'
15
+ import { Schema } from 'effect'
16
+ import { database } from '../database/schema'
17
+
18
+ export const OrderStat = Schema.Struct({
19
+ tenantId: Schema.String,
20
+ status: Schema.String,
21
+ orders: Schema.Number,
22
+ })
23
+ export type OrderStat = Schema.Schema.Type<typeof OrderStat>
24
+
25
+ export default defineAggregate({
26
+ name: 'orderStats',
27
+ refresh: '1m', // re-run every minute (interval shorthand)
28
+ output: OrderStat,
29
+ build: async (ctx) => {
30
+ const rows = await ctx.store.query(
31
+ database.orders
32
+ .groupBy(['tenantId', 'status'])
33
+ // Grouped columns must be EXPLICITLY projected via `column(...)`
34
+ // in the aggregate spec — they are NOT auto-included (SQL rule:
35
+ // a selected non-aggregate column must be in GROUP BY).
36
+ .aggregate({
37
+ tenantId: column('tenantId'),
38
+ status: column('status'),
39
+ orders: count(),
40
+ })
41
+ .descriptor,
42
+ )
43
+ return rows.map((r) => ({
44
+ tenantId: (r as { tenantId: string }).tenantId,
45
+ status: (r as { status: string }).status,
46
+ orders: (r as { orders: number }).orders,
47
+ }))
48
+ },
49
+ })
@@ -0,0 +1,41 @@
1
+ // Backend app for the {{projectName}} project. Read by `voltro dev`.
2
+ //
3
+ // This template demonstrates the framework's DURABLE-EXECUTION surface
4
+ // end-to-end on an order-fulfillment domain. Everything is wired so it
5
+ // boots with ZERO infra:
6
+ //
7
+ // - `store: 'memory'` — no docker, no postgres. Workflows run with
8
+ // the in-process durable engine (replay within one process; swap to
9
+ // `'postgres'` for multi-instance cluster runners). Memory resets on
10
+ // every supervised restart, which is fine for kicking the tyres.
11
+ //
12
+ // What's in here (all auto-discovered by file convention — nothing is
13
+ // registered in this config):
14
+ //
15
+ // mutations/orders.place.mutation.* — insert an order, then emit a
16
+ // post-commit `order.placed` event
17
+ // triggers/order.placed.trigger.tsx — event → start `orders.fulfill`
18
+ // workflows/order.fulfill.workflow.* — step → sleep → awaitSignal
19
+ // (human approval) → step
20
+ // mutations/orders.approve.mutation.* — inject the `approval` signal
21
+ // schedules/nightlyReport.cron.tsx — nightly summary cron
22
+ // subscribers/orderChanges.subscribe.ts— react to every orders write
23
+ // aggregates/orderStats.aggregate.ts — materialized per-status roll-up
24
+ // startup/warm.startup.tsx — run-once boot hook
25
+ //
26
+ // Add your own env below; it's validated at boot (fail-fast) and read on
27
+ // the server via `serverEnv` / `getSecret` from '@voltro/env/server'.
28
+ import { defineEnv, envVar } from '@voltro/env'
29
+
30
+ export const env = defineEnv({
31
+ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }),
32
+ // Add your own, e.g.:
33
+ // STRIPE_KEY: envVar.string({ access: 'secret' }),
34
+ })
35
+
36
+ export default {
37
+ type: 'api' as const,
38
+ name: '{{capProjectName}}{{capAppName}}',
39
+ store: 'memory' as const,
40
+ env,
41
+ }
@@ -0,0 +1,65 @@
1
+ // Schema for the {{projectName}} backend.
2
+ //
3
+ // Tables are auto-discovered: every exported `table(...)` in this file
4
+ // (or any `*.entity.ts` / `*.schema.ts` file) is registered by
5
+ // `voltro dev` — no manual barrel. `actors` + `tenants` are the
6
+ // framework's core tables: the built-in `audit()` / `tenant()` /
7
+ // `softDelete()` mixins reference them, so they must be declared (the
8
+ // CLI wires them into the mixin registry once it finds them).
9
+ //
10
+ // `orders` carries the `tenant()` mixin (→ tenantId + audit columns,
11
+ // auto-stamped by the runtime) and `.reactive()` so the `orderChanges`
12
+ // subscriber + any live subscription wake on every write.
13
+
14
+ import {
15
+ databaseHandle,
16
+ id,
17
+ integer,
18
+ table,
19
+ text,
20
+ timestamp,
21
+ type InferRow,
22
+ } from '@voltro/database'
23
+ import { tenant } from '@voltro/plugin-multitenancy'
24
+
25
+ // ---------- Core tables (required by the audit / tenant mixins) ----------
26
+
27
+ export const actors = table('actors', {
28
+ id: id(),
29
+ kind: text().oneOf(['user', 'serviceAccount', 'apiKey', 'system']),
30
+ displayName: text().nullable(),
31
+ createdAt: timestamp().default('now'),
32
+ })
33
+
34
+ export const tenants = table('tenants', {
35
+ id: id(),
36
+ name: text(),
37
+ createdAt: timestamp().default('now'),
38
+ })
39
+
40
+ // ---------- Application table — order-fulfillment domain ----------
41
+
42
+ export const orders = table('orders', {
43
+ id: id({ prefix: 'order' }),
44
+ // The fulfillment lifecycle. `oneOf` narrows the row type to the
45
+ // literal union AND emits a cross-dialect CHECK constraint.
46
+ status: text().oneOf([
47
+ 'placed', // created, fulfillment workflow kicked off
48
+ 'reserved', // stock reserved (workflow step 1)
49
+ 'approved', // human approval signal accepted
50
+ 'rejected', // human approval signal rejected
51
+ 'shipped', // shipped (workflow final step)
52
+ ]).default('placed'),
53
+ customerName: text(),
54
+ amountCents: integer(),
55
+ })
56
+ // tenant() pulls audit() transitively → adds tenantId + createdAt /
57
+ // updatedAt / createdBy / updatedBy (auto-stamped by the runtime).
58
+ .with(tenant())
59
+ // Opt into the matcher engine: the `orderChanges` subscriber + any
60
+ // live subscription against `orders` fire on every mutation write.
61
+ .reactive()
62
+
63
+ export type Order = InferRow<typeof orders>
64
+
65
+ export const database = databaseHandle({ actors, tenants, orders })