@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,607 @@
1
+ # Schema-driven UI
2
+
3
+ > Project the typed descriptor graph into UI — forms, tables, pickers, and reactive components, all bound to a descriptor with near-zero glue.
4
+
5
+
6
+
7
+ ---
8
+
9
+ <!-- source: en/ui/overview.md -->
10
+ ## Overview
11
+
12
+ _Project the typed descriptor graph into UI — forms, tables, pickers, and reactive components, all bound to a descriptor with near-zero glue._
13
+
14
+ You already own a typed schema on **both** sides of the wire: the entity DSL
15
+ (`*.entity.ts`) and the descriptor schemas (`defineQuery` / `defineMutation`
16
+ carry `effect/Schema` for input, output, and `target`). Schema-driven UI
17
+ **projects that into the frontend** — so a form, a table, or a picker is a
18
+ *binding to a descriptor* the framework already has, not hand-written glue.
19
+
20
+ Here's that idea live — a form bound to a mutation and a table bound to a query,
21
+ sharing one reactive backend. Add a row and it appears instantly, pushed from
22
+ the server (it's your own throwaway sandbox; it resets on refresh):
23
+
24
+ ```tsx
25
+ <AutoForm api="app" mutation="todos.create" submitLabel="Add todo" />
26
+ <DataTable api="app" query="todos.list" />
27
+ ```
28
+
29
+ ## Why this isn't "yet another admin generator"
30
+
31
+ Auto-generated CRUD UIs fail because they generate against a *dead* REST/SQL
32
+ schema and hit a wall the moment you need anything custom. Voltro's version is
33
+ different on one axis: the generated UI binds to a **reactive, auto-optimistic
34
+ backend**. A `<DataTable>` is not a dead grid you refetch — it's a live
35
+ subscription that updates on any write, with optimistic patches derived from
36
+ the mutation descriptor's `target`, for free. The generation is the *delivery*;
37
+ the reactivity is the *value*.
38
+
39
+ ## Binding symmetry — everything binds to a descriptor
40
+
41
+ | UI piece | binds to | gives you |
42
+ |---|---|---|
43
+ | a **form** | a **mutation** (`todos.create`) | fields from its input Schema, validation, submit, op-correct optimistic |
44
+ | a **field / picker** | a **query** (`users.search`) | live options, debounce, pagination |
45
+ | a **table** | a **query** (`todos.list`) | live rows, sort, pagination, row-action mutations |
46
+ | a **filter panel** | a **query**'s input | faceted controls + a live result count |
47
+ | a **detail view** | a **query** + relations | a live record + its eager-loaded relations |
48
+
49
+ There's no new data layer to learn. Customization is only ever choosing *how* a
50
+ binding renders — never re-plumbing the binding.
51
+
52
+ ## The customization ladder (never lose the binding)
53
+
54
+ This is where 99% of schema→UI generators die: they nail the happy path, then
55
+ force a config DSL until it's worse than hand-written JSX — or you eject and
56
+ lose everything. The one rule that avoids both:
57
+
58
+ > Customization is a ladder of ever-smaller overrides, and on **no rung do you
59
+ > lose the binding** (schema validation + mutation submit + optimistic; for a
60
+ > picker, the live query). Eject from the *rendering* is never eject from the
61
+ > *binding*.
62
+
63
+ | Rung | How | You lose |
64
+ |---|---|---|
65
+ | 0 — schema annotation | `widget` / `label` on the field | nothing (zero form code) |
66
+ | 1 — per-field render-prop | `<Field name="x">{f => <MyWidget .../>}</Field>` | nothing — state/validation/submit stay |
67
+ | 2 — widget registry | map a widget-kind → component app-wide | nothing |
68
+ | 3 — layout override | arrange `<Field/>`s in your own JSX | nothing |
69
+ | eject — headless | `useFormBinding` / `useDataTable` + your JSX | only the auto-rendering — the binding stays |
70
+
71
+ `<AutoForm>` / `<DataTable>` are sugar over a **headless core**
72
+ (`useFormBinding` / `useDataTable`) — which is exactly why ejecting from the
73
+ rendering keeps everything underneath.
74
+
75
+ ## Localizing the built-in strings
76
+
77
+ The components render a handful of user-facing labels — `Clear`, `Actions`,
78
+ `Search…`, the workflow status words (`Running` / `Succeeded` / …), presence's
79
+ "X is editing" sentence, and so on — with **English defaults**. Localize them
80
+ all at once by wrapping the app in `UiStringsProvider`, instead of threading a
81
+ prop through every component:
82
+
83
+ ```tsx
84
+ import { UiStringsProvider } from '@voltro/web'
85
+
86
+ <UiStringsProvider
87
+ strings={{
88
+ filters: { clear: 'Zurücksetzen', resultCount: (n) => `${n} Ergebnisse` },
89
+ dataTable: { actions: 'Aktionen' },
90
+ workflow: { status: { running: 'Läuft' } },
91
+ presence: { editingOne: (name, verb) => `${name} ist am ${verb}` },
92
+ }}
93
+ >
94
+ <App />
95
+ </UiStringsProvider>
96
+ ```
97
+
98
+ Overrides **deep-merge** onto the defaults — supply only the sections and keys
99
+ you change; everything else stays English. Interpolated strings (counts, names)
100
+ are functions so a locale can reorder or pluralize. Providers nest (an inner one
101
+ merges onto the outer), and a per-component prop (e.g. `<AgentChat placeholder>`)
102
+ still wins over the context for a one-off tweak. `useUiStrings()` reads the
103
+ active strings; `defaultUiStrings` is the English baseline.
104
+
105
+ ## Packaging
106
+
107
+ Three layers, all re-exported by `@voltro/web` so apps import everything from
108
+ the framework's web entry:
109
+
110
+ - **Headless bindings** (`useFormBinding`, `useDataTable`, `useQueryField`, …)
111
+ → `@voltro/client` — pure logic, no kit dependency; works with any
112
+ presentation (incl. an MUI/Mantine adapter).
113
+ - **The widget seam + components** (`<AutoForm>` / `<Field>` / `<DataTable>` /
114
+ `<AsyncSelect>` + the registry + accessible HTML defaults) → `@voltro/ui`.
115
+ - **The styled kit** (Tailwind `shadcnWidgets` + tokens) → `@voltro/ui-shadcn`,
116
+ which plugs into the seam via `<WidgetRegistryProvider widgets={shadcnWidgets}>`.
117
+
118
+ ## In this section
119
+
120
+ - **[Forms & tables](./forms-and-tables)** — `<AutoForm>`, `<DataTable>`,
121
+ query-bound pickers, the widget seam, skeletons, filters.
122
+ - **[Reactive components](./reactive-components)** — workflow progress, presence
123
+ / multiplayer, AI chat — UI over the framework's durable + reactive backend.
124
+ - **[Client utilities](./client-utilities/use-can)** — `useCan`, `useDerived`,
125
+ `useProvenance`, `useUndo`, `usePreview`, async validation, `<RecordView>`,
126
+ the typed analytics catalog, the offline outbox, windowed subscriptions.
127
+
128
+
129
+
130
+ ---
131
+
132
+ <!-- source: en/ui/forms-and-tables.md -->
133
+ ## Forms & tables
134
+
135
+ _<AutoForm> binds to a mutation, <DataTable> to a query — fields and columns from the Schema, validation and live updates for free._
136
+
137
+ Import components from `@voltro/web`, headless hooks from `@voltro/client`.
138
+
139
+ ## `<AutoForm>` — bind to a MUTATION
140
+
141
+ A form binds to **one mutation's** input `Schema`. This cleanly resolves
142
+ create-vs-update: they're *different mutations with different input schemas*, so
143
+ they're naturally different forms — no "CRUD mode" switch.
144
+
145
+ ```tsx
146
+ import { AutoForm } from '@voltro/web'
147
+
148
+ // fields from the mutation's input schema; client+server share the schema;
149
+ // submits via the mutation with op-correct optimistic (insert prepends, etc.)
150
+ <AutoForm api="app" mutation="todos.create" onSuccess={(t) => navigate(`/todos/${t.id}`)} />
151
+
152
+ // update: bind the update mutation + pass the existing row
153
+ <AutoForm api="app" mutation="todos.update" defaults={row} />
154
+ ```
155
+
156
+ Here it is **live** — a real `<AutoForm>` bound to a throwaway demo API (your
157
+ own sandbox; data resets on refresh). Add a todo and watch it appear in the
158
+ table below, pushed from the server:
159
+
160
+ ```tsx
161
+ <AutoForm api="docs" mutation="todos.create" submitLabel="Add todo" />
162
+ <DataTable api="docs" query="todos.list" />
163
+ ```
164
+
165
+ A combined create-or-edit screen is a three-line wrapper:
166
+
167
+ ```tsx
168
+ {row
169
+ ? <AutoForm api="app" mutation="todos.update" defaults={row} />
170
+ : <AutoForm api="app" mutation="todos.create" />}
171
+ ```
172
+
173
+ ### The customization ladder
174
+
175
+ - **Rung 0 — zero config.** Fields render from the schema: a `Schema.Literal`
176
+ union → `select`; string → text; boolean → checkbox; `Date` → date; nested
177
+ object → a `custom` placeholder asking for a render-prop.
178
+ - **Rung 1 — one custom widget** via a `<Field>` render-prop:
179
+ ```tsx
180
+ import { AutoForm, Field, AsyncSelect } from '@voltro/web'
181
+
182
+ <AutoForm api="app" mutation="todos.create">
183
+ {() => (
184
+ <>
185
+ <Field name="title" /> {/* auto */}
186
+ <Field name="assigneeId">
187
+ {(w) => <AsyncSelect {...w} api="app" source="users.search" />} {/* live picker */}
188
+ </Field>
189
+ </>
190
+ )}
191
+ </AutoForm>
192
+ ```
193
+ - **Rung 2 — swap a widget kind app-wide** via the registry:
194
+ ```tsx
195
+ import { WidgetRegistryProvider } from '@voltro/web'
196
+ import { shadcnWidgets } from '@voltro/ui-shadcn'
197
+ <WidgetRegistryProvider widgets={shadcnWidgets}>{/* AutoForms render styled */}</WidgetRegistryProvider>
198
+ ```
199
+ - **Rung 3 — own the layout.** Pass children + arrange `<Field>`s (columns,
200
+ sections, tabs); each still auto-renders.
201
+ - **Eject (headless).** `useFormBinding('app', 'todos.create')` returns
202
+ `{ fields, values, errors, isValid, pending, setValue, submit, reset }` for
203
+ 100% custom JSX — the binding stays.
204
+
205
+ ## `<DataTable>` — bind to a QUERY
206
+
207
+ Columns come from the query's output `Schema`; rows are a LIVE subscription
208
+ (update on any write, no refetch); headers sort client-side.
209
+
210
+ ```tsx
211
+ import { DataTable } from '@voltro/web'
212
+
213
+ <DataTable
214
+ api="app"
215
+ query="todos.list"
216
+ rowActions={(row) => <button onClick={() => del.mutate({ id: row.id })}>Delete</button>}
217
+ />
218
+ ```
219
+
220
+ **Live** — the same demo todos, with per-row actions wired to the toggle +
221
+ delete mutations. Open this page in a second tab and toggle or delete a row:
222
+ the other tab updates instantly, no refetch — that's the reactive query, not a
223
+ poll.
224
+
225
+ ```tsx
226
+ <DataTable
227
+ api="docs"
228
+ query="todos.list"
229
+ rowActions={(row) => (
230
+ <>
231
+ <button onClick={() => toggle.mutate({ id: row.id, done: !row.done })}>Done</button>
232
+ <button onClick={() => del.mutate({ id: row.id })}>Delete</button>
233
+ </>
234
+ )}
235
+ />
236
+ ```
237
+
238
+ Headless eject: `useDataTable('app', 'todos.list', { initialSort, pageSize })`
239
+ → `{ columns, rows, loading, error, sort, toggleSort, loadMore, hasMore }`.
240
+ `pageSize` opts into LIVE grow-the-window pagination (a "Load more" button; the
241
+ query applies `.limit(input.limit)`) — rows stay reactive as the window grows.
242
+ `renderCell` / `rowKey` / `emptyText` / `loadMoreText` cover the common overrides.
243
+
244
+ ## Query-bound pickers
245
+
246
+ A picker binds to a query the way a form binds to a mutation. `<AsyncSelect>`
247
+ (or the headless `useQueryField`) drives a debounced, LIVE typeahead off a
248
+ source query — the option list updates reactively when the rows change:
249
+
250
+ ```tsx
251
+ const picker = useQueryField('app', 'users.search', { labelField: 'name', valueField: 'id' })
252
+ // → { options, loading, term, search(term) }
253
+ ```
254
+
255
+ Three cases need zero config because the schema says enough: an `enum` →
256
+ `select` (the options ARE the union); a `reference()` column → defaults to
257
+ `async-select` on the conventional `users.search`; a create-on-the-fly combobox
258
+ = a picker bound to a query (search) AND a mutation (`tags.create`).
259
+
260
+ ## Skeletons — shape-matched loading, no CLS
261
+
262
+ While a bound query/mutation loads, render a placeholder shaped like the real
263
+ thing — derived from the same descriptor, so the swap causes zero layout shift.
264
+
265
+ ```tsx
266
+ import { FormSkeleton, TableSkeleton } from '@voltro/web'
267
+ <FormSkeleton api="app" mutation="todos.create" /> {/* right field count */}
268
+ <TableSkeleton api="app" query="todos.list" rows={8} /> {/* right columns */}
269
+ ```
270
+
271
+ ## Filters — the read-side AutoForm
272
+
273
+ A query's INPUT Schema IS the filter spec. `<QueryFilters>` generates a control
274
+ per filterable input field; values map to the query input; the result + count
275
+ update LIVE (the query is a subscription).
276
+
277
+ ```tsx
278
+ import { QueryFilters } from '@voltro/web'
279
+
280
+ <QueryFilters api="app" query="todos.list">
281
+ {(f) => <DataTable api="app" query="todos.list" /* … */ />}
282
+ </QueryFilters>
283
+ ```
284
+
285
+ Headless core: `useQueryFilters('app', 'todos.list')` →
286
+ `{ filters, values, setFilter, clear, rows, count, loading }`.
287
+
288
+ ## The schema rule (load-bearing)
289
+
290
+ A descriptor's `input` MUST be `effect/Schema` — that's what the form, the wire,
291
+ and the capability map introspect. **Never put Zod (or another validator) in a
292
+ `*.mutation.ts` / `*.query.ts` descriptor.** Client-side EXTRA validation
293
+ (beyond the descriptor) may use any Standard-Schema validator.
294
+
295
+
296
+
297
+ ---
298
+
299
+ <!-- source: en/ui/reactive-components.md -->
300
+ ## Reactive components
301
+
302
+ _Drop-in UI for durable workflows, presence/multiplayer, and AI chat — bound to backend primitives the framework already has, never polling._
303
+
304
+ UI over the framework's durable + reactive backend. Each has a headless hook
305
+ (the escape hatch) + a styled component. Components from `@voltro/web`, hooks
306
+ from `@voltro/client`.
307
+
308
+ ## Workflow-aware UI
309
+
310
+ No other framework has a UI vocabulary for durable execution. Bind to a workflow
311
+ run id; the timeline + wait-states push reactively (no status-poll endpoint to
312
+ wire). `useWorkflowRunState('app', runId)` is the headless aggregator over the
313
+ EXISTING run/steps/events subscriptions → `{ status, steps, currentStep,
314
+ waitingFor, error, traceId, cancel, resume, signal, update }`.
315
+
316
+ ```tsx
317
+ import { WorkflowProgress, WorkflowStatusBadge, ApprovalControls } from '@voltro/web'
318
+ import { useWorkflowRunState } from '@voltro/client'
319
+
320
+ const run = useWorkflowRunState('app', runId)
321
+ <WorkflowProgress api="app" runId={runId} /> {/* live step timeline */}
322
+ <WorkflowStatusBadge api="app" runId={runId} /> {/* status + failing step + trace hint */}
323
+
324
+ // Approve/Reject a parked awaitSignal — renders ONLY while the run waits on it:
325
+ <ApprovalControls
326
+ when={run.waitingFor?.name === 'approval'}
327
+ onApprove={() => run.signal('approval', { approved: true })}
328
+ onReject={() => run.signal('approval', { approved: false })}
329
+ />
330
+ ```
331
+
332
+ Signal/update payloads are schema-typed (declared on the workflow's `messages`
333
+ metadata) — don't pass stringly-typed blobs.
334
+
335
+ ## Reactive multiplayer
336
+
337
+ `@voltro/plugin-presence` ships ephemeral "who's online" per channel. Combined
338
+ with the reactive engine, live-collaboration primitives become drop-ins —
339
+ prop-driven so the kit stays plugin-agnostic. Feed them the roster from
340
+ `usePresence` (`@voltro/plugin-presence/web`):
341
+
342
+ ```tsx
343
+ import { PresenceAvatars, EditingIndicator } from '@voltro/web'
344
+ import { usePresence, useTyping } from '@voltro/plugin-presence/web'
345
+
346
+ const members = usePresence(`doc:${docId}`, { meta: { name, field: 'title' } })
347
+ <PresenceAvatars members={members} max={5} />
348
+ <EditingIndicator members={members} selfKey={myId} field="title" />
349
+
350
+ const typing = useTyping(`thread:${threadId}`, { selfKey: myId }) // { active, isTyping, start, stop }
351
+ ```
352
+
353
+ Live cursors ride an ephemeral broadcast lane, NEVER the durable presence table
354
+ — don't write cursor positions at 60fps to a swept table.
355
+
356
+ ## AI chat — `<AgentChat>`
357
+
358
+ A complete chat over an agent's synthesized `*.send` + `*.messages` — durable +
359
+ reactive, so reconnect/reload-surviving for free. Render from the persisted
360
+ `parts` (text / reasoning / tool / source / file) so reload === live.
361
+
362
+ ```tsx
363
+ import { AgentChat, AgentStream, AppAgent } from '@voltro/web'
364
+ import { useAgentChat } from '@voltro/client'
365
+
366
+ const threadId = useRef(`thread_${crypto.randomUUID().replace(/-/g, '')}`).current
367
+ <AgentChat api="app" agent="support" threadId={threadId} />
368
+
369
+ // Headless — render your own bubbles from chat.messages[i].parts:
370
+ <AgentStream api="app" agent="support" threadId={threadId}>
371
+ {(chat) => chat.messages.map((m) => /* … */)}
372
+ </AgentStream>
373
+ ```
374
+
375
+ `<AppAgent>` is the end-user "do it for me" agent: `<AgentChat>` + a tools
376
+ disclosure (it acts AS the logged-in subject, so its ceiling is the subject's
377
+ permissions). Don't hand-wire `useResumableAgentStream` + a bubble list for a
378
+ standard chat — `<AgentChat>` is the supported path; reach for the resumable
379
+ hook directly only for a TRANSIENT (non-persisted) run over a `*.stream.ts`.
380
+
381
+
382
+
383
+ ---
384
+
385
+ <!-- source: en/ui/client-utilities/use-can.md -->
386
+ ## useCan
387
+
388
+ _Gate UI on the same scope strings the server enforces — reactive permissions._
389
+
390
+ Gate UI on the SAME scope strings the server's `requireScope` checks — one
391
+ source of truth, no separate frontend permission list. Feed the subject's scopes
392
+ (from your session query) to `<PermissionProvider>`; `useCan` reads them.
393
+
394
+ ```tsx
395
+ import { PermissionProvider, useCan } from '@voltro/web'
396
+
397
+ <PermissionProvider scopes={session.scopes}>…</PermissionProvider>
398
+ const canDelete = useCan('todos:delete') // ADMIN bypasses; deny-by-default
399
+ ```
400
+
401
+ UX only — the server still enforces. Pairs with `<AutoForm>` / `<DataTable>` to
402
+ auto-hide actions the subject can't perform.
403
+
404
+
405
+
406
+ ---
407
+
408
+ <!-- source: en/ui/client-utilities/use-derived.md -->
409
+ ## useDerived
410
+
411
+ _A value computed from reactive sources, recomputed only when a source changes._
412
+
413
+ A value computed from reactive sources (subscription snapshots), recomputed only
414
+ when a source changes, same reference otherwise — the formula layer.
415
+
416
+ ```tsx
417
+ const total = useDerived({ cart: cart ?? [], tax }, ({ cart, tax }) =>
418
+ cart.reduce((s, i) => s + i.price, 0) * (1 + tax))
419
+ ```
420
+
421
+ A derived value that needs the DB is a computed *query* (server), not this.
422
+
423
+
424
+
425
+ ---
426
+
427
+ <!-- source: en/ui/client-utilities/use-preview.md -->
428
+ ## usePreview
429
+
430
+ _Mutation dry-run — the {old,new} diff in a rolled-back transaction before commit._
431
+
432
+ "What will this change?" The app exposes a preview action that runs the real
433
+ handler in a transaction the framework **rolls back** (`previewInRollback` +
434
+ `buildPreview` from `@voltro/runtime`); `usePreview` returns the `{old,new}` diff
435
+ before commit. Actions (external I/O) aren't previewable — same boundary as undo.
436
+
437
+ ```tsx
438
+ const p = usePreview('app', 'todos.update.preview')
439
+ const diff = await p.preview({ id, title }) // { rows, summary } — nothing committed
440
+ ```
441
+
442
+
443
+
444
+ ---
445
+
446
+ <!-- source: en/ui/client-utilities/use-async-validation.md -->
447
+ ## useAsyncValidation
448
+
449
+ _DB-backed field validation as the user types — debounced, typed, over a query._
450
+
451
+ Async checks that need the DB (uniqueness, cross-row rules) run reactively as the
452
+ user types, debounced + typed, over a query — the same query gates submit.
453
+
454
+ ```tsx
455
+ const email = useAsyncValidation('app', 'users.emailAvailable', value, {
456
+ input: (v) => ({ email: v }),
457
+ interpret: (r) => ({ valid: r.available, message: r.available ? undefined : 'Email taken' }),
458
+ }) // email.status: 'idle' | 'checking' | 'valid' | 'invalid'
459
+ ```
460
+
461
+
462
+
463
+ ---
464
+
465
+ <!-- source: en/ui/client-utilities/record-view.md -->
466
+ ## RecordView
467
+
468
+ _Live read-only detail view for one record plus its eager-loaded relations._
469
+
470
+ The read counterpart to `<AutoForm>`: a live detail view for one record + its
471
+ eager-loaded relations (scalars → a definition list; arrays → nested tables).
472
+ `useRecord('app', 'users.get', { id })` is the headless core.
473
+
474
+ ```tsx
475
+ import { RecordView } from '@voltro/web'
476
+ <RecordView api="app" query="users.get" input={{ id }} />
477
+ ```
478
+
479
+
480
+
481
+ ---
482
+
483
+ <!-- source: en/ui/client-utilities/use-provenance.md -->
484
+ ## useProvenance
485
+
486
+ _Last-write attribution (actor + traceId) for a (table, id, column)._
487
+
488
+ "Why is this value here?" Last-write attribution (audit actor + traceId) for a
489
+ `(table, id, column)`, over `/_voltro/inspect/provenance`. Out-of-band /
490
+ un-audited rows report no attribution (never a fabricated actor); computed
491
+ values are set-level. Available in dev.
492
+
493
+ ```tsx
494
+ const prov = useProvenance('app', 'invoices', invoiceId, 'status')
495
+ // → { value, lastWrite: { actor, at, traceId }, attribution, found }
496
+ ```
497
+
498
+
499
+
500
+ ---
501
+
502
+ <!-- source: en/ui/client-utilities/use-undo.md -->
503
+ ## useUndoLog
504
+
505
+ _Universal end-user undo + redo over mutations, server-persisted via synthesized inverses._
506
+
507
+ End-user Ctrl-Z over mutations, **server-backed**. When undo capture is on, the
508
+ framework records each mutation's change-set (the CDC `{old,new}` per row) into
509
+ `_voltro_undo_log` — inside the mutation's own transaction, so a rolled-back
510
+ write leaves no entry. Three built-in rpc procedures expose it, typed
511
+ end-to-end via codegen:
512
+
513
+ - `__voltro.undo.log` — a reactive, **subject-scoped** feed of your recent
514
+ undoable actions (newest first).
515
+ - `__voltro.undo.apply` / `__voltro.undo.redo` — undo / redo one invocation by id.
516
+
517
+ `useUndoLog(api)` is the client controller:
518
+
519
+ ```tsx
520
+ const undo = useUndoLog('app')
521
+ // → { entries, loading, canUndo, canRedo, undo, redo, undoLast, redoLast }
522
+
523
+ <button disabled={!undo.canUndo} onClick={() => undo.undoLast()}>Undo</button>
524
+ <button disabled={!undo.canRedo} onClick={() => undo.redoLast()}>Redo</button>
525
+ ```
526
+
527
+ Undo applies the synthesized inverse as a **normal store write** — it traverses
528
+ the same tenant/RBAC guards, is reactive (the affected rows reappear / vanish
529
+ live, even across tabs), and is audited. It is **per-actor** (you can't undo
530
+ another subject's action), refuses on a concurrent-change **conflict** or past
531
+ an **action** boundary (an external side effect), and is idempotent. Because the
532
+ stack lives on the server, it survives a page reload.
533
+
534
+ ## Enabling — `VOLTRO_UNDO`
535
+
536
+ Capture has a per-mutation cost (a read-before-write on update/delete + a
537
+ log-row insert), so it's **on outside production, off in production** by default;
538
+ set `VOLTRO_UNDO=on|off` to override (the same environment-aware default the
539
+ durable trace persistence uses). When off, the table isn't created, nothing is
540
+ captured, and the built-ins aren't served or codegen'd.
541
+
542
+ ## Boundaries
543
+
544
+ Captures writes made through `ctx.store` (the same scope CDC covers) — raw
545
+ `unsafe()` SQL writes and the bulk helpers (`updateMany` / `deleteMany` /
546
+ `upsert`) aren't captured. Undo of an action-crossing invocation is refused
547
+ (the engine's "can't undo past an external effect" wall).
548
+
549
+
550
+
551
+ ---
552
+
553
+ <!-- source: en/ui/client-utilities/analytics-catalog.md -->
554
+ ## Analytics catalog
555
+
556
+ _Typed analytics — defineEvent + createAnalytics; track is compile-checked._
557
+
558
+ Declared, Schema-typed events: `track` is typed against the catalog (wrong name
559
+ / payload = a compile error) + validated at runtime. One discoverable taxonomy.
560
+
561
+ ```tsx
562
+ const analytics = createAnalytics([
563
+ defineEvent('checkout.started', Schema.Struct({ plan: Schema.String })),
564
+ ], sink)
565
+ analytics.track('checkout.started', { plan: 'pro' }) // typed + validated
566
+ ```
567
+
568
+ Builds on `defineTracking` (the declarative per-component event map).
569
+
570
+
571
+
572
+ ---
573
+
574
+ <!-- source: en/ui/client-utilities/use-outbox.md -->
575
+ ## useOutbox
576
+
577
+ _Queue mutations offline, replay them in order on reconnect._
578
+
579
+ Queue mutations while offline, replay IN ORDER on reconnect — over the existing
580
+ optimistic layer. Replay stops at the first conflict to preserve causality. NOT
581
+ multi-device CRDT (single-user/device, honest about its limits).
582
+
583
+ ```tsx
584
+ const outbox = useOutbox({ send })
585
+ // → { queue, enqueue, replay, online, pending, conflicts }
586
+ ```
587
+
588
+
589
+
590
+ ---
591
+
592
+ <!-- source: en/ui/client-utilities/use-windowed-subscription.md -->
593
+ ## useWindowedSubscription
594
+
595
+ _Subscribe to only the visible viewport of a huge table — live and bounded._
596
+
597
+ For a huge table, subscribe to only the visible viewport (offset+limit from
598
+ scroll); the server pushes deltas only for in-window rows — live AND bounded.
599
+
600
+ ```tsx
601
+ const w = useWindowedSubscription('app', 'rows.list', { rowHeight: 32, viewportHeight: 480, total })
602
+ <div style={{ height: 480, overflow: 'auto' }} onScroll={w.onScroll}>
603
+ <div style={{ height: w.topSpacer }} />
604
+ {w.rows.map(/* … */)}
605
+ <div style={{ height: w.bottomSpacer }} />
606
+ </div>
607
+ ```
@@ -0,0 +1,42 @@
1
+ # Security
2
+
3
+ > How Voltro handles security — reporting a vulnerability, the supply-chain gates (dependency audit, inbound-license allowlist, SBOM), supported versions, and why self-hosting keeps your data yours.
4
+
5
+
6
+
7
+ ---
8
+
9
+ <!-- source: en/security/overview.md -->
10
+ ## Overview
11
+
12
+ _How Voltro handles security — reporting a vulnerability, the supply-chain gates (dependency audit, inbound-license allowlist, SBOM), supported versions, and why self-hosting keeps your data yours._
13
+
14
+ Security is a first-class concern, not an afterthought. This page is the public summary of how we handle it; the machine-readable policy also ships as a `SECURITY.md` inside every `@voltro/*` package.
15
+
16
+ ## Reporting a vulnerability
17
+
18
+ Please report suspected vulnerabilities **privately** — never in public issues or channels.
19
+
20
+ - **Email [support@voltro.dev](mailto:support@voltro.dev)** with the subject `SECURITY`.
21
+ - Include the affected package(s) and version(s), the impact, and a minimal reproduction if you have one.
22
+
23
+ You'll get an **acknowledgement within 3 business days**, an assessment once we've reproduced the issue, and a **coordinated disclosure** timeline agreed with you — with credit in the release notes if you'd like it. We don't run a paid bug-bounty program yet, but we genuinely value responsible disclosure.
24
+
25
+ ## Supply-chain assurance
26
+
27
+ Every release passes automated supply-chain gates in CI before a single package is published:
28
+
29
+ - **Dependency audit.** The production dependency graph is audited on every build (`pnpm audit --prod`); a HIGH or CRITICAL advisory **fails the release**. Known-but-unfixed-upstream transitives are pinned deliberately, not waved through.
30
+ - **Inbound-license allowlist.** Every third-party runtime dependency's license is checked against an allowlist — a disallowed license **fails the release**. The aggregated attributions ship as `THIRD-PARTY-NOTICES.md` in each package.
31
+ - **SBOM.** A CycloneDX Software Bill of Materials of the third-party runtime graph is generated for, and attached to, each release. If your procurement or security team needs it, request it at [support@voltro.dev](mailto:support@voltro.dev).
32
+ - **Release integrity.** Publishing is gated behind organization 2FA and a narrowly-scoped, short-lived automation token, and is all-or-nothing (two-phase) so consumers never see a half-published release.
33
+
34
+ ## Supported versions
35
+
36
+ Voltro is pre-1.0 and ships in lockstep — all `@voltro/*` packages share one version. **Only the latest published release receives security fixes.** Pin exact versions in production and upgrade promptly.
37
+
38
+ ## Your data stays yours
39
+
40
+ Voltro is **self-hosted**: it runs next to *your* database, with *your* connection string, *your* backups, and *your* access controls. **When you self-host**, the framework never proxies your data through Voltro infrastructure — there is no phone-home and no hosted control plane in the request path; the runtime is a library that lives in your own deployment.
41
+
42
+ Managed **Voltro Cloud** is coming as a separate, opt-in deploy target. Choosing it means running your workload on Voltro-operated infrastructure under its own data-processing terms — a deliberate choice, not the default. Self-hosting remains the default and keeps the guarantees above.