@podosoft/podokit 0.17.3 → 1.0.1

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 (683) hide show
  1. package/README.md +70 -114
  2. package/dist/add.d.ts +3 -2
  3. package/dist/add.js +18 -8
  4. package/dist/assemble.d.ts +2 -0
  5. package/dist/assemble.js +18 -5
  6. package/dist/create.d.ts +8 -4
  7. package/dist/create.js +16 -6
  8. package/dist/deploy-compose-profile.js +1 -0
  9. package/dist/deploy-compose-render.d.ts +1 -1
  10. package/dist/deploy-compose-render.js +6 -3
  11. package/dist/deploy-compose-sync.d.ts +10 -14
  12. package/dist/deploy-compose-sync.js +21 -22
  13. package/dist/deploy-compose.js +4 -1
  14. package/dist/deploy-profile.d.ts +1 -0
  15. package/dist/deploy-profile.js +9 -1
  16. package/dist/deploy-render.js +23 -8
  17. package/dist/deploy-schema.js +6 -1
  18. package/dist/dev.d.ts +1 -0
  19. package/dist/dev.js +63 -14
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +15 -9
  22. package/dist/inspect.d.ts +3 -1
  23. package/dist/inspect.js +6 -4
  24. package/dist/lockfile.d.ts +8 -3
  25. package/dist/lockfile.js +18 -4
  26. package/dist/prompt.d.ts +5 -12
  27. package/dist/prompt.js +5 -22
  28. package/dist/remove.js +10 -5
  29. package/dist/templates/base/AGENTS.md +8 -6
  30. package/dist/templates/base/README.md +2 -2
  31. package/dist/templates/base/apps/api/src/main.ts +1 -1
  32. package/dist/templates/base/bunfig.toml +3 -0
  33. package/dist/templates/base/package.json +5 -4
  34. package/dist/templates/{fullstack-nest-svelte → fullstack}/AGENTS.md +19 -12
  35. package/dist/templates/fullstack/Dockerfile.dev +31 -0
  36. package/dist/templates/{fullstack-nest-svelte → fullstack}/README.md +35 -18
  37. package/dist/templates/fullstack/apps/api/Dockerfile +47 -0
  38. package/dist/templates/fullstack/apps/api/package.json +35 -0
  39. package/dist/templates/fullstack/apps/api/scripts/build.mjs +38 -0
  40. package/dist/templates/fullstack/apps/api/scripts/verify-api-contract.ts +37 -0
  41. package/dist/templates/fullstack/apps/api/src/app.extensions.ts +10 -0
  42. package/dist/templates/fullstack/apps/api/src/app.ts +162 -0
  43. package/dist/templates/{todo → fullstack}/apps/api/src/config/redis.connection.spec.ts +20 -2
  44. package/dist/templates/{todo → fullstack}/apps/api/src/config/redis.connection.ts +16 -0
  45. package/dist/templates/fullstack/apps/api/src/core/api-contract.spec.ts +59 -0
  46. package/dist/templates/fullstack/apps/api/src/core/api-contract.ts +169 -0
  47. package/dist/templates/fullstack/apps/api/src/core/services.spec.ts +90 -0
  48. package/dist/templates/fullstack/apps/api/src/core/services.ts +208 -0
  49. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/src/database/data-source.ts +8 -3
  50. package/dist/templates/fullstack/apps/api/src/database/database.ts +25 -0
  51. package/dist/templates/fullstack/apps/api/src/health/health.plugin.ts +28 -0
  52. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/src/health/readiness.service.spec.ts +1 -1
  53. package/dist/templates/{todo → fullstack}/apps/api/src/health/readiness.service.ts +0 -3
  54. package/dist/templates/fullstack/apps/api/src/main.ts +30 -0
  55. package/dist/templates/{todo → fullstack}/apps/api/tsconfig.json +1 -2
  56. package/dist/templates/fullstack/apps/web/Dockerfile +41 -0
  57. package/dist/templates/{todo → fullstack}/apps/web/components.json +3 -3
  58. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/package.json +13 -10
  59. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/app.html +0 -1
  60. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/alert/alert-action.svelte +1 -1
  61. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/alert/alert-description.svelte +1 -1
  62. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/alert/alert-title.svelte +1 -1
  63. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/alert/alert.svelte +1 -1
  64. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +1 -1
  65. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +1 -1
  66. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +1 -1
  67. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +1 -1
  68. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +1 -1
  69. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/avatar/avatar.svelte +1 -1
  70. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/badge/badge.svelte +1 -1
  71. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/button/button.svelte +1 -1
  72. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/card/card-action.svelte +1 -1
  73. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/card/card-content.svelte +1 -1
  74. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/card/card-description.svelte +1 -1
  75. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/card/card-footer.svelte +1 -1
  76. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/card/card-header.svelte +1 -1
  77. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/card/card-title.svelte +1 -1
  78. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/card/card.svelte +1 -1
  79. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/checkbox/checkbox.svelte +1 -1
  80. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +2 -2
  81. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +1 -1
  82. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +2 -2
  83. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +1 -1
  84. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +1 -1
  85. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +1 -1
  86. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
  87. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
  88. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
  89. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
  90. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +1 -1
  91. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
  92. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +1 -1
  93. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
  94. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
  95. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
  96. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/input/input.svelte +1 -1
  97. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/label/label.svelte +1 -1
  98. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-content.svelte +2 -2
  99. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/select/select-group-heading.svelte +1 -1
  100. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-group.svelte +1 -1
  101. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-item.svelte +1 -1
  102. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/select/select-label.svelte +1 -1
  103. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +1 -1
  104. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +1 -1
  105. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-separator.svelte +2 -2
  106. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/select/select-trigger.svelte +1 -1
  107. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/separator/separator.svelte +1 -1
  108. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +1 -1
  109. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/switch/switch.svelte +1 -1
  110. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-body.svelte +1 -1
  111. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-caption.svelte +1 -1
  112. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-cell.svelte +1 -1
  113. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/table/table-footer.svelte +1 -1
  114. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-head.svelte +1 -1
  115. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-header.svelte +1 -1
  116. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table-row.svelte +1 -1
  117. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/table.svelte +1 -1
  118. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +1 -1
  119. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +1 -1
  120. package/dist/templates/{todo → fullstack}/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +1 -1
  121. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tabs/tabs.svelte +1 -1
  122. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +2 -2
  123. package/dist/templates/{todo → fullstack}/apps/web/src/lib/server/api.ts +9 -6
  124. package/dist/templates/{todo → fullstack}/apps/web/src/lib/server/backend-proxy.test.ts +25 -0
  125. package/dist/templates/{todo → fullstack}/apps/web/src/lib/server/backend-proxy.ts +8 -1
  126. package/dist/templates/fullstack/apps/web/src/routes/+layout.svelte +14 -0
  127. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/routes/+page.svelte +5 -5
  128. package/dist/templates/{todo → fullstack}/apps/web/src/routes/api/[...path]/+server.ts +1 -1
  129. package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/routes/api/auth/[...all]/+server.ts +1 -1
  130. package/dist/templates/{todo → fullstack}/apps/web/tsconfig.json +3 -2
  131. package/dist/templates/fullstack/apps/web/vite.config.ts +25 -0
  132. package/dist/templates/fullstack/bunfig.toml +3 -0
  133. package/dist/templates/{todo → fullstack}/compose.dev.yaml +8 -38
  134. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy/SKILL.md +5 -5
  135. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy/references/profile.md +5 -3
  136. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy/references/rollback.md +2 -2
  137. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy-fast/SKILL.md +3 -3
  138. package/dist/templates/{todo → fullstack}/dot-claude/skills/podokit-add-module/SKILL.md +2 -2
  139. package/dist/templates/fullstack/dot-claude/skills/podokit-elysia-endpoint/SKILL.md +27 -0
  140. package/dist/templates/{todo → fullstack}/dot-claude/skills/podokit-sveltekit-route/SKILL.md +4 -4
  141. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-update/SKILL.md +3 -1
  142. package/dist/templates/{todo → fullstack}/dot-devcontainer/devcontainer.json +1 -1
  143. package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-env.example +1 -7
  144. package/dist/templates/{todo → fullstack}/dot-github/workflows/release.yml +5 -8
  145. package/dist/templates/fullstack/dot-mcp.json +8 -0
  146. package/dist/templates/fullstack/dot-podokit/dev.json +5 -0
  147. package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/docker/docker-compose.yml +2 -2
  148. package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/docker/sms-sink.mjs +2 -1
  149. package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/README.md +5 -0
  150. package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/configmap.yaml +2 -0
  151. package/dist/templates/fullstack/package.json +27 -0
  152. package/dist/templates/{fullstack-nest-svelte → fullstack}/tests/README.md +6 -6
  153. package/dist/templates/fullstack/tests/package.json +15 -0
  154. package/dist/templates/{fullstack-nest-svelte → fullstack}/tests/ui/smoke.ui.spec.ts +2 -1
  155. package/dist/templates/modules/admin-dashboard/files/apps/api/scripts/bootstrap-admin.mjs +4 -4
  156. package/dist/templates/modules/admin-dashboard/files/apps/api/src/admin.module.ts +153 -0
  157. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.service.spec.ts +13 -13
  158. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.service.ts +34 -22
  159. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.validation.spec.ts +7 -7
  160. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.validation.ts +5 -6
  161. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.service.ts +31 -29
  162. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.validation.spec.ts +22 -0
  163. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.validation.ts +73 -0
  164. package/dist/templates/modules/admin-dashboard/files/apps/web/src/app.d.ts +2 -2
  165. package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +7 -6
  166. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/registry.svelte.ts +1 -1
  167. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/auth-redirect.ts +1 -1
  168. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-menu.svelte +6 -6
  169. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-page.svelte +16 -13
  170. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/admin-sidebar.svelte +3 -3
  171. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/data-table.svelte +4 -4
  172. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/impersonation-banner.svelte +24 -0
  173. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/language-switch.svelte +4 -4
  174. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/session-idle-timeout.svelte +1 -1
  175. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/settings/appearance-card.svelte +10 -10
  176. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +4 -4
  177. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-footer.svelte +2 -2
  178. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-runtime.svelte +3 -3
  179. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/table-pagination.svelte +1 -1
  180. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/table-toolbar.svelte +4 -4
  181. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/theme-toggle.svelte +3 -3
  182. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-content.svelte +1 -1
  183. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-ellipsis.svelte +1 -1
  184. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-item.svelte +1 -1
  185. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-link.svelte +2 -2
  186. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next-button.svelte +1 -1
  187. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next.svelte +2 -2
  188. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-prev-button.svelte +1 -1
  189. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-previous.svelte +2 -2
  190. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination.svelte +1 -1
  191. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-content.svelte +2 -2
  192. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-description.svelte +1 -1
  193. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-footer.svelte +1 -1
  194. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-header.svelte +1 -1
  195. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-overlay.svelte +1 -1
  196. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-title.svelte +1 -1
  197. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/context.svelte.ts +1 -1
  198. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-content.svelte +1 -1
  199. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-footer.svelte +1 -1
  200. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-action.svelte +1 -1
  201. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-content.svelte +1 -1
  202. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-label.svelte +1 -1
  203. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group.svelte +1 -1
  204. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-header.svelte +1 -1
  205. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-input.svelte +2 -2
  206. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-inset.svelte +1 -1
  207. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-action.svelte +1 -1
  208. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte +1 -1
  209. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +2 -2
  210. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-item.svelte +1 -1
  211. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte +2 -2
  212. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +1 -1
  213. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte +1 -1
  214. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte +1 -1
  215. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu.svelte +1 -1
  216. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-provider.svelte +2 -2
  217. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-rail.svelte +1 -1
  218. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-separator.svelte +2 -2
  219. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-trigger.svelte +2 -2
  220. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar.svelte +2 -2
  221. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/user-avatar.svelte +1 -1
  222. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/index.ts +1 -1
  223. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/+layout.server.ts +2 -2
  224. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/+layout.svelte +8 -20
  225. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/+page.svelte +3 -3
  226. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/account/+page.svelte +1 -1
  227. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/audit/+page.server.ts +1 -1
  228. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/audit/+page.svelte +5 -5
  229. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/organizations/+page.server.ts +1 -1
  230. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/organizations/+page.svelte +10 -10
  231. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/sessions/+page.server.ts +1 -1
  232. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/sessions/+page.svelte +9 -9
  233. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/settings/+page.server.ts +1 -1
  234. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/settings/+page.svelte +13 -13
  235. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/settings/general-settings.svelte +10 -10
  236. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/users/+page.server.ts +1 -1
  237. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/users/+page.svelte +18 -17
  238. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/+layout.server.ts +1 -1
  239. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/accept-invitation/[id]/+page.svelte +4 -4
  240. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/+layout.svelte +2 -2
  241. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/forgot-password/+page.svelte +7 -7
  242. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/login/+page.svelte +10 -10
  243. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/pending-approval/+page.svelte +3 -3
  244. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/reset-password/+page.svelte +7 -7
  245. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/signup/+page.svelte +9 -9
  246. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/verify-email/+page.svelte +7 -7
  247. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.server.ts +3 -3
  248. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+page.svelte +6 -6
  249. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.server.ts +9 -2
  250. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.svelte +12 -8
  251. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/maintenance/+page.svelte +4 -4
  252. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/oauth2/consent/+page.svelte +3 -3
  253. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/setup-2fa/+page.server.ts +2 -2
  254. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/setup-2fa/+page.svelte +14 -10
  255. package/dist/templates/modules/admin-dashboard/files/dot-claude/skills/podokit-data-table/SKILL.md +3 -3
  256. package/dist/templates/modules/admin-dashboard/files/tests/helpers/accounts.ts +17 -2
  257. package/dist/templates/modules/admin-dashboard/files/tests/helpers/disposable-users.ts +29 -12
  258. package/dist/templates/modules/admin-dashboard/files/tests/helpers/hydration.ts +4 -4
  259. package/dist/templates/modules/admin-dashboard/files/tests/ui/account-flows.ui.spec.ts +4 -2
  260. package/dist/templates/modules/admin-dashboard/files/tests/ui/account.ui.spec.ts +51 -0
  261. package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +2 -2
  262. package/dist/templates/modules/admin-dashboard/files/tests/ui/impersonation.ui.spec.ts +4 -2
  263. package/dist/templates/modules/admin-dashboard/files/tests/ui/oidc.ui.spec.ts +16 -11
  264. package/dist/templates/modules/admin-dashboard/files/tests/ui/passkey.ui.spec.ts +3 -2
  265. package/dist/templates/modules/admin-dashboard/files/tests/ui/two-factor.ui.spec.ts +40 -7
  266. package/dist/templates/modules/admin-dashboard/module.manifest.json +14 -24
  267. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key-verifier.spec.ts +1 -1
  268. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key-verifier.ts +0 -2
  269. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.spec.ts +21 -0
  270. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.ts +36 -9
  271. package/dist/templates/modules/api-key-auth/module.manifest.json +4 -4
  272. package/dist/templates/modules/audit-log/files/apps/api/src/audit/README.md +17 -16
  273. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-events.ts +8 -6
  274. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-hook.ts +2 -2
  275. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +31 -12
  276. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.spec.ts +48 -0
  277. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.ts +76 -25
  278. package/dist/templates/modules/audit-log/module.manifest.json +12 -16
  279. package/dist/templates/modules/auth/files/apps/api/scripts/configure-auth.mjs +5 -5
  280. package/dist/templates/modules/auth/files/apps/api/scripts/run-migrations.mjs +14 -0
  281. package/dist/templates/modules/auth/files/apps/api/src/auth/auth-provider.ts +3 -6
  282. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.module.ts +176 -0
  283. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.openapi.spec.ts +20 -0
  284. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.openapi.ts +22 -0
  285. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.runtime.spec.ts +3 -3
  286. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.service.spec.ts +52 -0
  287. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.service.ts +78 -0
  288. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +4 -1
  289. package/dist/templates/modules/auth/files/apps/api/src/auth/user-delete-handlers.spec.ts +6 -6
  290. package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.service.ts +214 -100
  291. package/dist/templates/modules/auth/files/apps/api/src/migrations/1720400000000-InitAppSettings.ts +2 -1
  292. package/dist/templates/modules/auth/files/apps/api/src/settings/app-settings.migration.spec.ts +34 -0
  293. package/dist/templates/modules/auth/files/apps/api/src/settings/flag-defaults.ts +3 -3
  294. package/dist/templates/modules/auth/files/apps/api/src/settings/settings.service.ts +26 -30
  295. package/dist/templates/modules/auth/files/dot-claude/skills/podokit-configure-auth/SKILL.md +7 -7
  296. package/dist/templates/modules/auth/files/dot-claude/skills/podokit-configure-auth/references/bootstrap-admin.md +3 -3
  297. package/dist/templates/modules/auth/files/dot-claude/skills/podokit-configure-auth/references/google.md +3 -3
  298. package/dist/templates/modules/auth/module.manifest.json +24 -77
  299. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/demo.processor.spec.ts +10 -0
  300. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/demo.processor.ts +3 -9
  301. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/jobs.module.ts +35 -13
  302. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.ts +18 -19
  303. package/dist/templates/modules/bullmq/files/apps/api/src/main-worker.ts +12 -10
  304. package/dist/templates/modules/bullmq/files/infra/docker/worker.compose.example.yml +1 -1
  305. package/dist/templates/modules/bullmq/files/infra/k3s/worker-deployment.yaml +1 -1
  306. package/dist/templates/modules/bullmq/module.manifest.json +8 -9
  307. package/dist/templates/modules/file-upload/files/apps/api/src/files/files.module.ts +28 -8
  308. package/dist/templates/modules/file-upload/files/tests/api/files.api.spec.ts +9 -4
  309. package/dist/templates/modules/file-upload/module.manifest.json +2 -5
  310. package/dist/templates/modules/job-progress/files/apps/api/src/progress/job-progress.module.ts +33 -11
  311. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.bridge.spec.ts +6 -6
  312. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.bridge.ts +5 -13
  313. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.processor.ts +11 -18
  314. package/dist/templates/modules/job-progress/module.manifest.json +5 -8
  315. package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +15 -28
  316. package/dist/templates/modules/logging/module.manifest.json +5 -6
  317. package/dist/templates/modules/mailer/module.manifest.json +2 -2
  318. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.config.spec.ts +20 -0
  319. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.config.ts +17 -21
  320. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.module.ts +43 -9
  321. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.service.ts +26 -35
  322. package/dist/templates/modules/object-storage-s3/module.manifest.json +3 -7
  323. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.config.spec.ts +10 -4
  324. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.config.ts +13 -0
  325. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.identity.spec.ts +43 -103
  326. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.identity.ts +19 -56
  327. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.spec.ts +124 -212
  328. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +123 -87
  329. package/dist/templates/modules/rate-limit/files/tests/api/rate-limit.api.spec.ts +17 -1
  330. package/dist/templates/modules/rate-limit/module.manifest.json +17 -11
  331. package/dist/templates/modules/redis/files/apps/api/src/redis/redis.module.ts +41 -10
  332. package/dist/templates/modules/redis/files/apps/api/src/redis/redis.service.spec.ts +3 -3
  333. package/dist/templates/modules/redis/files/apps/api/src/redis/redis.service.ts +29 -51
  334. package/dist/templates/modules/redis/module.manifest.json +3 -12
  335. package/dist/templates/modules/sse/files/apps/api/src/events/events.module.ts +46 -17
  336. package/dist/templates/modules/sse/files/apps/api/src/events/events.service.spec.ts +19 -50
  337. package/dist/templates/modules/sse/files/apps/api/src/events/events.service.ts +40 -25
  338. package/dist/templates/modules/sse/files/apps/api/src/events/events.transport.ts +25 -79
  339. package/dist/templates/modules/sse/module.manifest.json +2 -5
  340. package/dist/templates/todo/AGENTS.md +15 -12
  341. package/dist/templates/todo/README.md +19 -13
  342. package/dist/templates/todo/apps/api/src/todos/todo.plugin.ts +59 -0
  343. package/dist/templates/todo/apps/api/src/todos/todo.repository.ts +69 -0
  344. package/dist/templates/todo/apps/web/src/routes/+page.svelte +7 -7
  345. package/dist/templates.js +4 -4
  346. package/dist/toolchain.d.ts +13 -0
  347. package/dist/toolchain.js +44 -0
  348. package/dist/update.d.ts +18 -1
  349. package/dist/update.js +50 -12
  350. package/dist/websocket-paths.d.ts +1 -0
  351. package/dist/websocket-paths.js +32 -0
  352. package/package.json +5 -4
  353. package/dist/templates/fullstack-nest-svelte/Dockerfile.dev +0 -58
  354. package/dist/templates/fullstack-nest-svelte/apps/api/Dockerfile +0 -88
  355. package/dist/templates/fullstack-nest-svelte/apps/api/nest-cli.json +0 -5
  356. package/dist/templates/fullstack-nest-svelte/apps/api/package.json +0 -66
  357. package/dist/templates/fullstack-nest-svelte/apps/api/src/app.extensions.ts +0 -21
  358. package/dist/templates/fullstack-nest-svelte/apps/api/src/app.module.ts +0 -26
  359. package/dist/templates/fullstack-nest-svelte/apps/api/src/common/all-exceptions.filter.ts +0 -43
  360. package/dist/templates/fullstack-nest-svelte/apps/api/src/config/redis.connection.spec.ts +0 -53
  361. package/dist/templates/fullstack-nest-svelte/apps/api/src/config/redis.connection.ts +0 -69
  362. package/dist/templates/fullstack-nest-svelte/apps/api/src/health/health.controller.ts +0 -38
  363. package/dist/templates/fullstack-nest-svelte/apps/api/src/health/health.module.ts +0 -11
  364. package/dist/templates/fullstack-nest-svelte/apps/api/src/health/readiness.service.ts +0 -33
  365. package/dist/templates/fullstack-nest-svelte/apps/api/src/main.ts +0 -29
  366. package/dist/templates/fullstack-nest-svelte/apps/api/tsconfig.json +0 -30
  367. package/dist/templates/fullstack-nest-svelte/apps/web/Dockerfile +0 -81
  368. package/dist/templates/fullstack-nest-svelte/apps/web/components.json +0 -15
  369. package/dist/templates/fullstack-nest-svelte/apps/web/server.js +0 -31
  370. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-description.svelte +0 -23
  371. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +0 -26
  372. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
  373. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -23
  374. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +0 -23
  375. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
  376. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar.svelte +0 -26
  377. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-description.svelte +0 -20
  378. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-footer.svelte +0 -20
  379. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-title.svelte +0 -20
  380. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
  381. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
  382. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +0 -20
  383. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
  384. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
  385. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -44
  386. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -31
  387. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -27
  388. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
  389. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
  390. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -29
  391. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group-heading.svelte +0 -21
  392. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-label.svelte +0 -20
  393. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-trigger.svelte +0 -29
  394. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/separator.svelte +0 -23
  395. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +0 -17
  396. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-footer.svelte +0 -20
  397. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +0 -20
  398. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +0 -20
  399. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/api.ts +0 -21
  400. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.test.ts +0 -79
  401. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.ts +0 -80
  402. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/ws-upgrade.js +0 -267
  403. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/ws-upgrade.test.js +0 -134
  404. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/+layout.svelte +0 -9
  405. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/[...path]/+server.ts +0 -16
  406. package/dist/templates/fullstack-nest-svelte/apps/web/svelte.config.js +0 -15
  407. package/dist/templates/fullstack-nest-svelte/apps/web/tsconfig.json +0 -9
  408. package/dist/templates/fullstack-nest-svelte/apps/web/vite.config.ts +0 -29
  409. package/dist/templates/fullstack-nest-svelte/compose.dev.yaml +0 -162
  410. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-add-module/SKILL.md +0 -27
  411. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-nest-endpoint/SKILL.md +0 -23
  412. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-sveltekit-route/SKILL.md +0 -23
  413. package/dist/templates/fullstack-nest-svelte/dot-devcontainer/devcontainer.json +0 -20
  414. package/dist/templates/fullstack-nest-svelte/dot-github/workflows/release.yml +0 -142
  415. package/dist/templates/fullstack-nest-svelte/dot-mcp.json +0 -8
  416. package/dist/templates/fullstack-nest-svelte/dot-podokit/dev.json +0 -4
  417. package/dist/templates/fullstack-nest-svelte/package.json +0 -21
  418. package/dist/templates/fullstack-nest-svelte/tests/package.json +0 -15
  419. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image-upload.interceptor.ts +0 -39
  420. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.controller.ts +0 -73
  421. package/dist/templates/modules/admin-dashboard/files/apps/api/src/profile-image/profile-image.module.ts +0 -9
  422. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.controller.ts +0 -155
  423. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.module.ts +0 -14
  424. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.decorator.ts +0 -9
  425. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.spec.ts +0 -49
  426. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.ts +0 -21
  427. package/dist/templates/modules/api-key-auth/files/apps/api/src/machine/machine.controller.ts +0 -14
  428. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-log.entity.ts +0 -46
  429. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.controller.ts +0 -21
  430. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.decorator.ts +0 -23
  431. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.interceptor.ts +0 -56
  432. package/dist/templates/modules/auth/files/apps/api/src/account/account.controller.ts +0 -101
  433. package/dist/templates/modules/auth/files/apps/api/src/account/account.module.ts +0 -6
  434. package/dist/templates/modules/auth/files/apps/api/src/auth/two-factor-required.guard.ts +0 -68
  435. package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.controller.ts +0 -33
  436. package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.entity.ts +0 -26
  437. package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.module.ts +0 -12
  438. package/dist/templates/modules/auth/files/apps/api/src/health/health.controller.ts +0 -41
  439. package/dist/templates/modules/auth/files/apps/api/src/settings/app-setting.entity.ts +0 -16
  440. package/dist/templates/modules/auth/files/apps/api/src/settings/settings.module.ts +0 -11
  441. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/dto/create-job.dto.ts +0 -9
  442. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/jobs.controller.ts +0 -29
  443. package/dist/templates/modules/file-upload/files/apps/api/src/files/files.controller.ts +0 -32
  444. package/dist/templates/modules/job-progress/files/apps/api/src/progress/dto/start-job.dto.ts +0 -11
  445. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.controller.ts +0 -17
  446. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/dto/put-object.dto.ts +0 -8
  447. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.controller.ts +0 -29
  448. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.service.spec.ts +0 -35
  449. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.integration.spec.ts +0 -91
  450. package/dist/templates/modules/redis/files/apps/api/src/redis/cache.controller.ts +0 -21
  451. package/dist/templates/modules/redis/files/apps/api/src/redis/dto/set-cache.dto.ts +0 -14
  452. package/dist/templates/modules/sse/files/apps/api/src/events/dto/publish-event.dto.ts +0 -8
  453. package/dist/templates/modules/sse/files/apps/api/src/events/events.controller.ts +0 -39
  454. package/dist/templates/modules/sse/files/apps/api/src/events/events.transport.redis.spec.ts +0 -42
  455. package/dist/templates/modules/sse/files/apps/api/src/events/events.transport.spec.ts +0 -97
  456. package/dist/templates/todo/CLAUDE.md +0 -6
  457. package/dist/templates/todo/Dockerfile.dev +0 -58
  458. package/dist/templates/todo/apps/api/Dockerfile +0 -88
  459. package/dist/templates/todo/apps/api/nest-cli.json +0 -5
  460. package/dist/templates/todo/apps/api/package.json +0 -66
  461. package/dist/templates/todo/apps/api/scripts/.keep +0 -1
  462. package/dist/templates/todo/apps/api/src/app.extensions.ts +0 -21
  463. package/dist/templates/todo/apps/api/src/app.module.ts +0 -28
  464. package/dist/templates/todo/apps/api/src/common/all-exceptions.filter.ts +0 -43
  465. package/dist/templates/todo/apps/api/src/common/app-exception.ts +0 -4
  466. package/dist/templates/todo/apps/api/src/config/env.validation.ts +0 -23
  467. package/dist/templates/todo/apps/api/src/database/data-source.ts +0 -19
  468. package/dist/templates/todo/apps/api/src/database/migrate.ts +0 -16
  469. package/dist/templates/todo/apps/api/src/health/health.controller.ts +0 -38
  470. package/dist/templates/todo/apps/api/src/health/health.module.ts +0 -11
  471. package/dist/templates/todo/apps/api/src/health/readiness.service.spec.ts +0 -22
  472. package/dist/templates/todo/apps/api/src/main.ts +0 -29
  473. package/dist/templates/todo/apps/api/src/todos/dto/create-todo.dto.ts +0 -10
  474. package/dist/templates/todo/apps/api/src/todos/dto/update-todo.dto.ts +0 -10
  475. package/dist/templates/todo/apps/api/src/todos/todo.entity.ts +0 -16
  476. package/dist/templates/todo/apps/api/src/todos/todos.controller.ts +0 -38
  477. package/dist/templates/todo/apps/api/src/todos/todos.module.ts +0 -12
  478. package/dist/templates/todo/apps/api/src/todos/todos.service.ts +0 -41
  479. package/dist/templates/todo/apps/web/Dockerfile +0 -78
  480. package/dist/templates/todo/apps/web/package.json +0 -38
  481. package/dist/templates/todo/apps/web/server.js +0 -31
  482. package/dist/templates/todo/apps/web/src/app.css +0 -81
  483. package/dist/templates/todo/apps/web/src/app.d.ts +0 -11
  484. package/dist/templates/todo/apps/web/src/app.html +0 -13
  485. package/dist/templates/todo/apps/web/src/lib/api.ts +0 -5
  486. package/dist/templates/todo/apps/web/src/lib/components/site-runtime.svelte +0 -7
  487. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-action.svelte +0 -20
  488. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-title.svelte +0 -23
  489. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert.svelte +0 -43
  490. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/index.ts +0 -17
  491. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/index.ts +0 -22
  492. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/badge.svelte +0 -49
  493. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/index.ts +0 -2
  494. package/dist/templates/todo/apps/web/src/lib/components/ui/button/button.svelte +0 -82
  495. package/dist/templates/todo/apps/web/src/lib/components/ui/button/index.ts +0 -17
  496. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-action.svelte +0 -23
  497. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-content.svelte +0 -20
  498. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-header.svelte +0 -23
  499. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card.svelte +0 -22
  500. package/dist/templates/todo/apps/web/src/lib/components/ui/card/index.ts +0 -25
  501. package/dist/templates/todo/apps/web/src/lib/components/ui/checkbox/index.ts +0 -6
  502. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
  503. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +0 -48
  504. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +0 -32
  505. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
  506. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
  507. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog.svelte +0 -7
  508. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/index.ts +0 -34
  509. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
  510. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -22
  511. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
  512. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -24
  513. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
  514. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
  515. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
  516. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -20
  517. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
  518. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
  519. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
  520. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/index.ts +0 -54
  521. package/dist/templates/todo/apps/web/src/lib/components/ui/input/index.ts +0 -7
  522. package/dist/templates/todo/apps/web/src/lib/components/ui/input/input.svelte +0 -48
  523. package/dist/templates/todo/apps/web/src/lib/components/ui/label/index.ts +0 -7
  524. package/dist/templates/todo/apps/web/src/lib/components/ui/label/label.svelte +0 -20
  525. package/dist/templates/todo/apps/web/src/lib/components/ui/select/index.ts +0 -37
  526. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-content.svelte +0 -45
  527. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group.svelte +0 -17
  528. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-item.svelte +0 -40
  529. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-portal.svelte +0 -7
  530. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
  531. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
  532. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-separator.svelte +0 -18
  533. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select.svelte +0 -11
  534. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/index.ts +0 -7
  535. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/index.ts +0 -7
  536. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/index.ts +0 -1
  537. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/sonner.svelte +0 -34
  538. package/dist/templates/todo/apps/web/src/lib/components/ui/switch/index.ts +0 -7
  539. package/dist/templates/todo/apps/web/src/lib/components/ui/switch/switch.svelte +0 -29
  540. package/dist/templates/todo/apps/web/src/lib/components/ui/table/index.ts +0 -28
  541. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-body.svelte +0 -15
  542. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-caption.svelte +0 -20
  543. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-cell.svelte +0 -15
  544. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-head.svelte +0 -15
  545. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-header.svelte +0 -20
  546. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-row.svelte +0 -15
  547. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table.svelte +0 -17
  548. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/index.ts +0 -16
  549. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +0 -17
  550. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs.svelte +0 -19
  551. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/index.ts +0 -19
  552. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -52
  553. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +0 -7
  554. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +0 -7
  555. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -7
  556. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +0 -7
  557. package/dist/templates/todo/apps/web/src/lib/i18n/README.md +0 -9
  558. package/dist/templates/todo/apps/web/src/lib/i18n/catalogs/app/en.json +0 -1
  559. package/dist/templates/todo/apps/web/src/lib/i18n/catalogs/app/ko.json +0 -1
  560. package/dist/templates/todo/apps/web/src/lib/i18n/locales/en.json +0 -6
  561. package/dist/templates/todo/apps/web/src/lib/i18n/locales/ko.json +0 -6
  562. package/dist/templates/todo/apps/web/src/lib/server/ws-upgrade.js +0 -267
  563. package/dist/templates/todo/apps/web/src/lib/server/ws-upgrade.test.js +0 -134
  564. package/dist/templates/todo/apps/web/src/lib/utils.ts +0 -11
  565. package/dist/templates/todo/apps/web/src/routes/+layout.svelte +0 -9
  566. package/dist/templates/todo/apps/web/src/routes/api/auth/[...all]/+server.ts +0 -16
  567. package/dist/templates/todo/apps/web/static/.gitkeep +0 -0
  568. package/dist/templates/todo/apps/web/static/favicon.svg +0 -13
  569. package/dist/templates/todo/apps/web/svelte.config.js +0 -15
  570. package/dist/templates/todo/apps/web/vite.config.ts +0 -29
  571. package/dist/templates/todo/dot-agents/skills/podokit-deploy/SKILL.md +0 -65
  572. package/dist/templates/todo/dot-agents/skills/podokit-deploy/agents/openai.yaml +0 -4
  573. package/dist/templates/todo/dot-agents/skills/podokit-deploy/references/profile.md +0 -75
  574. package/dist/templates/todo/dot-agents/skills/podokit-deploy/references/release.md +0 -64
  575. package/dist/templates/todo/dot-agents/skills/podokit-deploy/references/rollback.md +0 -5
  576. package/dist/templates/todo/dot-agents/skills/podokit-deploy-fast/SKILL.md +0 -92
  577. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/SKILL.md +0 -63
  578. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/agents/openai.yaml +0 -4
  579. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/references/catalog-format.md +0 -49
  580. package/dist/templates/todo/dot-claude/skills/podokit-deploy/SKILL.md +0 -8
  581. package/dist/templates/todo/dot-claude/skills/podokit-deploy-fast/SKILL.md +0 -8
  582. package/dist/templates/todo/dot-claude/skills/podokit-nest-endpoint/SKILL.md +0 -23
  583. package/dist/templates/todo/dot-claude/skills/podokit-update/SKILL.md +0 -26
  584. package/dist/templates/todo/dot-cursor/rules/podokit.mdc +0 -11
  585. package/dist/templates/todo/dot-dockerignore +0 -15
  586. package/dist/templates/todo/dot-env.docker +0 -26
  587. package/dist/templates/todo/dot-env.example +0 -34
  588. package/dist/templates/todo/dot-github/copilot-instructions.md +0 -6
  589. package/dist/templates/todo/dot-gitignore +0 -23
  590. package/dist/templates/todo/dot-mcp.json +0 -8
  591. package/dist/templates/todo/dot-podokit/dev.json +0 -4
  592. package/dist/templates/todo/infra/docker/docker-compose.yml +0 -33
  593. package/dist/templates/todo/infra/k3s/README.md +0 -18
  594. package/dist/templates/todo/infra/k3s/api-deployment.yaml +0 -29
  595. package/dist/templates/todo/infra/k3s/configmap.yaml +0 -12
  596. package/dist/templates/todo/infra/k3s/ingress.yaml +0 -32
  597. package/dist/templates/todo/infra/k3s/namespace.yaml +0 -4
  598. package/dist/templates/todo/infra/k3s/secret.example.yaml +0 -10
  599. package/dist/templates/todo/infra/k3s/services.yaml +0 -21
  600. package/dist/templates/todo/infra/k3s/web-deployment.yaml +0 -30
  601. package/dist/templates/todo/infra/traefik/dynamic.yml +0 -17
  602. package/dist/templates/todo/package.json +0 -21
  603. package/dist/templates/todo/tests/README.md +0 -21
  604. package/dist/templates/todo/tests/api/health.api.spec.ts +0 -14
  605. package/dist/templates/todo/tests/package.json +0 -15
  606. package/dist/templates/todo/tests/playwright.config.ts +0 -27
  607. package/dist/templates/todo/tests/playwright.extensions.ts +0 -44
  608. package/dist/templates/todo/tests/ui/smoke.ui.spec.ts +0 -8
  609. /package/dist/templates/{fullstack-nest-svelte → fullstack}/CLAUDE.md +0 -0
  610. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/scripts/.keep +0 -0
  611. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/src/common/app-exception.ts +0 -0
  612. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/src/config/env.validation.ts +0 -0
  613. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/api/src/database/migrate.ts +0 -0
  614. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/app.css +0 -0
  615. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/app.d.ts +0 -0
  616. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/api.ts +0 -0
  617. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/site-runtime.svelte +0 -0
  618. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/alert/index.ts +0 -0
  619. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/avatar/index.ts +0 -0
  620. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/badge/index.ts +0 -0
  621. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/button/index.ts +0 -0
  622. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/card/index.ts +0 -0
  623. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/checkbox/index.ts +0 -0
  624. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +0 -0
  625. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +0 -0
  626. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -0
  627. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/dialog.svelte +0 -0
  628. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dialog/index.ts +0 -0
  629. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -0
  630. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -0
  631. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -0
  632. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -0
  633. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -0
  634. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -0
  635. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -0
  636. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/dropdown-menu/index.ts +0 -0
  637. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/input/index.ts +0 -0
  638. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/label/index.ts +0 -0
  639. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/index.ts +0 -0
  640. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select-portal.svelte +0 -0
  641. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/select/select.svelte +0 -0
  642. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/separator/index.ts +0 -0
  643. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/skeleton/index.ts +0 -0
  644. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/sonner/index.ts +0 -0
  645. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/sonner/sonner.svelte +0 -0
  646. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/switch/index.ts +0 -0
  647. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/table/index.ts +0 -0
  648. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tabs/index.ts +0 -0
  649. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/index.ts +0 -0
  650. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +0 -0
  651. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +0 -0
  652. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -0
  653. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +0 -0
  654. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/i18n/README.md +0 -0
  655. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/i18n/catalogs/app/en.json +0 -0
  656. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/i18n/catalogs/app/ko.json +0 -0
  657. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/i18n/locales/en.json +0 -0
  658. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/i18n/locales/ko.json +0 -0
  659. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/src/lib/utils.ts +0 -0
  660. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/static/.gitkeep +0 -0
  661. /package/dist/templates/{fullstack-nest-svelte → fullstack}/apps/web/static/favicon.svg +0 -0
  662. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy/agents/openai.yaml +0 -0
  663. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-agents/skills/podokit-deploy/references/release.md +0 -0
  664. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-add-locale/SKILL.md +0 -0
  665. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-add-locale/agents/openai.yaml +0 -0
  666. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-add-locale/references/catalog-format.md +0 -0
  667. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-deploy/SKILL.md +0 -0
  668. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-claude/skills/podokit-deploy-fast/SKILL.md +0 -0
  669. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-cursor/rules/podokit.mdc +0 -0
  670. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-dockerignore +0 -0
  671. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-env.docker +0 -0
  672. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-github/copilot-instructions.md +0 -0
  673. /package/dist/templates/{fullstack-nest-svelte → fullstack}/dot-gitignore +0 -0
  674. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/api-deployment.yaml +0 -0
  675. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/ingress.yaml +0 -0
  676. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/namespace.yaml +0 -0
  677. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/secret.example.yaml +0 -0
  678. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/services.yaml +0 -0
  679. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/k3s/web-deployment.yaml +0 -0
  680. /package/dist/templates/{fullstack-nest-svelte → fullstack}/infra/traefik/dynamic.yml +0 -0
  681. /package/dist/templates/{fullstack-nest-svelte → fullstack}/tests/api/health.api.spec.ts +0 -0
  682. /package/dist/templates/{fullstack-nest-svelte → fullstack}/tests/playwright.config.ts +0 -0
  683. /package/dist/templates/{fullstack-nest-svelte → fullstack}/tests/playwright.extensions.ts +0 -0
