@podosoft/podokit 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/templates/fullstack-nest-svelte/apps/api/package.json +29 -11
  4. package/dist/templates/fullstack-nest-svelte/apps/api/src/app.module.ts +3 -0
  5. package/dist/templates/fullstack-nest-svelte/apps/api/tsconfig.json +14 -5
  6. package/dist/templates/fullstack-nest-svelte/apps/web/package.json +8 -6
  7. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/api.ts +5 -0
  8. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  9. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  10. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  11. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  12. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  13. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  14. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  15. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  16. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  17. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  18. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  19. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  20. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  21. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  22. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  23. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  24. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  25. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  26. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  27. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  28. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  29. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  30. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  31. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  32. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  33. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  34. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  35. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  36. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  37. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  38. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  39. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  40. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  41. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  42. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  43. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  44. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  45. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  46. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  47. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  48. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  49. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  50. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  51. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/index.ts +37 -0
  52. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  53. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  54. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  55. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  56. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  57. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  58. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  59. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  60. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  61. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  62. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  63. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  64. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  65. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  66. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  67. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  68. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  69. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/index.ts +28 -0
  70. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  71. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  72. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  73. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  74. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  75. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  76. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  77. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  78. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  79. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  80. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  81. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  82. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  83. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  84. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  85. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  86. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  87. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  88. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  89. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/ko.ts +5 -2
  90. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/api.ts +19 -0
  91. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.ts +43 -4
  92. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/+page.svelte +8 -3
  93. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/[...path]/+server.ts +12 -0
  94. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/auth/[...all]/+server.ts +12 -0
  95. package/dist/templates/fullstack-nest-svelte/dot-gitignore +5 -0
  96. package/dist/templates/fullstack-nest-svelte/package.json +11 -3
  97. package/dist/templates/fullstack-nest-svelte/tests/README.md +15 -0
  98. package/dist/templates/fullstack-nest-svelte/tests/api/health.api.spec.ts +14 -0
  99. package/dist/templates/fullstack-nest-svelte/tests/package.json +14 -0
  100. package/dist/templates/fullstack-nest-svelte/tests/playwright.config.ts +25 -0
  101. package/dist/templates/fullstack-nest-svelte/tests/ui/smoke.ui.spec.ts +8 -0
  102. package/dist/templates/modules/admin-dashboard/files/apps/web/src/app.d.ts +23 -0
  103. package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +20 -0
  104. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/app-sidebar.svelte +59 -0
  105. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/language-switch.svelte +33 -0
  106. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +44 -0
  107. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/table-pagination.svelte +40 -0
  108. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/theme-toggle.svelte +27 -0
  109. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible-content.svelte +7 -0
  110. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible-trigger.svelte +7 -0
  111. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/collapsible.svelte +11 -0
  112. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/collapsible/index.ts +13 -0
  113. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/index.ts +31 -0
  114. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-content.svelte +20 -0
  115. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-ellipsis.svelte +22 -0
  116. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-item.svelte +14 -0
  117. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-link.svelte +42 -0
  118. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next-button.svelte +31 -0
  119. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-next.svelte +26 -0
  120. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-prev-button.svelte +31 -0
  121. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination-previous.svelte +26 -0
  122. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/pagination/pagination.svelte +28 -0
  123. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/index.ts +34 -0
  124. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-close.svelte +7 -0
  125. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-content.svelte +55 -0
  126. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-description.svelte +17 -0
  127. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-footer.svelte +20 -0
  128. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-header.svelte +20 -0
  129. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-overlay.svelte +17 -0
  130. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-portal.svelte +7 -0
  131. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-title.svelte +17 -0
  132. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet-trigger.svelte +7 -0
  133. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sheet/sheet.svelte +7 -0
  134. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/constants.ts +6 -0
  135. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/context.svelte.ts +81 -0
  136. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/index.ts +75 -0
  137. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-content.svelte +24 -0
  138. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-footer.svelte +21 -0
  139. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-action.svelte +33 -0
  140. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-content.svelte +21 -0
  141. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group-label.svelte +33 -0
  142. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-group.svelte +21 -0
  143. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-header.svelte +21 -0
  144. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-input.svelte +21 -0
  145. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-inset.svelte +20 -0
  146. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-action.svelte +37 -0
  147. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte +24 -0
  148. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +102 -0
  149. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-item.svelte +21 -0
  150. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte +36 -0
  151. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +39 -0
  152. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte +21 -0
  153. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte +21 -0
  154. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-menu.svelte +21 -0
  155. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-provider.svelte +53 -0
  156. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-rail.svelte +36 -0
  157. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-separator.svelte +19 -0
  158. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar-trigger.svelte +36 -0
  159. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/ui/sidebar/sidebar.svelte +108 -0
  160. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/user-avatar.svelte +12 -0
  161. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/hooks/is-mobile.svelte.ts +9 -0
  162. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/index.ts +27 -0
  163. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/messages.ts +359 -0
  164. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/+layout.server.ts +14 -0
  165. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/+layout.svelte +50 -0
  166. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/+page.svelte +25 -0
  167. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/account/+page.server.ts +5 -0
  168. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/account/+page.svelte +374 -0
  169. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/audit/+page.server.ts +8 -0
  170. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/audit/+page.svelte +78 -0
  171. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/sessions/+page.server.ts +8 -0
  172. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/sessions/+page.svelte +122 -0
  173. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/users/+page.server.ts +9 -0
  174. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/users/+page.svelte +406 -0
  175. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/+layout.svelte +13 -0
  176. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/forgot-password/+page.svelte +54 -0
  177. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/login/+page.svelte +59 -0
  178. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/reset-password/+page.svelte +51 -0
  179. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/signup/+page.svelte +60 -0
  180. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.server.ts +22 -0
  181. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.svelte +20 -0
  182. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+page.svelte +22 -0
  183. package/dist/templates/modules/admin-dashboard/files/tests/api/audit.api.spec.ts +48 -0
  184. package/dist/templates/modules/admin-dashboard/files/tests/api/auth.api.spec.ts +43 -0
  185. package/dist/templates/modules/admin-dashboard/files/tests/api/users-admin.api.spec.ts +134 -0
  186. package/dist/templates/modules/admin-dashboard/files/tests/helpers/accounts.ts +6 -0
  187. package/dist/templates/modules/admin-dashboard/files/tests/helpers/hydration.ts +9 -0
  188. package/dist/templates/modules/admin-dashboard/files/tests/playwright.config.ts +26 -0
  189. package/dist/templates/modules/admin-dashboard/files/tests/seed.setup.ts +29 -0
  190. package/dist/templates/modules/admin-dashboard/files/tests/ui/account.ui.spec.ts +55 -0
  191. package/dist/templates/modules/admin-dashboard/files/tests/ui/audit.ui.spec.ts +16 -0
  192. package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +45 -0
  193. package/dist/templates/modules/admin-dashboard/files/tests/ui/dashboard.ui.spec.ts +25 -0
  194. package/dist/templates/modules/admin-dashboard/files/tests/ui/guards.ui.spec.ts +21 -0
  195. package/dist/templates/modules/admin-dashboard/files/tests/ui/i18n.ui.spec.ts +13 -0
  196. package/dist/templates/modules/admin-dashboard/files/tests/ui/sessions.ui.spec.ts +15 -0
  197. package/dist/templates/modules/admin-dashboard/files/tests/ui/sidebar.ui.spec.ts +16 -0
  198. package/dist/templates/modules/admin-dashboard/files/tests/ui/users-crud.ui.spec.ts +129 -0
  199. package/dist/templates/modules/admin-dashboard/files/tests/ui/users.ui.spec.ts +19 -0
  200. package/dist/templates/modules/admin-dashboard/module.manifest.json +41 -0
  201. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.decorator.ts +9 -0
  202. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.ts +29 -0
  203. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.ts +9 -0
  204. package/dist/templates/modules/api-key-auth/files/apps/api/src/machine/machine.controller.ts +14 -0
  205. package/dist/templates/modules/api-key-auth/module.manifest.json +19 -0
  206. package/dist/templates/modules/audit-log/files/apps/api/src/audit/README.md +59 -0
  207. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-events.ts +34 -0
  208. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-hook.ts +70 -0
  209. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-log.entity.ts +46 -0
  210. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.controller.ts +21 -0
  211. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.decorator.ts +23 -0
  212. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.interceptor.ts +54 -0
  213. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +14 -0
  214. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.ts +36 -0
  215. package/dist/templates/modules/audit-log/files/apps/api/src/migrations/1720300000000-InitAuditLogs.ts +31 -0
  216. package/dist/templates/modules/audit-log/module.manifest.json +39 -0
  217. package/dist/templates/modules/auth/files/apps/api/src/account/account.controller.ts +30 -0
  218. package/dist/templates/modules/auth/files/apps/api/src/account/account.module.ts +5 -0
  219. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +59 -0
  220. package/dist/templates/modules/auth/files/apps/api/src/health/health.controller.ts +26 -0
  221. package/dist/templates/modules/auth/module.manifest.json +70 -0
  222. package/dist/templates/modules/bullmq/module.manifest.json +11 -3
  223. package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +29 -0
  224. package/dist/templates/modules/logging/module.manifest.json +27 -0
  225. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +26 -0
  226. package/dist/templates/modules/rate-limit/module.manifest.json +25 -0
  227. package/dist/templates/todo/apps/api/package.json +29 -11
  228. package/dist/templates/todo/apps/api/src/app.module.ts +3 -0
  229. package/dist/templates/todo/apps/api/tsconfig.json +14 -5
  230. package/dist/templates/todo/apps/web/package.json +8 -6
  231. package/dist/templates/todo/apps/web/src/lib/api.ts +5 -0
  232. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  233. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  234. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  235. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  236. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  237. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  238. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  239. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  240. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  241. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  242. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  243. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  244. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  245. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  246. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  247. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  248. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  249. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  250. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  251. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  252. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  253. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  254. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  255. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  256. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  257. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  258. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  259. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  260. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  261. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  262. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  263. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  264. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  265. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  266. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  267. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  268. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  269. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  270. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  271. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  272. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  273. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  274. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  275. package/dist/templates/todo/apps/web/src/lib/components/ui/select/index.ts +37 -0
  276. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  277. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  278. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  279. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  280. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  281. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  282. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  283. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  284. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  285. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  286. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  287. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  288. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  289. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  290. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  291. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  292. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  293. package/dist/templates/todo/apps/web/src/lib/components/ui/table/index.ts +28 -0
  294. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  295. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  296. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  297. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  298. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  299. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  300. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  301. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  302. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  303. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  304. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  305. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  306. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  307. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  308. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  309. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  310. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  311. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  312. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  313. package/dist/templates/todo/apps/web/src/lib/i18n/ko.ts +5 -2
  314. package/dist/templates/todo/apps/web/src/lib/server/api.ts +19 -0
  315. package/dist/templates/todo/apps/web/src/lib/server/backend-proxy.ts +43 -4
  316. package/dist/templates/todo/apps/web/src/routes/+page.svelte +19 -18
  317. package/dist/templates/todo/apps/web/src/routes/api/[...path]/+server.ts +12 -0
  318. package/dist/templates/todo/apps/web/src/routes/api/auth/[...all]/+server.ts +12 -0
  319. package/dist/templates/todo/dot-gitignore +5 -0
  320. package/dist/templates/todo/package.json +11 -3
  321. package/dist/templates/todo/tests/README.md +15 -0
  322. package/dist/templates/todo/tests/api/health.api.spec.ts +14 -0
  323. package/dist/templates/todo/tests/package.json +14 -0
  324. package/dist/templates/todo/tests/playwright.config.ts +25 -0
  325. package/dist/templates/todo/tests/ui/smoke.ui.spec.ts +8 -0
  326. package/package.json +2 -2
  327. package/dist/templates/fullstack-nest-svelte/apps/api/test/health.e2e-spec.ts +0 -23
  328. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/health/+server.ts +0 -12
  329. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.controller.ts +0 -31
  330. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.module.ts +0 -22
  331. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.service.ts +0 -44
  332. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/login.dto.ts +0 -12
  333. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/register.dto.ts +0 -13
  334. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt-auth.guard.ts +0 -5
  335. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt.strategy.ts +0 -23
  336. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/user.entity.ts +0 -16
  337. package/dist/templates/modules/auth-jwt/files/apps/api/src/migrations/1720200000000-InitUsers.ts +0 -23
  338. package/dist/templates/modules/auth-jwt/module.manifest.json +0 -31
  339. package/dist/templates/todo/apps/api/test/health.e2e-spec.ts +0 -23
  340. package/dist/templates/todo/apps/web/src/routes/api/health/+server.ts +0 -12
  341. package/dist/templates/todo/apps/web/src/routes/api/todos/+server.ts +0 -24
  342. package/dist/templates/todo/apps/web/src/routes/api/todos/[id]/+server.ts +0 -24
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import { Button } from "$lib/components/ui/button/index.js";
3
+ import PanelLeftIcon from '@lucide/svelte/icons/panel-left';
4
+ import { cn } from "$lib/utils.js";
5
+ import type { ComponentProps } from "svelte";
6
+ import { useSidebar } from "./context.svelte.js";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ onclick,
12
+ ...restProps
13
+ }: ComponentProps<typeof Button> & {
14
+ onclick?: (e: MouseEvent) => void;
15
+ } = $props();
16
+
17
+ const sidebar = useSidebar();
18
+ </script>
19
+
20
+ <Button
21
+ bind:ref
22
+ data-sidebar="trigger"
23
+ data-slot="sidebar-trigger"
24
+ variant="ghost"
25
+ size="icon-sm"
26
+ class={cn("cn-sidebar-trigger", className)}
27
+ type="button"
28
+ onclick={(e) => {
29
+ onclick?.(e);
30
+ sidebar.toggle();
31
+ }}
32
+ {...restProps}
33
+ >
34
+ <PanelLeftIcon />
35
+ <span class="sr-only">Toggle Sidebar</span>
36
+ </Button>
@@ -0,0 +1,108 @@
1
+ <script lang="ts">
2
+ import * as Sheet from "$lib/components/ui/sheet/index.js";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+ import type { HTMLAttributes } from "svelte/elements";
5
+ import { SIDEBAR_WIDTH_MOBILE } from "./constants.js";
6
+ import { useSidebar } from "./context.svelte.js";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ side = "left",
11
+ variant = "sidebar",
12
+ collapsible = "offcanvas",
13
+ class: className,
14
+ children,
15
+ ...restProps
16
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
17
+ side?: "left" | "right";
18
+ variant?: "sidebar" | "floating" | "inset";
19
+ collapsible?: "offcanvas" | "icon" | "none";
20
+ } = $props();
21
+
22
+ const sidebar = useSidebar();
23
+ </script>
24
+
25
+ {#if collapsible === "none"}
26
+ <div
27
+ class={cn(
28
+ "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
29
+ className
30
+ )}
31
+ bind:this={ref}
32
+ {...restProps}
33
+ >
34
+ {@render children?.()}
35
+ </div>
36
+ {:else if sidebar.isMobile}
37
+ <Sheet.Root
38
+ bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)}
39
+ {...restProps}
40
+ >
41
+ <Sheet.Content
42
+ bind:ref
43
+ data-sidebar="sidebar"
44
+ data-slot="sidebar"
45
+ data-mobile="true"
46
+ class={cn(
47
+ "bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",
48
+ className
49
+ )}
50
+ style="--sidebar-width: {SIDEBAR_WIDTH_MOBILE};"
51
+ {side}
52
+ >
53
+ <Sheet.Header class="sr-only">
54
+ <Sheet.Title>Sidebar</Sheet.Title>
55
+ <Sheet.Description>Displays the mobile sidebar.</Sheet.Description>
56
+ </Sheet.Header>
57
+ <div class="flex h-full w-full flex-col">
58
+ {@render children?.()}
59
+ </div>
60
+ </Sheet.Content>
61
+ </Sheet.Root>
62
+ {:else}
63
+ <div
64
+ bind:this={ref}
65
+ class="text-sidebar-foreground group peer hidden md:block"
66
+ data-state={sidebar.state}
67
+ data-collapsible={sidebar.state === "collapsed" ? collapsible : ""}
68
+ data-variant={variant}
69
+ data-side={side}
70
+ data-slot="sidebar"
71
+ >
72
+ <!-- This is what handles the sidebar gap on desktop -->
73
+ <div
74
+ data-slot="sidebar-gap"
75
+ class={cn(
76
+ "transition-[width] duration-200 ease-linear relative w-(--sidebar-width) bg-transparent",
77
+ "group-data-[collapsible=offcanvas]:w-0",
78
+ "group-data-[side=right]:rotate-180",
79
+ variant === "floating" || variant === "inset"
80
+ ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
81
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
82
+ )}
83
+ ></div>
84
+ <div
85
+ data-slot="sidebar-container"
86
+ class={cn(
87
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
88
+ side === "left"
89
+ ? "start-0 group-data-[collapsible=offcanvas]:start-[calc(var(--sidebar-width)*-1)]"
90
+ : "end-0 group-data-[collapsible=offcanvas]:end-[calc(var(--sidebar-width)*-1)]",
91
+ // Adjust the padding for floating and inset variants.
92
+ variant === "floating" || variant === "inset"
93
+ ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
94
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-e group-data-[side=right]:border-s",
95
+ className
96
+ )}
97
+ {...restProps}
98
+ >
99
+ <div
100
+ data-sidebar="sidebar"
101
+ data-slot="sidebar-inner"
102
+ class="bg-sidebar group-data-[variant=floating]:ring-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 flex size-full flex-col"
103
+ >
104
+ {@render children?.()}
105
+ </div>
106
+ </div>
107
+ </div>
108
+ {/if}
@@ -0,0 +1,12 @@
1
+ <script lang="ts">
2
+ import * as Avatar from "$lib/components/ui/avatar";
3
+ import type { SessionUser } from "../../app.d.ts";
4
+
5
+ let { user, class: className }: { user: Pick<SessionUser, "name" | "email" | "image">; class?: string } = $props();
6
+ const initials = $derived((user.name || user.email || "?").slice(0, 2).toUpperCase());
7
+ </script>
8
+
9
+ <Avatar.Root class={className}>
10
+ {#if user.image}<Avatar.Image src={user.image} alt={user.name} />{/if}
11
+ <Avatar.Fallback>{initials}</Avatar.Fallback>
12
+ </Avatar.Root>
@@ -0,0 +1,9 @@
1
+ import { MediaQuery } from "svelte/reactivity";
2
+
3
+ const DEFAULT_MOBILE_BREAKPOINT = 768;
4
+
5
+ export class IsMobile extends MediaQuery {
6
+ constructor(breakpoint: number = DEFAULT_MOBILE_BREAKPOINT) {
7
+ super(`max-width: ${breakpoint - 1}px`);
8
+ }
9
+ }
@@ -0,0 +1,27 @@
1
+ import { getContext, setContext } from "svelte";
2
+ import type { Locale, Messages } from "./messages";
3
+
4
+ const KEY = Symbol("i18n");
5
+
6
+ export type I18nContext = { readonly t: Messages; readonly locale: Locale };
7
+
8
+ export function setI18nContext(ctx: I18nContext): void {
9
+ setContext(KEY, ctx);
10
+ }
11
+
12
+ export function getI18n(): I18nContext {
13
+ return getContext(KEY) as I18nContext;
14
+ }
15
+
16
+ // Fill {name}-style placeholders in a message.
17
+ export function fmt(template: string, values: Record<string, string | number>): string {
18
+ return template.replace(/\{(\w+)\}/g, (match, key: string) =>
19
+ key in values ? String(values[key]) : match,
20
+ );
21
+ }
22
+
23
+ // Render a timestamp in the viewer's own locale and timezone (browser defaults),
24
+ // so dates always match the user's regional settings. Used across all pages.
25
+ export function formatDateTime(value: string | Date): string {
26
+ return new Date(value).toLocaleString();
27
+ }
@@ -0,0 +1,359 @@
1
+ // Static message catalogs for the admin dashboard. Default locale is English.
2
+ export const LOCALES = ["en", "ko"] as const;
3
+ export type Locale = (typeof LOCALES)[number];
4
+ export const defaultLocale: Locale = "en";
5
+
6
+ export const localeNames: Record<Locale, string> = {
7
+ en: "English",
8
+ ko: "한국어",
9
+ };
10
+
11
+ const en = {
12
+ common: { appName: "Admin" },
13
+ landing: { title: "Welcome", subtitle: "This is your app's home page. Replace it with your own content — the admin area lives under /admin.", openAdmin: "Open admin" },
14
+ language: { label: "Language" },
15
+ theme: { toggle: "Toggle theme", light: "Light", dark: "Dark", system: "System" },
16
+ auth: {
17
+ signInTitle: "Sign in",
18
+ signInDesc: "Enter your credentials to continue.",
19
+ email: "Email",
20
+ password: "Password",
21
+ forgot: "Forgot?",
22
+ signIn: "Sign in",
23
+ signingIn: "Signing in…",
24
+ noAccount: "No account?",
25
+ signUp: "Sign up",
26
+ signInFailed: "Sign in failed",
27
+ createTitle: "Create account",
28
+ createDesc: "Sign up to get started.",
29
+ name: "Name",
30
+ create: "Create account",
31
+ creating: "Creating…",
32
+ haveAccount: "Have an account?",
33
+ signUpFailed: "Sign up failed",
34
+ resetTitle: "Reset password",
35
+ resetDesc: "We'll send a reset link to your email.",
36
+ sendReset: "Send reset link",
37
+ sending: "Sending…",
38
+ resetSent: "If that email exists, a reset link is on its way.",
39
+ backToSignIn: "Back to sign in",
40
+ requestFailed: "Request failed",
41
+ newTitle: "Set a new password",
42
+ newPassword: "New password",
43
+ updatePassword: "Update password",
44
+ updating: "Updating…",
45
+ missingToken: "Missing or invalid reset token.",
46
+ resetFailed: "Reset failed",
47
+ },
48
+ nav: { overview: "Overview", users: "Users", sessions: "Sessions", audit: "Audit log", account: "Account", signOut: "Sign out" },
49
+ dashboard: { title: "Dashboard", welcome: "Welcome back, {name}.", yourRole: "Your role", signedInAs: "Signed in as" },
50
+ audit: { title: "Audit log", when: "When", actor: "Actor", action: "Action", target: "Target", ip: "IP", empty: "No audit entries.", loadFailed: "Failed to load audit log", total: "{count} entries" },
51
+ users: {
52
+ title: "Users",
53
+ search: "Search by email…",
54
+ name: "Name",
55
+ email: "Email",
56
+ role: "Role",
57
+ status: "Status",
58
+ active: "Active",
59
+ banned: "Banned",
60
+ makeUser: "Make user",
61
+ makeAdmin: "Make admin",
62
+ ban: "Ban",
63
+ unban: "Unban",
64
+ empty: "No users.",
65
+ total: "{count} users",
66
+ previous: "Previous",
67
+ next: "Next",
68
+ roleSet: "Role set to {role}",
69
+ userBanned: "User banned",
70
+ userUnbanned: "User unbanned",
71
+ loadFailed: "Failed to load users",
72
+ actionFailed: "Action failed",
73
+ addUser: "Add user",
74
+ createTitle: "Create user",
75
+ password: "Password",
76
+ create: "Create",
77
+ cancel: "Cancel",
78
+ userCreated: "User created",
79
+ setPassword: "Set password",
80
+ newPassword: "New password",
81
+ save: "Save",
82
+ passwordSet: "Password updated",
83
+ delete: "Delete",
84
+ deleteTitle: "Delete user",
85
+ deleteConfirm: "Delete {email}? This cannot be undone.",
86
+ userDeleted: "User deleted",
87
+ confirmPassword: "Confirm password",
88
+ confirmNewPassword: "Confirm new password",
89
+ passwordMismatch: "Passwords do not match",
90
+ edit: "Edit",
91
+ editTitle: "Edit user",
92
+ userUpdated: "User updated",
93
+ impersonate: "Impersonate",
94
+ banTitle: "Ban user",
95
+ banReason: "Reason (optional)",
96
+ banExpiryDays: "Expires in (days, optional)",
97
+ stopImpersonating: "Stop impersonating",
98
+ impersonatingAs: "Impersonating {email}",
99
+ manage: "Manage",
100
+ revokeSession: "Revoke",
101
+ },
102
+ sessions: {
103
+ title: "Active sessions",
104
+ device: "Device",
105
+ ip: "IP",
106
+ since: "Since",
107
+ revoke: "Revoke",
108
+ unknown: "Unknown",
109
+ empty: "No active sessions.",
110
+ revoked: "Session revoked",
111
+ loadFailed: "Failed to load sessions",
112
+ revokeFailed: "Failed to revoke",
113
+ status: "Status",
114
+ current: "Current",
115
+ signOutOthers: "Sign out other sessions",
116
+ othersRevoked: "Signed out other sessions",
117
+ total: "{count} sessions",
118
+ },
119
+ adminSessions: {
120
+ title: "User sessions",
121
+ user: "User",
122
+ device: "Device",
123
+ ip: "IP",
124
+ since: "Since",
125
+ revoke: "Revoke session",
126
+ revokeAll: "Revoke all for user",
127
+ unknown: "Unknown",
128
+ empty: "No active sessions.",
129
+ revoked: "Session revoked",
130
+ allRevoked: "All sessions revoked for user",
131
+ loadFailed: "Failed to load sessions",
132
+ total: "{count} sessions",
133
+ },
134
+ account: {
135
+ title: "Account",
136
+ profile: "Profile",
137
+ name: "Name",
138
+ email: "Email",
139
+ role: "Role",
140
+ changePassword: "Change password",
141
+ currentPassword: "Current password",
142
+ newPassword: "New password",
143
+ update: "Update password",
144
+ updating: "Updating…",
145
+ changed: "Password changed",
146
+ changeFailed: "Failed to change password",
147
+ nav: { profile: "Profile", security: "Security", connected: "Connected", sessions: "Sessions", danger: "Danger zone" },
148
+ twoFactorTitle: "Two-factor authentication",
149
+ twoFactorDesc: "Add a one-time code from your authenticator app at sign-in.",
150
+ twoFactorOn: "Enabled",
151
+ twoFactorOff: "Disabled",
152
+ enable: "Enable",
153
+ disable: "Disable",
154
+ password: "Password",
155
+ scanHint: "Add this to your authenticator app, then enter the 6-digit code.",
156
+ setupKey: "Setup key (otpauth URI)",
157
+ backupCodes: "Backup codes — store them somewhere safe",
158
+ code: "Verification code",
159
+ verify: "Verify",
160
+ twoFactorEnabled: "Two-factor enabled",
161
+ twoFactorDisabled: "Two-factor disabled",
162
+ connectedTitle: "Connected accounts",
163
+ connectedDesc: "Link social accounts to sign in with them.",
164
+ connect: "Connect",
165
+ disconnect: "Disconnect",
166
+ connected: "Connected",
167
+ notConnected: "Not connected",
168
+ disconnected: "Disconnected",
169
+ dangerTitle: "Delete account",
170
+ dangerDesc: "Permanently delete your account and all associated data.",
171
+ deleteAccount: "Delete account",
172
+ deleteAccountConfirm: "This permanently deletes your account and cannot be undone. Enter your password to confirm.",
173
+ accountDeleted: "Account deleted",
174
+ save: "Save changes",
175
+ saved: "Profile updated",
176
+ saveFailed: "Failed to save profile",
177
+ verified: "Verified",
178
+ unverified: "Unverified",
179
+ },
180
+ };
181
+
182
+ export type Messages = typeof en;
183
+
184
+ const ko: Messages = {
185
+ common: { appName: "관리자" },
186
+ landing: { title: "환영합니다", subtitle: "앱의 홈 페이지입니다. 원하는 내용으로 교체하세요 — 관리자 기능은 /admin 에 있습니다.", openAdmin: "관리자 열기" },
187
+ language: { label: "언어" },
188
+ theme: { toggle: "테마 전환", light: "라이트", dark: "다크", system: "시스템" },
189
+ auth: {
190
+ signInTitle: "로그인",
191
+ signInDesc: "계속하려면 로그인하세요.",
192
+ email: "이메일",
193
+ password: "비밀번호",
194
+ forgot: "비밀번호 찾기",
195
+ signIn: "로그인",
196
+ signingIn: "로그인 중…",
197
+ noAccount: "계정이 없으신가요?",
198
+ signUp: "회원가입",
199
+ signInFailed: "로그인에 실패했습니다",
200
+ createTitle: "회원가입",
201
+ createDesc: "가입하고 시작하세요.",
202
+ name: "이름",
203
+ create: "계정 만들기",
204
+ creating: "생성 중…",
205
+ haveAccount: "이미 계정이 있으신가요?",
206
+ signUpFailed: "회원가입에 실패했습니다",
207
+ resetTitle: "비밀번호 재설정",
208
+ resetDesc: "이메일로 재설정 링크를 보내드립니다.",
209
+ sendReset: "재설정 링크 보내기",
210
+ sending: "전송 중…",
211
+ resetSent: "해당 이메일이 존재하면 재설정 링크가 전송됩니다.",
212
+ backToSignIn: "로그인으로 돌아가기",
213
+ requestFailed: "요청에 실패했습니다",
214
+ newTitle: "새 비밀번호 설정",
215
+ newPassword: "새 비밀번호",
216
+ updatePassword: "비밀번호 변경",
217
+ updating: "변경 중…",
218
+ missingToken: "재설정 토큰이 없거나 유효하지 않습니다.",
219
+ resetFailed: "재설정에 실패했습니다",
220
+ },
221
+ nav: { overview: "개요", users: "회원", sessions: "세션", audit: "감사 로그", account: "계정", signOut: "로그아웃" },
222
+ dashboard: { title: "대시보드", welcome: "{name}님, 환영합니다.", yourRole: "내 권한", signedInAs: "로그인 계정" },
223
+ audit: { title: "감사 로그", when: "시각", actor: "수행자", action: "동작", target: "대상", ip: "IP", empty: "감사 기록이 없습니다.", loadFailed: "감사 로그를 불러오지 못했습니다", total: "항목 {count}개" },
224
+ users: {
225
+ title: "회원",
226
+ search: "이메일로 검색…",
227
+ name: "이름",
228
+ email: "이메일",
229
+ role: "권한",
230
+ status: "상태",
231
+ active: "활성",
232
+ banned: "차단됨",
233
+ makeUser: "일반 사용자로",
234
+ makeAdmin: "관리자로",
235
+ ban: "차단",
236
+ unban: "차단 해제",
237
+ empty: "회원이 없습니다.",
238
+ total: "회원 {count}명",
239
+ previous: "이전",
240
+ next: "다음",
241
+ roleSet: "권한을 {role}(으)로 변경했습니다",
242
+ userBanned: "회원을 차단했습니다",
243
+ userUnbanned: "차단을 해제했습니다",
244
+ loadFailed: "회원 목록을 불러오지 못했습니다",
245
+ actionFailed: "작업에 실패했습니다",
246
+ addUser: "사용자 추가",
247
+ createTitle: "사용자 생성",
248
+ password: "비밀번호",
249
+ create: "생성",
250
+ cancel: "취소",
251
+ userCreated: "사용자를 생성했습니다",
252
+ setPassword: "비밀번호 설정",
253
+ newPassword: "새 비밀번호",
254
+ save: "저장",
255
+ passwordSet: "비밀번호를 변경했습니다",
256
+ delete: "삭제",
257
+ deleteTitle: "사용자 삭제",
258
+ deleteConfirm: "{email} 사용자를 삭제할까요? 되돌릴 수 없습니다.",
259
+ userDeleted: "사용자를 삭제했습니다",
260
+ confirmPassword: "비밀번호 확인",
261
+ confirmNewPassword: "새 비밀번호 확인",
262
+ passwordMismatch: "비밀번호가 일치하지 않습니다",
263
+ edit: "편집",
264
+ editTitle: "사용자 편집",
265
+ userUpdated: "사용자를 수정했습니다",
266
+ impersonate: "이 사용자로 로그인",
267
+ banTitle: "사용자 차단",
268
+ banReason: "사유 (선택)",
269
+ banExpiryDays: "만료 (일, 선택)",
270
+ stopImpersonating: "대리 로그인 종료",
271
+ impersonatingAs: "{email} 사용자로 대리 로그인 중",
272
+ manage: "관리",
273
+ revokeSession: "종료",
274
+ },
275
+ sessions: {
276
+ title: "활성 세션",
277
+ device: "기기",
278
+ ip: "IP",
279
+ since: "시작",
280
+ revoke: "종료",
281
+ unknown: "알 수 없음",
282
+ empty: "활성 세션이 없습니다.",
283
+ revoked: "세션을 종료했습니다",
284
+ loadFailed: "세션을 불러오지 못했습니다",
285
+ revokeFailed: "세션 종료에 실패했습니다",
286
+ status: "상태",
287
+ current: "현재",
288
+ signOutOthers: "다른 세션 모두 종료",
289
+ othersRevoked: "다른 세션을 모두 종료했습니다",
290
+ total: "세션 {count}개",
291
+ },
292
+ adminSessions: {
293
+ title: "사용자 세션",
294
+ user: "사용자",
295
+ device: "기기",
296
+ ip: "IP",
297
+ since: "시작",
298
+ revoke: "세션 종료",
299
+ revokeAll: "사용자 세션 모두 종료",
300
+ unknown: "알 수 없음",
301
+ empty: "활성 세션이 없습니다.",
302
+ revoked: "세션을 종료했습니다",
303
+ allRevoked: "사용자의 세션을 모두 종료했습니다",
304
+ loadFailed: "세션을 불러오지 못했습니다",
305
+ total: "세션 {count}개",
306
+ },
307
+ account: {
308
+ title: "계정",
309
+ profile: "프로필",
310
+ name: "이름",
311
+ email: "이메일",
312
+ role: "권한",
313
+ changePassword: "비밀번호 변경",
314
+ currentPassword: "현재 비밀번호",
315
+ newPassword: "새 비밀번호",
316
+ update: "비밀번호 변경",
317
+ updating: "변경 중…",
318
+ changed: "비밀번호를 변경했습니다",
319
+ changeFailed: "비밀번호 변경에 실패했습니다",
320
+ nav: { profile: "프로필", security: "보안", connected: "연결", sessions: "세션", danger: "위험 영역" },
321
+ twoFactorTitle: "2단계 인증",
322
+ twoFactorDesc: "로그인 시 인증 앱의 일회용 코드를 추가로 요구합니다.",
323
+ twoFactorOn: "사용 중",
324
+ twoFactorOff: "사용 안 함",
325
+ enable: "사용",
326
+ disable: "해제",
327
+ password: "비밀번호",
328
+ scanHint: "인증 앱에 등록한 뒤 6자리 코드를 입력하세요.",
329
+ setupKey: "설정 키 (otpauth URI)",
330
+ backupCodes: "백업 코드 — 안전한 곳에 보관하세요",
331
+ code: "인증 코드",
332
+ verify: "확인",
333
+ twoFactorEnabled: "2단계 인증을 사용합니다",
334
+ twoFactorDisabled: "2단계 인증을 해제했습니다",
335
+ connectedTitle: "연결된 계정",
336
+ connectedDesc: "소셜 계정을 연결하면 해당 계정으로 로그인할 수 있습니다.",
337
+ connect: "연결",
338
+ disconnect: "연결 해제",
339
+ connected: "연결됨",
340
+ notConnected: "연결 안 됨",
341
+ disconnected: "연결을 해제했습니다",
342
+ dangerTitle: "계정 삭제",
343
+ dangerDesc: "계정과 모든 관련 데이터를 영구히 삭제합니다.",
344
+ deleteAccount: "계정 삭제",
345
+ deleteAccountConfirm: "계정이 영구히 삭제되며 되돌릴 수 없습니다. 확인하려면 비밀번호를 입력하세요.",
346
+ accountDeleted: "계정을 삭제했습니다",
347
+ save: "변경 저장",
348
+ saved: "프로필을 저장했습니다",
349
+ saveFailed: "프로필 저장에 실패했습니다",
350
+ verified: "인증됨",
351
+ unverified: "미인증",
352
+ },
353
+ };
354
+
355
+ export const messages: Record<Locale, Messages> = { en, ko };
356
+
357
+ export function resolveLocale(value: string | undefined | null): Locale {
358
+ return LOCALES.includes(value as Locale) ? (value as Locale) : defaultLocale;
359
+ }
@@ -0,0 +1,14 @@
1
+ import type { LayoutServerLoad } from "./$types";
2
+
3
+ type Capabilities = { twoFactor: boolean; providers: string[]; deleteAccount: boolean; auditLog: boolean };
4
+
5
+ export const load: LayoutServerLoad = async ({ locals, fetch }) => {
6
+ let capabilities: Capabilities = { twoFactor: false, providers: [], deleteAccount: false, auditLog: false };
7
+ try {
8
+ const res = await fetch("/api/account/capabilities");
9
+ if (res.ok) capabilities = (await res.json()) as Capabilities;
10
+ } catch {
11
+ /* keep defaults */
12
+ }
13
+ return { user: locals.user, impersonating: !!locals.session?.impersonatedBy, capabilities };
14
+ };
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ import { goto } from "$app/navigation";
3
+ import * as Sidebar from "$lib/components/ui/sidebar";
4
+ import { Separator } from "$lib/components/ui/separator";
5
+ import { Button } from "$lib/components/ui/button";
6
+ import AppSidebar from "$lib/components/app-sidebar.svelte";
7
+ import ThemeToggle from "$lib/components/theme-toggle.svelte";
8
+ import LanguageSwitch from "$lib/components/language-switch.svelte";
9
+ import { Toaster } from "$lib/components/ui/sonner";
10
+ import { api } from "$lib/api";
11
+ import { getI18n } from "$lib/i18n";
12
+ import type { SessionUser } from "../../app.d.ts";
13
+
14
+ let {
15
+ children,
16
+ data,
17
+ }: {
18
+ children: import("svelte").Snippet;
19
+ data: { user: SessionUser; impersonating: boolean; capabilities: { auditLog?: boolean } };
20
+ } = $props();
21
+ const i18n = getI18n();
22
+
23
+ async function stopImpersonating(): Promise<void> {
24
+ await api.auth.admin.stopImpersonating();
25
+ await goto("/admin", { invalidateAll: true });
26
+ }
27
+ </script>
28
+
29
+ <Sidebar.Provider>
30
+ <AppSidebar user={data.user} capabilities={data.capabilities} />
31
+ <Sidebar.Inset>
32
+ {#if data.impersonating}
33
+ <div class="bg-primary text-primary-foreground flex items-center justify-between gap-2 px-4 py-2 text-sm">
34
+ <span>{i18n.t.users.impersonatingAs.replace("{email}", data.user.email)}</span>
35
+ <Button variant="secondary" size="sm" onclick={stopImpersonating}>{i18n.t.users.stopImpersonating}</Button>
36
+ </div>
37
+ {/if}
38
+ <header class="flex h-14 items-center gap-2 border-b px-4">
39
+ <Sidebar.Trigger />
40
+ <Separator orientation="vertical" class="mr-2 h-4" />
41
+ <div class="flex-1"></div>
42
+ <LanguageSwitch />
43
+ <ThemeToggle />
44
+ </header>
45
+ <main class="flex-1 overflow-auto p-6">
46
+ {@render children()}
47
+ </main>
48
+ </Sidebar.Inset>
49
+ </Sidebar.Provider>
50
+ <Toaster />
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import * as Card from "$lib/components/ui/card";
3
+ import { getI18n, fmt } from "$lib/i18n";
4
+ import type { SessionUser } from "../../../app.d.ts";
5
+
6
+ let { data }: { data: { user: SessionUser } } = $props();
7
+ const i18n = getI18n();
8
+ </script>
9
+
10
+ <div class="flex flex-col gap-6">
11
+ <div>
12
+ <h1 class="text-2xl font-semibold">{i18n.t.dashboard.title}</h1>
13
+ <p class="text-muted-foreground text-sm">{fmt(i18n.t.dashboard.welcome, { name: data.user.name })}</p>
14
+ </div>
15
+ <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
16
+ <Card.Root>
17
+ <Card.Header><Card.Title>{i18n.t.dashboard.yourRole}</Card.Title></Card.Header>
18
+ <Card.Content class="text-2xl font-semibold capitalize">{data.user.role ?? "user"}</Card.Content>
19
+ </Card.Root>
20
+ <Card.Root>
21
+ <Card.Header><Card.Title>{i18n.t.dashboard.signedInAs}</Card.Title></Card.Header>
22
+ <Card.Content class="text-muted-foreground truncate text-sm">{data.user.email}</Card.Content>
23
+ </Card.Root>
24
+ </div>
25
+ </div>
@@ -0,0 +1,5 @@
1
+ import type { PageServerLoad } from "./$types";
2
+
3
+ export const load: PageServerLoad = ({ locals }) => {
4
+ return { currentSessionId: locals.session?.id ?? null };
5
+ };