create-aron-app 0.1.6 → 0.1.7

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 (260) hide show
  1. package/dist/index.js +50 -115
  2. package/package.json +5 -2
  3. package/templates/{_base/.cursor → .cursor}/rules/api_architecture.mdc +27 -33
  4. package/templates/{_base/.cursor → .cursor}/rules/coding_standards.mdc +1 -1
  5. package/templates/{_base/.cursor → .cursor}/rules/convex_rules.mdc +78 -422
  6. package/templates/.cursor/rules/frontend_architecture_core.mdc +495 -0
  7. package/templates/.cursor/rules/frontend_architecture_nextjs.mdc +458 -0
  8. package/templates/.cursor/rules/frontend_architecture_reactrouter.mdc +473 -0
  9. package/templates/apps/api/_generated/api.d.ts +57 -0
  10. package/templates/apps/api/_generated/api.js +23 -0
  11. package/templates/apps/api/_generated/dataModel.d.ts +60 -0
  12. package/templates/apps/api/_generated/server.d.ts +143 -0
  13. package/templates/apps/api/_generated/server.js +93 -0
  14. package/templates/apps/api/http.ts +16 -0
  15. package/templates/apps/nextjs/.env.example +10 -0
  16. package/templates/{nextjs → apps/nextjs}/project.json +5 -5
  17. package/templates/{nextjs → apps/nextjs}/src/app/(auth)/not-allowed/page.tsx +1 -0
  18. package/templates/apps/nextjs/src/app/(dashboard)/layout.tsx +22 -0
  19. package/templates/apps/nextjs/src/app/(dashboard)/page.tsx +12 -0
  20. package/templates/{nextjs → apps/nextjs}/src/app/(dashboard)/todos/[id]/page.tsx +5 -2
  21. package/templates/apps/nextjs/src/app/(dashboard)/todos/page.tsx +19 -0
  22. package/templates/apps/nextjs/src/middleware.ts +18 -0
  23. package/templates/apps/nextjs/src/surfaces/home/bootstrap.ts +9 -0
  24. package/templates/apps/nextjs/src/surfaces/home/home.tsx +27 -0
  25. package/templates/apps/nextjs/src/surfaces/home/install.tsx +17 -0
  26. package/templates/apps/nextjs/src/surfaces/home/layout.tsx +44 -0
  27. package/templates/apps/nextjs/src/surfaces/home/main/create.tsx +34 -0
  28. package/templates/apps/nextjs/src/surfaces/sidebar/install.tsx +23 -0
  29. package/templates/apps/nextjs/src/surfaces/sidebar/layout.tsx +118 -0
  30. package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/create.tsx +19 -0
  31. package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/nav_config.ts +22 -0
  32. package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/nav_main.tsx +25 -0
  33. package/templates/apps/nextjs/src/surfaces/sidebar/nav_secondary/create.tsx +21 -0
  34. package/templates/apps/nextjs/src/surfaces/sidebar/nav_secondary/nav_secondary.tsx +33 -0
  35. package/templates/apps/nextjs/src/surfaces/sidebar/sidebar.tsx +23 -0
  36. package/templates/{nextjs/src/ui/sidebar/nav_link.tsx → apps/nextjs/src/surfaces/sidebar/ui/sidebar_nav_link.tsx} +13 -10
  37. package/templates/apps/nextjs/src/surfaces/sidebar/user_menu/create.tsx +28 -0
  38. package/templates/apps/nextjs/src/surfaces/sidebar/user_menu/user_menu.tsx +42 -0
  39. package/templates/apps/nextjs/src/surfaces/todos/all_todos/all_todos.tsx +29 -0
  40. package/templates/apps/nextjs/src/surfaces/todos/all_todos/all_todos_controller.ts +61 -0
  41. package/templates/apps/nextjs/src/surfaces/todos/all_todos/bootstrap.ts +21 -0
  42. package/templates/apps/nextjs/src/surfaces/todos/all_todos/header/create.tsx +23 -0
  43. package/templates/apps/nextjs/src/surfaces/todos/all_todos/install.tsx +23 -0
  44. package/templates/apps/nextjs/src/surfaces/todos/all_todos/layout.tsx +44 -0
  45. package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/create.tsx +49 -0
  46. package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/main.tsx +70 -0
  47. package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +56 -0
  48. package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +99 -0
  49. package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +11 -0
  50. package/templates/apps/nextjs/src/surfaces/todos/single_todo/bootstrap.ts +32 -0
  51. package/templates/apps/nextjs/src/surfaces/todos/single_todo/header/create.tsx +26 -0
  52. package/templates/apps/nextjs/src/surfaces/todos/single_todo/header/header.tsx +22 -0
  53. package/templates/apps/nextjs/src/surfaces/todos/single_todo/install.tsx +27 -0
  54. package/templates/apps/nextjs/src/surfaces/todos/single_todo/layout.tsx +55 -0
  55. package/templates/apps/nextjs/src/surfaces/todos/single_todo/main/create.tsx +38 -0
  56. package/templates/apps/nextjs/src/surfaces/todos/single_todo/main/main.tsx +49 -0
  57. package/templates/apps/nextjs/src/surfaces/todos/single_todo/single_todo.tsx +29 -0
  58. package/templates/apps/nextjs/src/surfaces/todos/single_todo/single_todo_controller.ts +13 -0
  59. package/templates/apps/nextjs/src/utils/auth.ts +18 -0
  60. package/templates/apps/react-router/.env.example +10 -0
  61. package/templates/apps/react-router/.react-router/types/+future.ts +9 -0
  62. package/templates/apps/react-router/.react-router/types/+routes.ts +71 -0
  63. package/templates/apps/react-router/.react-router/types/+server-build.d.ts +18 -0
  64. package/templates/apps/react-router/.react-router/types/src/+types/root.ts +59 -0
  65. package/templates/apps/react-router/.react-router/types/src/routes/(auth)/+types/layout.ts +62 -0
  66. package/templates/apps/react-router/.react-router/types/src/routes/(auth)/sign-in/+types/index.ts +65 -0
  67. package/templates/apps/react-router/.react-router/types/src/routes/(dashboard)/+types/index.ts +65 -0
  68. package/templates/apps/react-router/.react-router/types/src/routes/(dashboard)/+types/layout.ts +62 -0
  69. package/templates/apps/react-router/.react-router/types/src/routes/(dashboard)/todos/+types/[id].ts +65 -0
  70. package/templates/apps/react-router/.react-router/types/src/routes/(dashboard)/todos/+types/index.ts +65 -0
  71. package/templates/{react-router → apps/react-router}/project.json +4 -4
  72. package/templates/apps/react-router/src/app.css +3 -0
  73. package/templates/{react-router → apps/react-router}/src/components/error_boundary.tsx +1 -1
  74. package/templates/{react-router → apps/react-router}/src/providers/api_auth_provider.tsx +2 -0
  75. package/templates/{react-router/src/routes/auth → apps/react-router/src/routes/(auth)}/layout.tsx +1 -1
  76. package/templates/apps/react-router/src/routes/(dashboard)/index.tsx +19 -0
  77. package/templates/apps/react-router/src/routes/(dashboard)/layout.tsx +37 -0
  78. package/templates/apps/react-router/src/routes/(dashboard)/todos/[id].tsx +19 -0
  79. package/templates/apps/react-router/src/routes/(dashboard)/todos/index.tsx +19 -0
  80. package/templates/apps/react-router/src/routes.ts +12 -0
  81. package/templates/apps/react-router/src/surfaces/home/bootstrap.ts +9 -0
  82. package/templates/apps/react-router/src/surfaces/home/home.tsx +25 -0
  83. package/templates/apps/react-router/src/surfaces/home/install.tsx +17 -0
  84. package/templates/apps/react-router/src/surfaces/home/layout.tsx +35 -0
  85. package/templates/apps/react-router/src/surfaces/home/main/create.tsx +32 -0
  86. package/templates/apps/react-router/src/surfaces/sidebar/install.tsx +23 -0
  87. package/templates/apps/react-router/src/surfaces/sidebar/layout.tsx +110 -0
  88. package/templates/apps/react-router/src/surfaces/sidebar/nav_main/create.tsx +31 -0
  89. package/templates/apps/react-router/src/surfaces/sidebar/nav_main/nav_main.tsx +42 -0
  90. package/templates/apps/react-router/src/surfaces/sidebar/nav_secondary/create.tsx +21 -0
  91. package/templates/apps/react-router/src/surfaces/sidebar/nav_secondary/nav_secondary.tsx +31 -0
  92. package/templates/apps/react-router/src/surfaces/sidebar/sidebar.tsx +18 -0
  93. package/templates/apps/react-router/src/surfaces/sidebar/user_menu/create.tsx +26 -0
  94. package/templates/{react-router/src/layouts/sidebar/sidebar_aside → apps/react-router/src/surfaces/sidebar/user_menu}/user_menu.tsx +13 -9
  95. package/templates/apps/react-router/src/surfaces/todos/all_todos/all_todos.tsx +25 -0
  96. package/templates/apps/react-router/src/surfaces/todos/all_todos/all_todos_controller.ts +47 -0
  97. package/templates/apps/react-router/src/surfaces/todos/all_todos/bootstrap.ts +18 -0
  98. package/templates/apps/react-router/src/surfaces/todos/all_todos/header/create.tsx +21 -0
  99. package/templates/apps/react-router/src/surfaces/todos/all_todos/install.tsx +20 -0
  100. package/templates/apps/react-router/src/surfaces/todos/all_todos/layout.tsx +35 -0
  101. package/templates/apps/react-router/src/surfaces/todos/all_todos/main/create.tsx +47 -0
  102. package/templates/apps/react-router/src/surfaces/todos/all_todos/main/main.tsx +68 -0
  103. package/templates/apps/react-router/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +54 -0
  104. package/templates/apps/react-router/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +97 -0
  105. package/templates/apps/react-router/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +11 -0
  106. package/templates/apps/react-router/src/surfaces/todos/single_todo/bootstrap.ts +36 -0
  107. package/templates/apps/react-router/src/surfaces/todos/single_todo/header/create.tsx +32 -0
  108. package/templates/apps/react-router/src/surfaces/todos/single_todo/header/header.tsx +25 -0
  109. package/templates/apps/react-router/src/surfaces/todos/single_todo/install.tsx +27 -0
  110. package/templates/apps/react-router/src/surfaces/todos/single_todo/layout.tsx +45 -0
  111. package/templates/apps/react-router/src/surfaces/todos/single_todo/main/create.tsx +35 -0
  112. package/templates/apps/react-router/src/surfaces/todos/single_todo/main/main.tsx +47 -0
  113. package/templates/apps/react-router/src/surfaces/todos/single_todo/single_todo.tsx +27 -0
  114. package/templates/apps/react-router/src/surfaces/todos/single_todo/single_todo_controller.ts +16 -0
  115. package/templates/{react-router → apps/react-router}/vite.config.ts +27 -3
  116. package/templates/{_base/biome.json → biome.json} +7 -0
  117. package/templates/bun.lock +3187 -0
  118. package/templates/{_base/emails → emails}/project.json +1 -1
  119. package/templates/{_base/nx.json → nx.json} +11 -0
  120. package/templates/package.json +92 -0
  121. package/templates/{_base/tsconfig.base.json → tsconfig.base.json} +4 -1
  122. package/templates/_base/.cursor/rules/frontend_rules.mdc +0 -268
  123. package/templates/_base/.env.convex.example +0 -3
  124. package/templates/_base/_gitignore +0 -58
  125. package/templates/_base/package.json +0 -73
  126. package/templates/nextjs/.env.example +0 -8
  127. package/templates/nextjs/src/app/(dashboard)/layout.tsx +0 -27
  128. package/templates/nextjs/src/app/(dashboard)/page.tsx +0 -5
  129. package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +0 -16
  130. package/templates/nextjs/src/middleware.ts +0 -18
  131. package/templates/nextjs/src/surfaces/home_surface.tsx +0 -22
  132. package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +0 -97
  133. package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +0 -107
  134. package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +0 -90
  135. package/templates/nextjs/src/ui/sidebar/sidebar.tsx +0 -125
  136. package/templates/react-router/.env.example +0 -8
  137. package/templates/react-router/src/app.css +0 -3
  138. package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +0 -76
  139. package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +0 -22
  140. package/templates/react-router/src/routes/index.tsx +0 -9
  141. package/templates/react-router/src/routes/layout.tsx +0 -26
  142. package/templates/react-router/src/routes/todos/[id].tsx +0 -22
  143. package/templates/react-router/src/routes/todos/index.tsx +0 -13
  144. package/templates/react-router/src/routes.ts +0 -12
  145. package/templates/react-router/src/surfaces/home_surface.tsx +0 -20
  146. package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +0 -87
  147. package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +0 -102
  148. package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +0 -81
  149. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/SKILL.md +0 -0
  150. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/SKILL.md +0 -0
  151. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +0 -0
  152. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +0 -0
  153. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +0 -0
  154. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +0 -0
  155. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +0 -0
  156. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/SKILL.md +0 -0
  157. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +0 -0
  158. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +0 -0
  159. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +0 -0
  160. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +0 -0
  161. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +0 -0
  162. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +0 -0
  163. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +0 -0
  164. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +0 -0
  165. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +0 -0
  166. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +0 -0
  167. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +0 -0
  168. /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-webhooks/SKILL.md +0 -0
  169. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/SKILL.md +0 -0
  170. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/agents/openai.yml +0 -0
  171. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn-small.png +0 -0
  172. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn.png +0 -0
  173. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/cli.md +0 -0
  174. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/customization.md +0 -0
  175. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/evals/evals.json +0 -0
  176. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/mcp.md +0 -0
  177. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/base-vs-radix.md +0 -0
  178. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/composition.md +0 -0
  179. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/forms.md +0 -0
  180. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/icons.md +0 -0
  181. /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/styling.md +0 -0
  182. /package/templates/{_base/.cursor → .cursor}/commands/builder.md +0 -0
  183. /package/templates/{_base/.cursor → .cursor}/commands/pr.md +0 -0
  184. /package/templates/{_base/.github → .github}/workflows/ci.yml +0 -0
  185. /package/templates/{_base/.nvmrc → .nvmrc} +0 -0
  186. /package/templates/{_base/.vscode → .vscode}/settings.json +0 -0
  187. /package/templates/{_base/apps → apps}/api/auth.config.ts +0 -0
  188. /package/templates/{_base/apps → apps}/api/functions.ts +0 -0
  189. /package/templates/{_base/apps → apps}/api/project.json +0 -0
  190. /package/templates/{_base/apps → apps}/api/schema.ts +0 -0
  191. /package/templates/{_base/apps → apps}/api/todos/crud.ts +0 -0
  192. /package/templates/{_base/apps → apps}/api/todos/schema.ts +0 -0
  193. /package/templates/{_base/apps → apps}/api/todos/types.ts +0 -0
  194. /package/templates/{_base/apps → apps}/api/tsconfig.json +0 -0
  195. /package/templates/{_base/apps → apps}/api/types.ts +0 -0
  196. /package/templates/{nextjs → apps/nextjs}/index.d.ts +0 -0
  197. /package/templates/{nextjs → apps/nextjs}/next-env.d.ts +0 -0
  198. /package/templates/{nextjs → apps/nextjs}/next.config.js +0 -0
  199. /package/templates/{nextjs → apps/nextjs}/postcss.config.js +0 -0
  200. /package/templates/{nextjs → apps/nextjs}/src/app/(auth)/layout.tsx +0 -0
  201. /package/templates/{nextjs → apps/nextjs}/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +0 -0
  202. /package/templates/{nextjs → apps/nextjs}/src/app/app.css +0 -0
  203. /package/templates/{nextjs → apps/nextjs}/src/app/layout.tsx +0 -0
  204. /package/templates/{nextjs → apps/nextjs}/src/providers/convex_provider.tsx +0 -0
  205. /package/templates/{nextjs/src → apps/nextjs/src/utils}/convex.ts +0 -0
  206. /package/templates/{nextjs → apps/nextjs}/src/utils/font.ts +0 -0
  207. /package/templates/{nextjs → apps/nextjs}/tsconfig.json +0 -0
  208. /package/templates/{react-router → apps/react-router}/postcss.config.js +0 -0
  209. /package/templates/{react-router → apps/react-router}/public/favicon.ico +0 -0
  210. /package/templates/{react-router → apps/react-router}/react-router.config.ts +0 -0
  211. /package/templates/{react-router → apps/react-router}/src/root.tsx +0 -0
  212. /package/templates/{react-router/src/routes/auth/sign-in.tsx → apps/react-router/src/routes/(auth)/sign-in/index.tsx} +0 -0
  213. /package/templates/{react-router → apps/react-router}/tsconfig.json +0 -0
  214. /package/templates/{_base/convex.json → convex.json} +0 -0
  215. /package/templates/{_base/emails → emails}/tsconfig.json +0 -0
  216. /package/templates/{_base/emails → emails}/welcome_email.tsx +0 -0
  217. /package/templates/{_base/scripts → scripts}/sync_convex_env.ts +0 -0
  218. /package/templates/{_base/shared → shared}/assets/image.d.ts +0 -0
  219. /package/templates/{_base/shared → shared}/assets/src/styles/global.css +0 -0
  220. /package/templates/{_base/shared → shared}/assets/tsconfig.json +0 -0
  221. /package/templates/{_base/shared → shared}/ui/src/base/alert_dialog.tsx +0 -0
  222. /package/templates/{_base/shared → shared}/ui/src/base/badge.tsx +0 -0
  223. /package/templates/{_base/shared → shared}/ui/src/base/basic_data_table.tsx +0 -0
  224. /package/templates/{_base/shared → shared}/ui/src/base/button.tsx +0 -0
  225. /package/templates/{_base/shared → shared}/ui/src/base/button_group.tsx +0 -0
  226. /package/templates/{_base/shared → shared}/ui/src/base/card.tsx +0 -0
  227. /package/templates/{_base/shared → shared}/ui/src/base/checkbox.tsx +0 -0
  228. /package/templates/{_base/shared → shared}/ui/src/base/command.tsx +0 -0
  229. /package/templates/{_base/shared → shared}/ui/src/base/dialog.tsx +0 -0
  230. /package/templates/{_base/shared → shared}/ui/src/base/dropdown_menu.tsx +0 -0
  231. /package/templates/{_base/shared → shared}/ui/src/base/form.tsx +0 -0
  232. /package/templates/{_base/shared → shared}/ui/src/base/input.tsx +0 -0
  233. /package/templates/{_base/shared → shared}/ui/src/base/label.tsx +0 -0
  234. /package/templates/{_base/shared → shared}/ui/src/base/popover.tsx +0 -0
  235. /package/templates/{_base/shared → shared}/ui/src/base/radio_group.tsx +0 -0
  236. /package/templates/{_base/shared → shared}/ui/src/base/resizable.tsx +0 -0
  237. /package/templates/{_base/shared → shared}/ui/src/base/scroll_area.tsx +0 -0
  238. /package/templates/{_base/shared → shared}/ui/src/base/select.tsx +0 -0
  239. /package/templates/{_base/shared → shared}/ui/src/base/separator.tsx +0 -0
  240. /package/templates/{_base/shared → shared}/ui/src/base/sheet.tsx +0 -0
  241. /package/templates/{_base/shared → shared}/ui/src/base/side_bar.tsx +0 -0
  242. /package/templates/{_base/shared → shared}/ui/src/base/skeleton.tsx +0 -0
  243. /package/templates/{_base/shared → shared}/ui/src/base/spinner.tsx +0 -0
  244. /package/templates/{_base/shared → shared}/ui/src/base/switch.tsx +0 -0
  245. /package/templates/{_base/shared → shared}/ui/src/base/table.tsx +0 -0
  246. /package/templates/{_base/shared → shared}/ui/src/base/text_area.tsx +0 -0
  247. /package/templates/{_base/shared → shared}/ui/src/base/tooltip.tsx +0 -0
  248. /package/templates/{_base/shared → shared}/ui/src/base/utils.ts +0 -0
  249. /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_press.tsx +0 -0
  250. /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_release.tsx +0 -0
  251. /package/templates/{_base/shared → shared}/ui/src/hooks/use_mobile.tsx +0 -0
  252. /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_click.tsx +0 -0
  253. /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_location.tsx +0 -0
  254. /package/templates/{_base/shared → shared}/ui/src/hooks/use_outside_click.tsx +0 -0
  255. /package/templates/{_base/shared → shared}/ui/src/hooks/use_query_params.tsx +0 -0
  256. /package/templates/{_base/shared → shared}/ui/tsconfig.json +0 -0
  257. /package/templates/{_base/shared → shared}/utils/src/convex.ts +0 -0
  258. /package/templates/{_base/shared → shared}/utils/src/time.ts +0 -0
  259. /package/templates/{_base/shared → shared}/utils/tsconfig.json +0 -0
  260. /package/templates/{_base/skills-lock.json → skills-lock.json} +0 -0