@@ -1,23 +1,27 @@
1
1
  <script lang="ts">
2
- import AccountPage from "$lib/components/account-page.svelte";
3
- import LanguageSwitch from "$lib/components/language-switch.svelte";
4
- import SiteFooter from "$lib/components/site-footer.svelte";
5
- import ThemeToggle from "$lib/components/theme-toggle.svelte";
6
- import { Button } from "$lib/components/ui/button";
7
- import { Toaster } from "$lib/components/ui/sonner";
8
- import { getI18n } from "$lib/i18n";
2
+ import AccountPage from "#lib/components/account-page.svelte";
3
+ import ImpersonationBanner from "#lib/components/impersonation-banner.svelte";
4
+ import LanguageSwitch from "#lib/components/language-switch.svelte";
5
+ import SiteFooter from "#lib/components/site-footer.svelte";
6
+ import ThemeToggle from "#lib/components/theme-toggle.svelte";
7
+ import { Button } from "#lib/components/ui/button/index.js";
8
+ import { Toaster } from "#lib/components/ui/sonner/index.js";
9
+ import { getI18n } from "#lib/i18n/index.js";
9
10
  import type { Capabilities } from "@podosoft/podokit-api-client";
10
11
  import type { SessionUser } from "../../app.d.ts";
11
12
 
12
13
  let {
13
14
  data,
14
15
  }: {
15
- data: { user: SessionUser; currentSessionId: string | null; capabilities: Capabilities };
16
+ data: { user: SessionUser; currentSessionId: string | null; capabilities: Capabilities; impersonating: boolean };
16
17
  } = $props();
17
18
  const i18n = getI18n();
18
19
  </script>
19
20
 
20
21
  <div class="flex min-h-svh flex-col">
22
+ {#if data.impersonating}
23
+ <ImpersonationBanner email={data.user.email} />
24
+ {/if}
21
25
  <header class="flex h-14 items-center gap-2 border-b px-4">
22
26
  <Button href="/" variant="ghost">{i18n.t.nav.home}</Button>
23
27
  <div class="flex-1"></div>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  // Shown to non-admin visitors while maintenance mode is on (see +layout.server.ts).
3
3
  // Admins are never redirected here and can sign in to turn it off.
4
- import { Button } from "$lib/components/ui/button";
5
- import LanguageSwitch from "$lib/components/language-switch.svelte";
6
- import ThemeToggle from "$lib/components/theme-toggle.svelte";
7
- import { getI18n } from "$lib/i18n";
4
+ import { Button } from "#lib/components/ui/button/index.js";
5
+ import LanguageSwitch from "#lib/components/language-switch.svelte";
6
+ import ThemeToggle from "#lib/components/theme-toggle.svelte";
7
+ import { getI18n } from "#lib/i18n/index.js";
8
8
 
9
9
  const i18n = getI18n();
10
10
  </script>
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { page } from "$app/state";
3
- import { Button } from "$lib/components/ui/button";
4
- import * as Card from "$lib/components/ui/card";
5
- import { getI18n } from "$lib/i18n";
3
+ import { Button } from "#lib/components/ui/button/index.js";
4
+ import * as Card from "#lib/components/ui/card/index.js";
5
+ import { getI18n } from "#lib/i18n/index.js";
6
6
 
7
7
  const i18n = getI18n();
8
8
  // The OAuth provider redirects here with the authorization request in the query
@@ -1,6 +1,6 @@
1
1
  import { redirect } from "@sveltejs/kit";
2
2
  import type { PageServerLoad } from "./$types";
3
- import { requireBackendAvailable } from "$lib/server/guards";
3
+ import { requireBackendAvailable } from "#lib/server/guards.js";
4
4
 
5
5
  // The mandatory two-factor enrolment page (reached via the require-2fa gate).
6
6
  // Must be signed in; already-enrolled users have nothing to do here.
@@ -8,6 +8,6 @@ export const load: PageServerLoad = ({ locals }) => {
8
8
  requireBackendAvailable(locals);
9
9
  if (!locals.user) redirect(302, "/login");
10
10
  const user = locals.user as App.Locals["user"] & { twoFactorEnabled?: boolean };
11
- if (user.twoFactorEnabled) redirect(302, "/admin");
11
+ if (user.twoFactorEnabled) redirect(302, "/account");
12
12
  return { user: locals.user };
13
13
  };
@@ -1,14 +1,14 @@
1
1
  <script lang="ts">
2
2
  import { goto } from "$app/navigation";
3
3
  import QRCode from "qrcode";
4
- import { Button } from "$lib/components/ui/button";
5
- import { Input } from "$lib/components/ui/input";
6
- import { Label } from "$lib/components/ui/label";
7
- import { Checkbox } from "$lib/components/ui/checkbox";
8
- import * as Card from "$lib/components/ui/card";
9
- import * as Alert from "$lib/components/ui/alert";
10
- import { api } from "$lib/api";
11
- import { getI18n } from "$lib/i18n";
4
+ import { Button } from "#lib/components/ui/button/index.js";
5
+ import { Input } from "#lib/components/ui/input/index.js";
6
+ import { Label } from "#lib/components/ui/label/index.js";
7
+ import { Checkbox } from "#lib/components/ui/checkbox/index.js";
8
+ import * as Card from "#lib/components/ui/card/index.js";
9
+ import * as Alert from "#lib/components/ui/alert/index.js";
10
+ import { api } from "#lib/api.js";
11
+ import { getI18n } from "#lib/i18n/index.js";
12
12
 
13
13
  const i18n = getI18n();
14
14
  let password = $state("");
@@ -39,7 +39,11 @@
39
39
  error = e.code === "INVALID_PASSWORD" ? i18n.t.setup2fa.wrongPassword : i18n.t.setup2fa.enableFailed;
40
40
  return;
41
41
  }