@@ -0,0 +1,458 @@
1
+ ---
2
+ description: Frontend surface architecture — Next.js App Router + Convex variant. Covers MobX setup with makeObservable, server-side bootstrap with fetchQuery, and "use client" boundaries. Extends frontend_architecture_core.
3
+ globs: apps/nextjs/src/**
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Frontend Surface Architecture — Next.js + Convex
8
+
9
+ This document covers the Next.js-specific implementation of the surface architecture defined in `frontend_architecture_core`. Read that document first for the layer model, MobX philosophy, and component rules.
10
+
11
+ ---
12
+
13
+ ## Setup
14
+
15
+ ### MobX
16
+
17
+ Next.js uses SWC for compilation, not Babel. TC39 Stage 3 decorator support in SWC requires pinned WASM plugins that break on Next.js version upgrades. Use `makeObservable` instead — identical semantics, zero build tooling risk, works with SWC out of the box.
18
+
19
+ Do **not** set `experimentalDecorators: true`. Do **not** add a `babel.config.js` — this disables SWC entirely.
20
+
21
+ ```typescript
22
+ import { makeObservable, observable, action, computed } from "mobx";
23
+
24
+ export class ExampleController {
25
+ value = "";
26
+ isPending = false;
27
+
28
+ constructor() {
29
+ makeObservable(this, {
30
+ value: observable,
31
+ isPending: observable,
32
+ isReady: computed,
33
+ setValue: action,
34
+ });
35
+ }
36
+
37
+ get isReady() {
38
+ return this.value.trim().length > 0;
39
+ }
40
+
41
+ setValue(v: string) {
42
+ this.value = v;
43
+ }
44
+ }
45
+ ```
46
+
47
+ Rules:
48
+ - Use `makeObservable` with an explicit annotation map in the constructor
49
+ - Use `observable.ref` for fields that hold object/component references (only reference equality needed)
50
+ - Use `runInAction(() => { ... })` when mutating observables inside an async callback or Promise `.then`
51
+
52
+ ### Convex Client
53
+
54
+ The `ConvexReactClient` singleton is exported from the provider so presenters can call mutations directly outside of React:
55
+
56
+ ```typescript
57
+ // src/providers/convex_provider.tsx
58
+ export const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
59
+ ```
60
+
61
+ Rules:
62
+ - Presenters import `convex` from `@/web/providers/convex_provider` to call `convex.mutation()` directly
63
+
64
+ ### Auth Token Helper
65
+
66
+ Required for passing authenticated requests to `fetchQuery` during server rendering:
67
+
68
+ ```typescript
69
+ // src/utils/auth.ts
70
+ import { auth } from "@clerk/nextjs/server";
71
+
72
+ export const getAuthToken = async () => {
73
+ return (await (await auth()).getToken()) ?? undefined;
74
+ };
75
+ ```
76
+
77
+ ---
78
+
79
+ ## App routing: `(auth)` vs `(dashboard)`
80
+
81
+ Next.js [route groups](https://nextjs.org/docs/app/building-your-application/routing/route-groups) use parentheses: `app/(auth)/` and `app/(dashboard)/`. **Parent folder names do not appear in the URL.**
82
+
83
+ | Group | Role |
84
+ | --- | --- |
85
+ | `(auth)` | Sign-in and other unauthenticated pages. **No** app sidebar — minimal or centered layout (see `(auth)/layout.tsx`). |
86
+ | `(dashboard)` | Authenticated app **shell**: `SidebarProvider` + **Sidebar** surface + `SidebarInset` wrapping `{children}`. All main app routes nest here. |
87
+
88
+ Canonical URLs (unchanged by group folders):
89
+
90
+ - `/` — home
91
+ - `/todos` — all todos
92
+ - `/todos/[id]` — single todo
93
+ - `/sign-in/[[...sign-in]]` (or your Clerk catch-all) — auth
94
+
95
+ The `(dashboard)/layout.tsx` file should remain a **Server Component** when possible: compose providers and the client **Sidebar** entry only; avoid pulling server-only auth into client trees unnecessarily. The Sidebar surface module is a **`"use client"`** boundary (MobX + optional hooks).
96
+
97
+ ---
98
+
99
+ ## Shell surface vs page surfaces
100
+
101
+ - **Shell (layout-mounted):** `surfaces/sidebar/` — mounted **only** from `(dashboard)/layout.tsx`. Persists across navigations inside the dashboard. Uses **`SidebarLayout`** + **`installSidebar`** with lazy section `create*.tsx` files.
102
+ - **Page surfaces:** `surfaces/home/`, `surfaces/todos/all_todos/`, `surfaces/todos/single_todo/` — mounted from **`page.tsx`** under `(dashboard)/`. Each follows `frontend_architecture_core`: `bootstrap.ts` → `[feature].tsx` → `install.tsx` → layout slots → section `create.tsx` / display / controllers.
103
+
104
+ See `frontend_architecture_core` for folder naming: **`all_todos`**, **`single_todo`**, and exported components **`AllTodos`**, **`SingleTodo`** (or `AllTodoSurface` / `SingleTodoSurface` if you keep the `Surface` suffix consistently).
105
+
106
+ ---
107
+
108
+ ## Sidebar surface (layout chrome)
109
+
110
+ Required structure (slots are **product-dependent** — add/remove sections as needed):
111
+
112
+ ```
113
+ surfaces/sidebar/
114
+ sidebar.tsx # client entry: useMemo(createSidebarLayout), useEffect(() => installSidebar({ layout }))
115
+ layout.tsx # SidebarLayout + createSidebarLayout() — MobX observable slots + shell JSX
116
+ install.tsx # installSidebar — dynamic import() each section's create
117
+ nav_main/ # example section
118
+ create.tsx
119
+ nav_main.tsx # dumb display
120
+ nav_secondary/
121
+ create.tsx
122
+ nav_secondary.tsx
123
+ user_menu/
124
+ create.tsx
125
+ user_menu.tsx
126
+ ui/ # optional: shared dumb pieces for this surface only
127
+ ```
128
+
129
+ **Install timing:** Layout-mounted chrome uses **`useEffect`** to run `installSidebar` once (avoids some Strict Mode / hydration edge cases for persistent shell). **Route-mounted** feature surfaces use the **synchronous `useRef` install guard**.
130
+
131
+ ---
132
+
133
+ ## Route → surface map
134
+
135
+ | URL | Mount |
136
+ | --- | --- |
137
+ | `/` | `Home` (`surfaces/home/`) |
138
+ | `/todos` | `AllTodos` (`surfaces/todos/all_todos/`) |
139
+ | `/todos/[id]` | `SingleTodo` (`surfaces/todos/single_todo/`) |
140
+ | `(dashboard)` layout | `Sidebar` (`surfaces/sidebar/`) |
141
+
142
+ ---
143
+
144
+ ## Route + Bootstrap Pattern
145
+
146
+ Each Next.js page is a **Server Component** that calls the surface's bootstrap function, then renders the client surface with the bootstrap as a prop. The bootstrap runs `fetchQuery` to load the initial Convex data server-side, so the client surface renders with data immediately — no loading spinner on first paint.
147
+
148
+ ### Page File (`app/(group)/[path]/[id]/page.tsx`)
149
+
150
+ ```typescript
151
+ import type { Metadata } from "next";
152
+ import type { TodoId } from "@/api/todos/types";
153
+ import { bootstrapTodoDetail } from "@/web/surfaces/todo_detail/bootstrap";
154
+ import { TodoDetail } from "@/web/surfaces/todo_detail/todo_detail";
155
+ import { getAuthToken } from "@/web/utils/auth";
156
+
157
+ type TodoDetailPageProps = {
158
+ params: Promise<{ id: TodoId }>;
159
+ };
160
+
161
+ export const metadata: Metadata = {
162
+ title: "Todo",
163
+ description: "Todo detail",
164
+ };
165
+
166
+ export default async function TodoDetailPage({ params }: TodoDetailPageProps) {
167
+ const { id } = await params;
168
+ const token = await getAuthToken();
169
+ const bootstrap = await bootstrapTodoDetail({ todoId: id, token });
170
+ return <TodoDetail bootstrap={bootstrap} />;
171
+ }
172
+ ```
173
+
174
+ Rules:
175
+ - Page is an `async` Server Component — no `"use client"` directive
176
+ - `params` is a `Promise` in Next.js App Router — always `await` it
177
+ - `getAuthToken()` passes the Clerk JWT to `fetchQuery` for authenticated queries
178
+ - Page passes `bootstrap` directly to the surface — no intermediate data reshaping
179
+
180
+ ---
181
+
182
+ ## Layer Reference (Next.js-specific)
183
+
184
+ ### `bootstrap.ts`
185
+
186
+ Async function called in the server page. Uses `fetchQuery` from `convex/nextjs` to load the surface's primary entity server-side. The result is passed as `initialData` to queries in the `create` layer.
187
+
188
+ ```typescript
189
+ import { fetchQuery } from "convex/nextjs";
190
+
191
+ import { api } from "@/api/_generated/api";
192
+ import type { Todo, TodoId } from "@/api/todos/types";
193
+
194
+ export type TodoDetailBootstrapArgs = {
195
+ todoId: TodoId;
196
+ token?: string;
197
+ };
198
+
199
+ export type TodoDetailBootstrap = Awaited<ReturnType<typeof bootstrapTodoDetail>>;
200
+
201
+ export const bootstrapTodoDetail = async ({ todoId, token }: TodoDetailBootstrapArgs) => {
202
+ const todo = await fetchQuery(
203
+ api.todos.crud.getTodo,
204
+ { todoId },
205
+ { token },
206
+ );
207
+ return { todoId, todo };
208
+ };
209
+ ```
210
+
211
+ Rules:
212
+ - Use `fetchQuery` from `convex/nextjs` — returns the actual data value, passes `token` for authenticated queries
213
+ - Auth failures/redirects belong here, not in components
214
+
215
+ ### `[feature].tsx` — Surface Entry Component
216
+
217
+ `"use client"` boundary. Receives `bootstrap` from the server page. **Does not instantiate controllers** — that happens in `install.tsx`.
218
+
219
+ ```typescript
220
+ "use client";
221
+
222
+ import { useRouter } from "next/navigation";
223
+ import { useMemo, useRef } from "react";
224
+
225
+ import type { TodoDetailBootstrap } from "@/web/surfaces/todo_detail/bootstrap";
226
+ import { installTodoDetail } from "@/web/surfaces/todo_detail/install";
227
+ import { createLayout } from "@/web/surfaces/todo_detail/layout";
228
+
229
+ export type TodoDetailProps = {
230
+ bootstrap: TodoDetailBootstrap;
231
+ };
232
+
233
+ export const TodoDetail = ({ bootstrap }: TodoDetailProps) => {
234
+ const router = useRouter();
235
+ const { layout, Layout } = useMemo(() => createLayout(), []);
236
+ const installed = useRef(false);
237
+
238
+ if (!installed.current) {
239
+ installed.current = true;
240
+ installTodoDetail({ layout, bootstrap, router });
241
+ }
242
+
243
+ return <Layout />;
244
+ };
245
+ ```
246
+
247
+ Rules:
248
+ - Always add `"use client"` — this is the boundary between server and client
249
+ - Use `useRouter` from `next/navigation`
250
+ - **Never instantiate controllers here** — pass deps to install, which creates the controller
251
+ - All imports use `@/` aliases — no relative imports
252
+
253
+ ### `install.tsx`
254
+
255
+ ```typescript
256
+ import type { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
257
+
258
+ import type { TodoDetailBootstrap } from "@/web/surfaces/todo_detail/bootstrap";
259
+ import type { TodoDetailLayoutController } from "@/web/surfaces/todo_detail/layout";
260
+ import { TodoDetailController } from "@/web/surfaces/todo_detail/todo_detail_controller";
261
+
262
+ export type InstallTodoDetailOpts = {
263
+ layout: TodoDetailLayoutController;
264
+ bootstrap: TodoDetailBootstrap;
265
+ router: AppRouterInstance;
266
+ };
267
+
268
+ export const installTodoDetail = ({ layout, bootstrap, router }: InstallTodoDetailOpts) => {
269
+ const controller = new TodoDetailController();
270
+
271
+ import("@/web/surfaces/todo_detail/header/create").then(({ createHeader }) => {
272
+ layout.setHeader(createHeader({ controller, bootstrap }));
273
+ });
274
+
275
+ import("@/web/surfaces/todo_detail/main/create").then(({ createMain }) => {
276
+ layout.setMain(createMain({ controller, bootstrap, router }));
277
+ });
278
+ };
279
+ ```
280
+
281
+ Rules:
282
+ - Use `AppRouterInstance` from `next/dist/shared/lib/app-router-context.shared-runtime` for the router type
283
+ - **Controller instantiated here** — exactly once
284
+ - Dynamic `import()` paths use `@/` aliases
285
+
286
+ ### `layout.tsx`
287
+
288
+ ```typescript
289
+ "use client";
290
+
291
+ import { makeObservable, observable, action, runInAction } from "mobx";
292
+ import { observer } from "mobx-react-lite";
293
+ import type { ComponentType } from "react";
294
+
295
+ import { Skeleton } from "@/ui/base/skeleton";
296
+
297
+ export class LayoutController {
298
+ Header: ComponentType | undefined = undefined;
299
+ Main: ComponentType | undefined = undefined;
300
+
301
+ constructor() {
302
+ makeObservable(this, {
303
+ Header: observable.ref,
304
+ Main: observable.ref,
305
+ setHeader: action,
306
+ setMain: action,
307
+ });
308
+ }
309
+
310
+ setHeader(Header: ComponentType) {
311
+ runInAction(() => {
312
+ this.Header = Header;
313
+ });
314
+ }
315
+
316
+ setMain(Main: ComponentType) {
317
+ runInAction(() => {
318
+ this.Main = Main;
319
+ });
320
+ }
321
+ }
322
+
323
+ export const createLayout = () => {
324
+ const layout = new LayoutController();
325
+ return {
326
+ layout,
327
+ Layout: observer(() => {
328
+ const Header = layout.Header;
329
+ const Main = layout.Main;
330
+ return (
331
+ <div className="flex flex-col gap-8 w-full">
332
+ {Header ? <Header /> : <Skeleton className="h-12" />}
333
+ {Main ? <Main /> : <Skeleton className="h-64" />}
334
+ </div>
335
+ );
336
+ }),
337
+ };
338
+ };
339
+ ```
340
+
341
+ Rules:
342
+ - `runInAction` required when mutating observables inside a Promise `.then`
343
+
344
+ ### `[section]/create.tsx`
345
+
346
+ ```typescript
347
+ "use client";
348
+
349
+ import { convexQuery } from "@convex-dev/react-query";
350
+ import { useQuery } from "@tanstack/react-query";
351
+ import { observer } from "mobx-react-lite";
352
+
353
+ import { api } from "@/api/_generated/api";
354
+ import type { TodoDetailBootstrap } from "@/web/surfaces/todo_detail/bootstrap";
355
+ import type { TodoDetailController } from "@/web/surfaces/todo_detail/todo_detail_controller";
356
+ import { Main } from "@/web/surfaces/todo_detail/main/main";
357
+
358
+ export type CreateMainOpts = {
359
+ controller: TodoDetailController;
360
+ bootstrap: TodoDetailBootstrap;
361
+ };
362
+
363
+ export const createMain = ({ controller, bootstrap }: CreateMainOpts) => {
364
+ return observer(() => {
365
+ const { data: todo } = useQuery({
366
+ initialData: bootstrap.todo,
367
+ ...convexQuery(api.todos.crud.getTodo, { todoId: bootstrap.todoId }),
368
+ });
369
+
370
+ return (
371
+ <Main
372
+ todo={todo}
373
+ onToggle={(isCompleted) =>
374
+ controller.updateTodo({
375
+ todoId: bootstrap.todoId,
376
+ isCompleted,
377
+ })
378
+ }
379
+ onEdit={() => controller.openEdit(bootstrap.todoId)}
380
+ />
381
+ );
382
+ });
383
+ };
384
+ ```
385
+
386
+ Rules:
387
+ - Add `"use client"` — create files are client components
388
+ - Spread `convexQuery` with `initialData: bootstrap.[entity]` — eliminates loading flash, query stays reactive after hydration
389
+ - All imports use `@/` aliases — no relative imports
390
+
391
+ ### Display Components
392
+
393
+ Rules:
394
+ - No `"use client"` directive needed — display components have no hooks (exception: `useFormContext` for form displays, which does need `"use client"`)
395
+
396
+ ### `[section]_presenter.ts`
397
+
398
+ ```typescript
399
+ import { makeObservable, observable, action, computed, runInAction } from "mobx";
400
+ import { convex } from "@/web/providers/convex_provider";
401
+ import { api } from "@/api/_generated/api";
402
+ import type { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
403
+
404
+ export type NewTodoPresenterOpts = {
405
+ router: AppRouterInstance;
406
+ };
407
+
408
+ export class NewTodoPresenter {
409
+ private readonly router: AppRouterInstance;
410
+
411
+ input = "";
412
+ isPending = false;
413
+
414
+ constructor({ router }: NewTodoPresenterOpts) {
415
+ this.router = router;
416
+
417
+ makeObservable(this, {
418
+ input: observable,
419
+ isPending: observable,
420
+ isSubmitDisabled: computed,
421
+ setInput: action,
422
+ submit: action,
423
+ });
424
+ }
425
+
426
+ get isSubmitDisabled() {
427
+ return !this.input.trim() || this.isPending;
428
+ }
429
+
430
+ setInput(value: string) {
431
+ this.input = value;
432
+ }
433
+
434
+ async submit() {
435
+ runInAction(() => {
436
+ this.isPending = true;
437
+ });
438
+
439
+ try {
440
+ await convex.mutation(api.todos.crud.createTodo, {
441
+ title: this.input.trim()
442
+ });
443
+
444
+ runInAction(() => {
445
+ this.input = "";
446
+ });
447
+
448
+ } finally {
449
+ runInAction(() => {
450
+ this.isPending = false;
451
+ });
452
+ }
453
+ }
454
+ }
455
+ ```
456
+
457
+ Rules:
458
+ - Use `runInAction` when mutating observables after an `await`