42
- setup = { totpURI: data?.totpURI ?? "", backupCodes: (data?.backupCodes ?? []) as string[] };
42
+ if (!data?.totpURI || !Array.isArray(data.backupCodes)) {
43
+ error = i18n.t.setup2fa.enableFailed;
44
+ return;
45
+ }
46
+ setup = { totpURI: data.totpURI, backupCodes: data.backupCodes };
43
47
  }
44
48
 
45
49
  async function activate(): Promise<void> {
@@ -51,7 +55,7 @@
51
55
  error = i18n.t.auth.twoFactorInvalidCode;
52
56
  return;
53
57
  }
54
- await goto("/admin", { invalidateAll: true });
58
+ await goto("/account", { invalidateAll: true });
55
59
  }
56
60
 
57
61
  function downloadCodes(): void {
@@ -5,15 +5,15 @@ description: Use when building ANY list or table view in this project (users, se
5
5
 
6
6
  # Build a list with the shared DataTable
7
7
 
8
- **Every** list/table in this project must use `$lib/components/data-table.svelte`
8
+ **Every** list/table in this project must use `#lib/components/data-table.svelte`
9
9
  (`DataTable`) — it provides sortable headers and a footer pagination, consistently.
10
10
  Do **not** assemble `Table.Root` / `Table.Header` / `Table.Body` by hand, and don't
11
11
  put pagination outside the table.
12
12
 
13
13
  ```svelte
14
14
  <script lang="ts">
15
- import DataTable from "$lib/components/data-table.svelte";
16
- import { cn } from "$lib/utils";
15
+ import DataTable from "#lib/components/data-table.svelte";
16
+ import { cn } from "#lib/utils.js";
17
17
  const columns = [
18
18
  { key: "name", label: "Name", sortable: true },
19
19
  { key: "email", label: "Email", sortable: true },
@@ -13,7 +13,7 @@ export type Account = { name: string; email: string; password: string };
13
13
  * So the constant is a DEFAULT and the environment wins:
14
14
  *
15
15
  * ```bash
16
- * E2E_BASE_URL=https://app.example.com E2E_ADMIN_PASSWORD='…' npx playwright test …
16
+ * E2E_BASE_URL=https://app.example.com E2E_ADMIN_PASSWORD='…' {{packageExecutor}} playwright test …
17
17
  * ```
18
18
  *
19
19
  * Without the override the run fails with `INVALID_EMAIL_OR_PASSWORD`, which is the correct
@@ -29,4 +29,19 @@ export const USER = { name: "Normal User", email: "user@example.com", password:
29
29
  export const adminState = "playwright/.auth/admin.json";
30
30
  export const userState = "playwright/.auth/user.json";
31
31
  export const userBaselineState = "playwright/.auth/user-baseline.json";
32
- export const anonState = { cookies: [], origins: [] } as const;
32
+ const testUrl = new URL(process.env.E2E_BASE_URL ?? "http://localhost:5001");
33
+ export const anonState = {
34
+ cookies: [
35
+ {
36
+ name: "locale",
37
+ value: "en",
38
+ domain: testUrl.hostname,
39
+ path: "/",
40
+ expires: -1,
41
+ httpOnly: false,
42
+ secure: testUrl.protocol === "https:",
43
+ sameSite: "Lax" as const,
44
+ },
45
+ ],
46
+ origins: [],
47
+ };
@@ -3,6 +3,7 @@ import {
3
3
  test as base,
4
4
  type APIResponse,
5
5
  } from "@playwright/test";
6
+ import { ADMIN } from "./accounts";
6
7
 
7
8
  const baseURL = process.env.E2E_BASE_URL ?? "http://localhost:5001";
8
9
  const origin = { origin: baseURL };
@@ -29,11 +30,23 @@ async function readCreatedUserId(response: APIResponse): Promise<string> {
29
30
  }
30
31
 
31
32
  export const test = base.extend<{ disposableUsers: DisposableUsers }>({
32
- disposableUsers: async ({ context }, use) => {
33
- // Reuse the browser context's storageState-backed request client. Creating
34
- // a second admin login here can revoke the browser session in applications
35
- // that enforce a single concurrent session.
36
- const request = context.request;
33
+ disposableUsers: async ({ context, playwright }, use, testInfo) => {
34
+ // API projects do not inherit the UI project's admin storageState, while a
35
+ // second admin sign-in can invalidate the shared UI session. Authenticate an
36
+ // isolated request context only for API tests and reuse browser cookies for UI.
37
+ let request = context.request;
38
+ let ownsRequest = false;
39
+ if (testInfo.project.name === "api") {
40
+ request = await playwright.request.newContext({
41
+ baseURL,
42
+ extraHTTPHeaders: origin,
43
+ });
44
+ ownsRequest = true;
45
+ const signIn = await request.post("/api/auth/sign-in/email", {
46
+ data: { email: ADMIN.email, password: ADMIN.password },
47
+ });
48
+ expect(signIn.ok(), "sign in disposable user fixture").toBeTruthy();
49
+ }
37
50
  const userIds = new Set<string>();
38
51
 
39
52
  const disposableUsers: DisposableUsers = {
@@ -67,14 +80,18 @@ export const test = base.extend<{ disposableUsers: DisposableUsers }>({
67
80
  try {
68
81
  await use(disposableUsers);
69
82
  } finally {
70
- for (const userId of userIds) {
71
- const response = await request.post("/api/auth/admin/remove-user", {
72
- headers: origin,
73
- data: { userId },
74
- });
75
- if (!response.ok() && response.status() !== 404) {
76
- throw new Error(`Failed to remove disposable user ${userId}: HTTP ${response.status()}`);
83
+ try {
84
+ for (const userId of userIds) {
85
+ const response = await request.post("/api/auth/admin/remove-user", {
86
+ headers: origin,
87
+ data: { userId },
88
+ });
89
+ if (!response.ok() && response.status() !== 404) {
90
+ throw new Error(`Failed to remove disposable user ${userId}: HTTP ${response.status()}`);
91
+ }
77
92
  }
93
+ } finally {
94
+ if (ownsRequest) await request.dispose();
78
95
  }
79
96
  }
80
97
  },
@@ -1,9 +1,9 @@
1
1
  import type { Page } from "@playwright/test";
2
2
 
3
- // SvelteKit dev hydration can attach event handlers slightly after load;
4
- // wait for the page to settle before driving client-only interactions.
3
+ // Wait for SvelteKit to attach client event handlers before driving forms. The
4
+ // root layout adds this marker from onMount, so no fixed timing assumption is
5
+ // needed even while the development server compiles a route for the first time.
5
6
  export async function ready(page: Page, path: string): Promise<void> {
6
7
  await page.goto(path);
7
- await page.waitForLoadState("load");
8
- await page.waitForTimeout(400);
8
+ await page.locator('html[data-hydrated="true"]').waitFor();
9
9
  }
@@ -15,11 +15,13 @@ async function loginFresh(page: import("@playwright/test").Page, playwright: imp
15
15
  const api = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
16
16
  await api.post("/api/auth/sign-up/email", { data: { email, password: PW, name: "Acc" } });
17
17
  await api.dispose();
18
- await ready(page, `/login?redirect=${encodeURIComponent("/admin/account")}`);
18
+ await ready(page, `/login?redirect=${encodeURIComponent("/account")}`);
19
19
  await page.locator("#email").fill(email);
20
20
  await page.locator("#password").fill(PW);
21
21
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
22
- await expect(page).toHaveURL(/\/admin\/account/);
22
+ await expect(page).toHaveURL((url) => url.pathname === "/account");
23
+ await expect(page.getByRole("heading", { name: "Account" })).toBeVisible();
24
+ await expect(page.getByLabel("Name", { exact: true })).toBeVisible();
23
25
  }
24
26
 
25
27
  test("account: register and verify a phone number", async ({ page, playwright }) => {
@@ -226,6 +226,57 @@ test("account nav shows the core sections", async ({ page }) => {
226
226
  await expect(page.getByRole("button", { name: "Sessions" })).toBeVisible();
227
227
  });
228
228
 
229
+ test("connected account unlink uses the local account row id @smoke", async ({ page }) => {
230
+ const provider = "google";
231
+ let unlinkBody: unknown;
232
+ await page.route("**/api/auth/list-accounts", (route) =>
233
+ route.fulfill({
234
+ status: 200,
235
+ contentType: "application/json",
236
+ body: JSON.stringify([
237
+ { id: "local-account-id", providerId: provider, accountId: "provider-subject" },
238
+ ]),
239
+ }),
240
+ );
241
+ await page.route("**/api/auth/unlink-account", async (route) => {
242
+ unlinkBody = route.request().postDataJSON();
243
+ await route.fulfill({ status: 200, contentType: "application/json", body: "{}" });
244
+ });
245
+
246
+ try {
247
+ const enabled = await page.request.put("/api/account/auth-config", {
248
+ data: {
249
+ social: {
250
+ [provider]: {
251
+ enabled: true,
252
+ clientId: "podokit",
253
+ clientSecret: "podokit",
254
+ },
255
+ },
256
+ },
257
+ });
258
+ expect(enabled.ok()).toBeTruthy();
259
+ await expect
260
+ .poll(async () => {
261
+ const response = await page.request.get("/api/account/capabilities");
262
+ const body = (await response.json()) as { providers?: string[] };
263
+ return body.providers ?? [];
264
+ }, { timeout: 8_000 })
265
+ .toContain(provider);
266
+
267
+ await ready(page, "/admin/account");
268
+ await page.getByRole("button", { name: "Connected", exact: true }).click();
269
+ await page.getByRole("button", { name: "Disconnect", exact: true }).click();
270
+
271
+ await expect.poll(() => unlinkBody).toEqual({ accountId: "local-account-id" });
272
+ await expect(page.getByText("Disconnected", { exact: true })).toBeVisible();
273
+ } finally {
274
+ await page.request.put("/api/account/auth-config", {
275
+ data: { social: { [provider]: { enabled: false } } },
276
+ });
277
+ }
278
+ });
279
+
229
280
  test("two-factor setup shows a scannable QR code when enabled", async ({ page }) => {
230
281
  await ready(page, "/admin/account");
231
282
  await page.getByRole("button", { name: "Security" }).click();
@@ -9,7 +9,7 @@ const base = process.env.E2E_BASE_URL ?? "http://localhost:5001";
9
9
 
10
10
  test("login page renders @smoke", async ({ page }) => {
11
11
  await page.goto("/login");
12
- await expect(page.getByLabel("Email")).toBeVisible();
12
+ await expect(page.getByRole("textbox", { name: /Email(?: or username)?/ })).toBeVisible();
13
13
  await expect(page.getByLabel("Password")).toBeVisible();
14
14
  await expect(page.getByRole("button", { name: "Sign in", exact: true })).toBeVisible();
15
15
  await expect(page.getByRole("link", { name: "Sign up" })).toBeVisible();
@@ -18,7 +18,7 @@ test("login page renders @smoke", async ({ page }) => {
18
18
 
19
19
  test("invalid credentials show an error", async ({ page }) => {
20
20
  await ready(page, "/login");
21
- await page.getByLabel("Email").fill("nobody@example.com");
21
+ await page.getByRole("textbox", { name: /Email(?: or username)?/ }).fill("nobody@example.com");
22
22
  await page.getByLabel("Password").fill("wrong-password");
23
23
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
24
24
  await expect(page.getByRole("alert")).toBeVisible();
@@ -13,11 +13,13 @@ test("admin can impersonate a user and stop", async ({ page }) => {
13
13
  await row.getByRole("button").click();
14
14
  await page.getByRole("menuitem", { name: "Impersonate" }).click();
15
15
 
16
- // Impersonating drops us into the app with a banner offering to stop.
17
- await expect(page).toHaveURL(/\/admin(\/|$)/);
16
+ // Impersonating a normal user leaves the admin-only route group and keeps a
17
+ // visible route back to the original administrator session.
18
+ await expect(page).toHaveURL(/\/account(\/|$)/);
18
19
  const stop = page.getByRole("button", { name: "Stop impersonating" });
19
20
  await expect(stop).toBeVisible();
20
21
 
21
22
  await stop.click();
23
+ await expect(page).toHaveURL(/\/admin(\/|$)/);
22
24
  await expect(page.getByRole("button", { name: "Stop impersonating" })).toHaveCount(0);
23
25
  });
@@ -3,7 +3,9 @@ import { createHash, randomBytes } from "node:crypto";
3
3
 
4
4
  // admin storageState (project default) — the admin is the resource owner.
5
5
  const b64url = (b: Buffer): string => b.toString("base64url");
6
- const REDIRECT = "http://localhost:9999/callback";
6
+ // This front-channel test stops at consent, so use the HTTPS callback required
7
+ // for a web client without depending on a live relying-party callback server.
8
+ const REDIRECT = "https://example.com/callback";
7
9
 
8
10
  // Verifies the provider is correctly configured end to end on the front channel:
9
11
  // signed discovery + JWKS, dynamic client registration, and an authorize request
@@ -30,12 +32,13 @@ test("OIDC provider: discovery, JWKS, client registration, authorize handoff", a
30
32
  // the provider is enabled the auth instance may still be rebuilding.
31
33
  let reg: { client_id?: string; client_secret?: string } = {};
32
34
  await expect(async () => {
33
- reg = await (
34
- await page.request.post("/api/auth/oauth2/create-client", {
35
- data: { client_name: "E2E RP", redirect_uris: [REDIRECT] },
36
- headers,
37
- })
38
- ).json();
35
+ const response = await page.request.post("/api/auth/oauth2/create-client", {
36
+ data: { client_name: "E2E RP", redirect_uris: [REDIRECT] },
37
+ headers,
38
+ });
39
+ const body = await response.text();
40
+ expect(response.ok(), body).toBeTruthy();
41
+ reg = JSON.parse(body) as typeof reg;
39
42
  expect(reg.client_id).toBeTruthy();
40
43
  }).toPass({ timeout: 8000 });
41
44
  expect(reg.client_secret).toBeTruthy();
@@ -48,12 +51,14 @@ test("OIDC provider: discovery, JWKS, client registration, authorize handoff", a
48
51
  `/api/auth/oauth2/authorize?client_id=${reg.client_id}&redirect_uri=${encodeURIComponent(REDIRECT)}` +
49
52
  `&response_type=code&scope=${encodeURIComponent("openid profile email")}&state=st` +
50
53
  `&code_challenge=${challenge}&code_challenge_method=S256`;
51
- const authz = await (await page.request.get(authorizeUrl, { headers })).json();
52
- expect(String(authz.url)).toContain("/oauth2/consent");
53
- expect(String(authz.url)).toContain("client_id=");
54
+ const authz = await page.request.get(authorizeUrl, { headers, maxRedirects: 0 });
55
+ expect(authz.status()).toBe(302);
56
+ const consentUrl = authz.headers().location ?? "";
57
+ expect(consentUrl).toContain("/oauth2/consent");
58
+ expect(consentUrl).toContain("client_id=");
54
59
 
55
60
  // The consent page renders (reached in a real browser navigation).
56
- await page.goto(authz.url);
61
+ await page.goto(consentUrl);
57
62
  await expect(page.getByRole("button", { name: "Allow" })).toBeVisible();
58
63
  } finally {
59
64
  await page.request.put("/api/account/settings", { data: { oidcProvider: false }, headers });
@@ -1,8 +1,9 @@
1
1
  import { expect, test } from "@playwright/test";
2
+ import { anonState } from "../helpers/accounts";
2
3
  import { ready } from "../helpers/hydration";
3
4
 
4
5
  // Full passkey round trip on a throwaway account — never touches the shared admin.
5
- test.use({ storageState: { cookies: [], origins: [] } });
6
+ test.use({ storageState: anonState });
6
7
 
7
8
  test("register a passkey and sign in with it", async ({ page, baseURL }) => {
8
9
  const origin = { origin: baseURL ?? "" };
@@ -20,7 +21,7 @@ test("register a passkey and sign in with it", async ({ page, baseURL }) => {
20
21
  const signup = await page.context().request.post("/api/auth/sign-up/email", { data: { email, password: pw, name: "PK" }, headers: origin });
21
22
  expect(signup.ok(), await signup.text()).toBeTruthy();
22
23
 
23
- await ready(page, "/admin/account");
24
+ await ready(page, "/account");
24
25
  await page.getByRole("button", { name: "Security" }).click();
25
26
  const addBtn = page.getByRole("button", { name: "Add passkey" });
26
27
  test.skip((await addBtn.count()) === 0, "passkeys not enabled");
@@ -15,6 +15,12 @@ async function openHydratedLogin(page: Page, redirect?: string): Promise<void> {
15
15
  await page.waitForLoadState("networkidle");
16
16
  }
17
17
 
18
+ async function expectAccountPage(page: Page): Promise<void> {
19
+ await expect(page).toHaveURL((url) => url.pathname === "/account");
20
+ await expect(page.getByRole("heading", { name: "Account" })).toBeVisible();
21
+ await expect(page.getByLabel("Name", { exact: true })).toBeVisible();
22
+ }
23
+
18
24
  // A disposable account (never the shared admin/user) so enabling 2FA here can't
19
25
  // invalidate the seeded sessions the other auth specs rely on.
20
26
  test("two-factor: sign in with a backup code from the login page", async ({ page, playwright }) => {
@@ -31,7 +37,7 @@ test("two-factor: sign in with a backup code from the login page", async ({ page
31
37
  await api.dispose();
32
38
 
33
39
  // Password sign-in hands off to the second-factor step (no session yet).
34
- await openHydratedLogin(page, "/admin/account");
40
+ await openHydratedLogin(page, "/account");
35
41
  await page.getByLabel("Email").fill(email);
36
42
  await page.getByLabel("Password").fill(pw);
37
43
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
@@ -52,7 +58,30 @@ test("two-factor: sign in with a backup code from the login page", async ({ page
52
58
  // The real code completes the login.
53
59
  await page.getByLabel("Backup code").fill(backupCode);
54
60
  await page.getByRole("button", { name: "Verify", exact: true }).click();
55
- await expect(page).toHaveURL(/\/admin\/account/);
61
+ await expectAccountPage(page);
62
+ });
63
+
64
+ test("two-factor: sign in with an authenticator code from the login page", async ({ page, playwright }) => {
65
+ const api = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
66
+ const caps = await (await api.get("/api/account/capabilities")).json();
67
+ test.skip(!caps?.twoFactor, "two-factor not enabled");
68
+
69
+ const email = `tf-totp-ui-${Date.now()}@example.com`;
70
+ const pw = "Podokit3e-Str0ng!pw";
71
+ await api.post("/api/auth/sign-up/email", { data: { email, password: pw, name: "UI" } });
72
+ const enable = await (await api.post("/api/auth/two-factor/enable", { data: { password: pw } })).json();
73
+ await api.post("/api/auth/two-factor/verify-totp", { data: { code: totpCode(enable.totpURI) } });
74
+ await api.dispose();
75
+
76
+ await openHydratedLogin(page, "/account");
77
+ await page.getByLabel("Email").fill(email);
78
+ await page.getByLabel("Password").fill(pw);
79
+ await page.getByRole("button", { name: "Sign in", exact: true }).click();
80
+ await expect(page.getByTestId("two-factor-step")).toBeVisible();
81
+ await page.getByLabel("Authentication code").fill(totpCode(enable.totpURI));
82
+ await page.getByRole("button", { name: "Verify", exact: true }).click();
83
+
84
+ await expectAccountPage(page);
56
85
  });
57
86
 
58
87
  test("require-2fa: a new sign-up is forced through the enrolment page", async ({ page, playwright }) => {
@@ -74,7 +103,7 @@ test("require-2fa: a new sign-up is forced through the enrolment page", async ({
74
103
  await probe.dispose();
75
104
 
76
105
  // Signing in toward a protected route lands on the mandatory enrolment page.
77
- await openHydratedLogin(page, "/admin");
106
+ await openHydratedLogin(page, "/account");
78
107
  await page.getByLabel("Email").fill(email);
79
108
  await page.getByLabel("Password").fill(pw);
80
109
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
@@ -91,8 +120,12 @@ test("require-2fa: a new sign-up is forced through the enrolment page", async ({
91
120
  await page.getByLabel("3. Enter the 6-digit code").fill(totpCode(uri));
92
121
  await page.getByRole("button", { name: "Activate and continue" }).click();
93
122
 
94
- // Enrolled → the gate lets them into the app (no longer bounced to /setup-2fa).
95
- await expect(page).toHaveURL(/\/admin/);
123
+ // Enrolled → the gate lets the regular user into their account page.
124
+ await expectAccountPage(page);
125
+
126
+ // An enrolled user who revisits setup is returned to the same non-admin page.
127
+ await page.goto("/setup-2fa");
128
+ await expectAccountPage(page);
96
129
  } finally {
97
130
  await admin.put("/api/account/settings", { data: { require2fa: false } });
98
131
  await expect(async () => {
@@ -119,14 +152,14 @@ test("account: regenerate backup codes shows a fresh set", async ({ page, playwr
119
152
  await api.dispose();
120
153
 
121
154
  // Sign in (backup-code path) straight to the account page.
122
- await openHydratedLogin(page, "/admin/account");
155
+ await openHydratedLogin(page, "/account");
123
156
  await page.getByLabel("Email").fill(email);
124
157
  await page.getByLabel("Password").fill(pw);
125
158
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
126
159
  await page.getByRole("button", { name: "Use a backup code instead" }).click();
127
160
  await page.getByLabel("Backup code").fill(backupCode);
128
161
  await page.getByRole("button", { name: "Verify", exact: true }).click();
129
- await expect(page).toHaveURL(/\/admin\/account/);
162
+ await expectAccountPage(page);
130
163
 
131
164
  // Security → regenerate backup codes → a fresh set is shown.
132
165
  await page.getByRole("button", { name: "Security" }).click();
@@ -35,13 +35,13 @@
35
35
  "packageOverlays": {
36
36
  "api": {
37
37
  "dependencies": {
38
- "image-size": "^2.0.2"
38
+ "probe-image-size": "^7.4.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@types/multer": "^1.4.12"
41
+ "@types/probe-image-size": "^7.2.5"
42
42
  },
43
43
  "scripts": {
44
- "admin:bootstrap": "node scripts/bootstrap-admin.mjs"
44
+ "admin:bootstrap": "bun scripts/bootstrap-admin.mjs"
45
45
  }
46
46
  }
47
47
  },
@@ -75,8 +75,8 @@
75
75
  },
76
76
  {
77
77
  "path": "apps/web/src/routes/(admin)/+layout.svelte",
78
- "from": "$lib/components/app-sidebar.svelte",
79
- "to": "$lib/components/admin-sidebar.svelte",
78
+ "from": "#lib/components/app-sidebar.svelte",
79
+ "to": "#lib/components/admin-sidebar.svelte",
80
80
  "expected": 1
81
81
  }
82
82
  ]
@@ -87,7 +87,7 @@
87
87
  "file": "apps/web/src/routes/+page.svelte",
88
88
  "marker": "// podokit:end:landing-imports",
89
89
  "optional": true,
90
- "text": "import { page } from \"$app/state\";\n import AccountMenu from \"$lib/components/account-menu.svelte\";\n import LanguageSwitch from \"$lib/components/language-switch.svelte\";\n import ThemeToggle from \"$lib/components/theme-toggle.svelte\";"
90
+ "text": "import { page } from \"$app/state\";\n import AccountMenu from \"#lib/components/account-menu.svelte\";\n import LanguageSwitch from \"#lib/components/language-switch.svelte\";\n import ThemeToggle from \"#lib/components/theme-toggle.svelte\";"
91
91
  },
92
92
  {
93
93
  "file": "apps/web/src/routes/+page.svelte",
@@ -119,32 +119,22 @@
119
119
  "file": "AGENTS.md",
120
120
  "marker": "<!-- podokit:end:agents-modules -->",
121
121
  "optional": true,
122
- "text": "### admin-dashboard\n- The `(admin)` route group and `admin-sidebar.svelte` are the admin-console shell for `/admin/*` only. Put signed-in product pages in `(app)` or in a separate route group with its own layout; do not place them under `(admin)`.\n- Admin console lives at `/admin/*` (users, sessions, organizations, audit, settings, account). Set `ADMIN_EMAILS`, then create or verify the initial account with `npm run admin:bootstrap -w <app>-api`; never commit or persist `ADMIN_BOOTSTRAP_PASSWORD`. When sign-up approval is enabled, self-registered users stay pending until an administrator approves them on `/admin/users`; administrator-created users bypass the queue.\n- Signed-in users can upload, replace, or remove their profile image from `/account` or `/admin/account`. Keep the shared policy visible in custom account UI: PNG, JPEG, or WebP; at most 2 MB and 2048 by 2048 pixels. Use the managed `/api/account/profile-image` endpoints instead of writing directly to storage or `user.image`.\n- `sidebar-user-menu.svelte` is specific to the admin sidebar. For a product shell outside `Sidebar.Provider`, use the managed `<AccountMenu {user} variant=\"identity\" side=\"top\" />` component.\n- Custom protected server layouts must call `requireBackendAvailable(locals)` from `$lib/server/guards` before redirecting anonymous users. This preserves sessions and returns 503 when authentication or maintenance policy cannot be checked.\n- **Every list/table MUST use the shared `$lib/components/data-table.svelte` (`DataTable`)** \u2014 it gives sortable headers + a footer pagination. Add search/filters with `$lib/components/table-toolbar.svelte`. Never assemble `Table.Root`/`Table.Header`/`Table.Body` by hand. For responsive columns, use `hideBelow` and apply the row context's `cellClass(columnKey)` to the matching cell.\n"
122
+ "text": "### admin-dashboard\n- The `(admin)` route group and `admin-sidebar.svelte` are the admin-console shell for `/admin/*` only. Put signed-in product pages in `(app)` or in a separate route group with its own layout; do not place them under `(admin)`.\n- Admin console lives at `/admin/*` (users, sessions, organizations, audit, settings, account). Set `ADMIN_EMAILS`, then create or verify the initial account with `{{apiRun}} admin:bootstrap{{apiWorkspaceArg}}`; never commit or persist `ADMIN_BOOTSTRAP_PASSWORD`. When sign-up approval is enabled, self-registered users stay pending until an administrator approves them on `/admin/users`; administrator-created users bypass the queue.\n- Signed-in users can upload, replace, or remove their profile image from `/account` or `/admin/account`. Keep the shared policy visible in custom account UI: PNG, JPEG, or WebP; at most 2 MB and 2048 by 2048 pixels. Use the managed `/api/account/profile-image` endpoints instead of writing directly to storage or `user.image`.\n- `sidebar-user-menu.svelte` is specific to the admin sidebar. For a product shell outside `Sidebar.Provider`, use the managed `<AccountMenu {user} variant=\"identity\" side=\"top\" />` component.\n- Custom protected server layouts must call `requireBackendAvailable(locals)` from `#lib/server/guards.js` before redirecting anonymous users. This preserves sessions and returns 503 when authentication or maintenance policy cannot be checked.\n- **Every list/table MUST use the shared `#lib/components/data-table.svelte` (`DataTable`)** \u2014 it gives sortable headers + a footer pagination. Add search/filters with `#lib/components/table-toolbar.svelte`. Never assemble `Table.Root`/`Table.Header`/`Table.Body` by hand. For responsive columns, use `hideBelow` and apply the row context's `cellClass(columnKey)` to the matching cell.\n"
123
123
  },
124
124
  {
125
- "file": "apps/api/src/app.module.ts",
125
+ "file": "apps/api/src/app.ts",
126
126
  "marker": "// podokit:end:imports",
127
- "text": "import { SiteSettingsModule } from \"./site-settings/site-settings.module\";"
127
+ "text": "import { adminModule } from \"./admin.module\";"
128
128
  },
129
129
  {
130
- "file": "apps/api/src/app.module.ts",
131
- "marker": "// podokit:end:imports",
132
- "text": "import { ProfileImageModule } from \"./profile-image/profile-image.module\";"
133
- },
134
- {
135
- "file": "apps/api/src/app.module.ts",
136
- "marker": "// podokit:end:module-imports",
137
- "text": "SiteSettingsModule,"
138
- },
139
- {
140
- "file": "apps/api/src/app.module.ts",
141
- "marker": "// podokit:end:module-imports",
142
- "text": "ProfileImageModule,"
130
+ "file": "apps/api/src/app.ts",
131
+ "marker": "// podokit:end:modules",
132
+ "text": "adminModule,"
143
133
  }
144
134
  ],
145
135
  "instructions": [
146
- "Set ADMIN_EMAILS in .env (comma-separated). After building and migrating, inject ADMIN_BOOTSTRAP_EMAIL and ADMIN_BOOTSTRAP_PASSWORD for one command only, then run npm run admin:bootstrap -w <app>-api. The command creates a verified, approved admin or safely verifies an existing one.",
147
- "Re-run the auth migration to add the admin and sign-up approval columns: npx @better-auth/cli migrate -y --config apps/api/src/auth/auth.ts",
136
+ "Set ADMIN_EMAILS in .env (comma-separated). After building and migrating, inject ADMIN_BOOTSTRAP_EMAIL and ADMIN_BOOTSTRAP_PASSWORD for one command only, then run {{apiRun}} admin:bootstrap{{apiWorkspaceArg}}. The command creates a verified, approved admin or safely verifies an existing one.",
137
+ "Run all migrations to add the admin and sign-up approval columns: bun run --cwd apps/api migrate:all",
148
138
  "Remove ADMIN_BOOTSTRAP_PASSWORD from the environment after bootstrap. Keep ADMIN_EMAILS so matching future sign-ups are promoted consistently.",
149
139
  "Admin pages: /admin/users (list, approve pending registrations, ban, set role, revoke sessions). Signed-in users manage their profile, profile image, and security at /account; /admin/account remains available in the admin shell. Profile images accept PNG, JPEG, and WebP up to 2 MB and 2048 by 2048 pixels. Admin, account, authentication, maintenance, and API responses include X-Robots-Tag: noindex, nofollow by default.",
150
140
  "Password reset emails go through the mailer module (installed automatically with auth); in dev without SMTP they are logged to the API console. Configure SMTP in admin settings or via SMTP_* env for production."
@@ -1,4 +1,4 @@
1
- import { afterEach, describe, expect, it } from "@jest/globals";
1
+ import { afterEach, describe, expect, it } from "bun:test";
2
2
  import { ApiKeyVerifier } from "./api-key-verifier";
3
3
 
4
4
  const originalApiKeys = process.env.API_KEYS;