fastapi-fullstack 0.1.7__py3-none-any.whl

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 (241) hide show
  1. fastapi_fullstack-0.1.7.dist-info/METADATA +739 -0
  2. fastapi_fullstack-0.1.7.dist-info/RECORD +241 -0
  3. fastapi_fullstack-0.1.7.dist-info/WHEEL +4 -0
  4. fastapi_fullstack-0.1.7.dist-info/entry_points.txt +2 -0
  5. fastapi_fullstack-0.1.7.dist-info/licenses/LICENSE +21 -0
  6. fastapi_gen/__init__.py +3 -0
  7. fastapi_gen/cli.py +442 -0
  8. fastapi_gen/config.py +356 -0
  9. fastapi_gen/generator.py +207 -0
  10. fastapi_gen/prompts.py +874 -0
  11. fastapi_gen/template/VARIABLES.md +276 -0
  12. fastapi_gen/template/cookiecutter.json +93 -0
  13. fastapi_gen/template/hooks/post_gen_project.py +355 -0
  14. fastapi_gen/template/{{cookiecutter.project_slug}}/.env.prod.example +56 -0
  15. fastapi_gen/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +150 -0
  16. fastapi_gen/template/{{cookiecutter.project_slug}}/.gitignore +109 -0
  17. fastapi_gen/template/{{cookiecutter.project_slug}}/AGENTS.md +55 -0
  18. fastapi_gen/template/{{cookiecutter.project_slug}}/CLAUDE.md +99 -0
  19. fastapi_gen/template/{{cookiecutter.project_slug}}/Makefile +315 -0
  20. fastapi_gen/template/{{cookiecutter.project_slug}}/README.md +768 -0
  21. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.dockerignore +60 -0
  22. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.env.example +155 -0
  23. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +32 -0
  24. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/Dockerfile +56 -0
  25. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +76 -0
  26. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +30 -0
  27. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
  28. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic.ini +48 -0
  29. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +3 -0
  30. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py +447 -0
  31. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +23 -0
  32. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +226 -0
  33. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/langchain_assistant.py +226 -0
  34. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/prompts.py +10 -0
  35. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +13 -0
  36. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +17 -0
  37. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +1 -0
  38. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +541 -0
  39. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +98 -0
  40. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +10 -0
  41. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +9 -0
  42. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +87 -0
  43. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +902 -0
  44. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +395 -0
  45. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +498 -0
  46. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +227 -0
  47. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +275 -0
  48. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +205 -0
  49. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +168 -0
  50. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +333 -0
  51. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +477 -0
  52. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +46 -0
  53. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +221 -0
  54. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +14 -0
  55. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +88 -0
  56. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +117 -0
  57. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +75 -0
  58. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +28 -0
  59. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +266 -0
  60. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +5 -0
  61. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +23 -0
  62. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +267 -0
  63. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +153 -0
  64. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +122 -0
  65. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +101 -0
  66. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +99 -0
  67. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +23 -0
  68. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +58 -0
  69. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +271 -0
  70. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +102 -0
  71. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +7 -0
  72. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +41 -0
  73. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +31 -0
  74. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +319 -0
  75. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +96 -0
  76. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +126 -0
  77. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +218 -0
  78. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +244 -0
  79. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +130 -0
  80. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py +334 -0
  81. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +9 -0
  82. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +73 -0
  83. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +49 -0
  84. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +154 -0
  85. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +838 -0
  86. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +222 -0
  87. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +318 -0
  88. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +322 -0
  89. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +358 -0
  90. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +50 -0
  91. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +57 -0
  92. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +192 -0
  93. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +52 -0
  94. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +42 -0
  95. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +31 -0
  96. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +64 -0
  97. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +89 -0
  98. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +38 -0
  99. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +850 -0
  100. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +246 -0
  101. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +333 -0
  102. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +432 -0
  103. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +561 -0
  104. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +5 -0
  105. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +64 -0
  106. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +38 -0
  107. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +25 -0
  108. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +106 -0
  109. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +29 -0
  110. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +92 -0
  111. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +1 -0
  112. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +438 -0
  113. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +180 -0
  114. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
  115. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +1 -0
  116. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +1 -0
  117. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +242 -0
  118. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +151 -0
  119. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +113 -0
  120. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +310 -0
  121. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +253 -0
  122. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +151 -0
  123. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_admin.py +890 -0
  124. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +261 -0
  125. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +183 -0
  126. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +173 -0
  127. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +143 -0
  128. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +118 -0
  129. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +181 -0
  130. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +124 -0
  131. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +363 -0
  132. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +85 -0
  133. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +242 -0
  134. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +31 -0
  135. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +435 -0
  136. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.yml +241 -0
  137. fastapi_gen/template/{{cookiecutter.project_slug}}/docs/adding_features.md +132 -0
  138. fastapi_gen/template/{{cookiecutter.project_slug}}/docs/architecture.md +63 -0
  139. fastapi_gen/template/{{cookiecutter.project_slug}}/docs/patterns.md +161 -0
  140. fastapi_gen/template/{{cookiecutter.project_slug}}/docs/testing.md +120 -0
  141. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.dockerignore +40 -0
  142. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.env.example +12 -0
  143. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.gitignore +45 -0
  144. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +19 -0
  145. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +11 -0
  146. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +44 -0
  147. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/README.md +648 -0
  148. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +49 -0
  149. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +134 -0
  150. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +207 -0
  151. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +73 -0
  152. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +14 -0
  153. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +84 -0
  154. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +84 -0
  155. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +76 -0
  156. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/package.json +69 -0
  157. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +101 -0
  158. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +7 -0
  159. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/layout.tsx +11 -0
  160. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/login/page.tsx +5 -0
  161. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/register/page.tsx +5 -0
  162. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/chat/page.tsx +48 -0
  163. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/dashboard/page.tsx +99 -0
  164. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/layout.tsx +17 -0
  165. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/profile/page.tsx +152 -0
  166. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/auth/callback/page.tsx +113 -0
  167. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/layout.tsx +46 -0
  168. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/page.tsx +73 -0
  169. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +58 -0
  170. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +24 -0
  171. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +39 -0
  172. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +50 -0
  173. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +54 -0
  174. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +26 -0
  175. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +41 -0
  176. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +108 -0
  177. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +73 -0
  178. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +21 -0
  179. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +323 -0
  180. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +22 -0
  181. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +29 -0
  182. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +2 -0
  183. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +120 -0
  184. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +153 -0
  185. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +234 -0
  186. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +72 -0
  187. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +328 -0
  188. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/copy-button.tsx +46 -0
  189. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +11 -0
  190. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/local-conversation-sidebar.tsx +295 -0
  191. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/markdown-content.tsx +167 -0
  192. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +79 -0
  193. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +18 -0
  194. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +79 -0
  195. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +32 -0
  196. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +3 -0
  197. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +97 -0
  198. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +65 -0
  199. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +2 -0
  200. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +82 -0
  201. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +7 -0
  202. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +53 -0
  203. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +105 -0
  204. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +35 -0
  205. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +75 -0
  206. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +56 -0
  207. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +82 -0
  208. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +13 -0
  209. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +21 -0
  210. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +21 -0
  211. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/sheet.tsx +109 -0
  212. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +7 -0
  213. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +97 -0
  214. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +203 -0
  215. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +181 -0
  216. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +165 -0
  217. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +105 -0
  218. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +37 -0
  219. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +90 -0
  220. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +39 -0
  221. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +78 -0
  222. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +44 -0
  223. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +44 -0
  224. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +31 -0
  225. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +72 -0
  226. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +64 -0
  227. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-sidebar-store.ts +17 -0
  228. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +65 -0
  229. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +76 -0
  230. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +9 -0
  231. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/local-chat-store.ts +255 -0
  232. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/sidebar-store.ts +17 -0
  233. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +44 -0
  234. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +27 -0
  235. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +52 -0
  236. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +83 -0
  237. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +49 -0
  238. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +10 -0
  239. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +28 -0
  240. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +36 -0
  241. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +56 -0
@@ -0,0 +1,168 @@
1
+ {%- if cookiecutter.enable_session_management and cookiecutter.use_jwt %}
2
+ """Session management routes."""
3
+
4
+ from fastapi import APIRouter, status
5
+ {%- if cookiecutter.use_postgresql %}
6
+ from uuid import UUID
7
+ {%- endif %}
8
+
9
+ from app.api.deps import CurrentUser, SessionSvc
10
+ from app.schemas.session import LogoutAllResponse, SessionListResponse, SessionRead
11
+
12
+ router = APIRouter()
13
+
14
+
15
+ {%- if cookiecutter.use_postgresql %}
16
+
17
+
18
+ @router.get("", response_model=SessionListResponse)
19
+ async def list_sessions(
20
+ current_user: CurrentUser,
21
+ session_service: SessionSvc,
22
+ ):
23
+ """Get all active sessions for the current user."""
24
+ sessions = await session_service.get_user_sessions(current_user.id)
25
+ return SessionListResponse(
26
+ sessions=[
27
+ SessionRead(
28
+ id=s.id,
29
+ device_name=s.device_name,
30
+ device_type=s.device_type,
31
+ ip_address=s.ip_address,
32
+ is_current=False, # TODO: compare with current session
33
+ created_at=s.created_at,
34
+ last_used_at=s.last_used_at,
35
+ )
36
+ for s in sessions
37
+ ],
38
+ total=len(sessions),
39
+ )
40
+
41
+
42
+ @router.delete("/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
43
+ async def logout_session(
44
+ session_id: UUID,
45
+ current_user: CurrentUser,
46
+ session_service: SessionSvc,
47
+ ):
48
+ """Logout a specific session."""
49
+ await session_service.logout_session(session_id, current_user.id)
50
+
51
+
52
+ @router.delete("", response_model=LogoutAllResponse)
53
+ async def logout_all_sessions(
54
+ current_user: CurrentUser,
55
+ session_service: SessionSvc,
56
+ ):
57
+ """Logout from all sessions (logout from all devices)."""
58
+ count = await session_service.logout_all_sessions(current_user.id)
59
+ return LogoutAllResponse(
60
+ message="Successfully logged out from all sessions",
61
+ sessions_logged_out=count,
62
+ )
63
+
64
+
65
+ {%- elif cookiecutter.use_mongodb %}
66
+
67
+
68
+ @router.get("", response_model=SessionListResponse)
69
+ async def list_sessions(
70
+ current_user: CurrentUser,
71
+ session_service: SessionSvc,
72
+ ):
73
+ """Get all active sessions for the current user."""
74
+ sessions = await session_service.get_user_sessions(str(current_user.id))
75
+ return SessionListResponse(
76
+ sessions=[
77
+ SessionRead(
78
+ id=str(s.id),
79
+ device_name=s.device_name,
80
+ device_type=s.device_type,
81
+ ip_address=s.ip_address,
82
+ is_current=False,
83
+ created_at=s.created_at,
84
+ last_used_at=s.last_used_at,
85
+ )
86
+ for s in sessions
87
+ ],
88
+ total=len(sessions),
89
+ )
90
+
91
+
92
+ @router.delete("/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
93
+ async def logout_session(
94
+ session_id: str,
95
+ current_user: CurrentUser,
96
+ session_service: SessionSvc,
97
+ ):
98
+ """Logout a specific session."""
99
+ await session_service.logout_session(session_id, str(current_user.id))
100
+
101
+
102
+ @router.delete("", response_model=LogoutAllResponse)
103
+ async def logout_all_sessions(
104
+ current_user: CurrentUser,
105
+ session_service: SessionSvc,
106
+ ):
107
+ """Logout from all sessions (logout from all devices)."""
108
+ count = await session_service.logout_all_sessions(str(current_user.id))
109
+ return LogoutAllResponse(
110
+ message="Successfully logged out from all sessions",
111
+ sessions_logged_out=count,
112
+ )
113
+
114
+
115
+ {%- elif cookiecutter.use_sqlite %}
116
+
117
+
118
+ @router.get("", response_model=SessionListResponse)
119
+ def list_sessions(
120
+ current_user: CurrentUser,
121
+ session_service: SessionSvc,
122
+ ):
123
+ """Get all active sessions for the current user."""
124
+ sessions = session_service.get_user_sessions(current_user.id)
125
+ return SessionListResponse(
126
+ sessions=[
127
+ SessionRead(
128
+ id=s.id,
129
+ device_name=s.device_name,
130
+ device_type=s.device_type,
131
+ ip_address=s.ip_address,
132
+ is_current=False,
133
+ created_at=s.created_at,
134
+ last_used_at=s.last_used_at,
135
+ )
136
+ for s in sessions
137
+ ],
138
+ total=len(sessions),
139
+ )
140
+
141
+
142
+ @router.delete("/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
143
+ def logout_session(
144
+ session_id: str,
145
+ current_user: CurrentUser,
146
+ session_service: SessionSvc,
147
+ ):
148
+ """Logout a specific session."""
149
+ session_service.logout_session(session_id, current_user.id)
150
+
151
+
152
+ @router.delete("", response_model=LogoutAllResponse)
153
+ def logout_all_sessions(
154
+ current_user: CurrentUser,
155
+ session_service: SessionSvc,
156
+ ):
157
+ """Logout from all sessions (logout from all devices)."""
158
+ count = session_service.logout_all_sessions(current_user.id)
159
+ return LogoutAllResponse(
160
+ message="Successfully logged out from all sessions",
161
+ sessions_logged_out=count,
162
+ )
163
+
164
+
165
+ {%- endif %}
166
+ {%- else %}
167
+ """Session routes - not configured."""
168
+ {%- endif %}
@@ -0,0 +1,333 @@
1
+ {%- if cookiecutter.use_jwt %}
2
+ # ruff: noqa: I001 - Imports structured for Jinja2 template conditionals
3
+ """User management routes."""
4
+
5
+ from typing import Annotated
6
+ {%- if cookiecutter.use_postgresql %}
7
+
8
+ from uuid import UUID
9
+ {%- endif %}
10
+
11
+ from fastapi import APIRouter, Depends, status
12
+ {%- if cookiecutter.enable_pagination %}
13
+ from fastapi_pagination import Page
14
+ from fastapi_pagination.ext.sqlalchemy import paginate
15
+ from sqlalchemy import select
16
+ {%- endif %}
17
+
18
+ from app.api.deps import (
19
+ DBSession,
20
+ RoleChecker,
21
+ UserSvc,
22
+ get_current_user,
23
+ )
24
+ from app.db.models.user import User, UserRole
25
+ from app.schemas.user import UserRead, UserUpdate
26
+
27
+ router = APIRouter()
28
+
29
+
30
+ {%- if cookiecutter.use_postgresql %}
31
+
32
+
33
+ @router.get("/me", response_model=UserRead)
34
+ async def read_current_user(
35
+ current_user: Annotated[User, Depends(get_current_user)],
36
+ ):
37
+ """Get current user.
38
+
39
+ Returns the authenticated user's profile including their role.
40
+ """
41
+ return current_user
42
+
43
+
44
+ @router.patch("/me", response_model=UserRead)
45
+ async def update_current_user(
46
+ user_in: UserUpdate,
47
+ current_user: Annotated[User, Depends(get_current_user)],
48
+ user_service: UserSvc,
49
+ ):
50
+ """Update current user.
51
+
52
+ Users can update their own profile (email, full_name).
53
+ Role changes require admin privileges.
54
+ """
55
+ # Prevent non-admin users from changing their own role
56
+ if user_in.role is not None and not current_user.has_role(UserRole.ADMIN):
57
+ user_in.role = None
58
+ user = await user_service.update(current_user.id, user_in)
59
+ return user
60
+
61
+
62
+ {%- if cookiecutter.enable_pagination %}
63
+
64
+
65
+ @router.get("", response_model=Page[UserRead])
66
+ async def read_users(
67
+ db: DBSession,
68
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
69
+ ):
70
+ """Get all users (admin only)."""
71
+ return await paginate(db, select(User))
72
+
73
+
74
+ {%- else %}
75
+
76
+
77
+ @router.get("", response_model=list[UserRead])
78
+ async def read_users(
79
+ user_service: UserSvc,
80
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
81
+ skip: int = 0,
82
+ limit: int = 100,
83
+ ):
84
+ """Get all users (admin only)."""
85
+ users = await user_service.get_multi(skip=skip, limit=limit)
86
+ return users
87
+
88
+
89
+ {%- endif %}
90
+
91
+
92
+ @router.get("/{user_id}", response_model=UserRead)
93
+ async def read_user(
94
+ user_id: UUID,
95
+ user_service: UserSvc,
96
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
97
+ ):
98
+ """Get user by ID (admin only).
99
+
100
+ Raises NotFoundError if user does not exist.
101
+ """
102
+ user = await user_service.get_by_id(user_id)
103
+ return user
104
+
105
+
106
+ @router.patch("/{user_id}", response_model=UserRead)
107
+ async def update_user_by_id(
108
+ user_id: UUID,
109
+ user_in: UserUpdate,
110
+ user_service: UserSvc,
111
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
112
+ ):
113
+ """Update user by ID (admin only).
114
+
115
+ Admins can update any user including their role.
116
+
117
+ Raises NotFoundError if user does not exist.
118
+ """
119
+ user = await user_service.update(user_id, user_in)
120
+ return user
121
+
122
+
123
+ @router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
124
+ async def delete_user_by_id(
125
+ user_id: UUID,
126
+ user_service: UserSvc,
127
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
128
+ ):
129
+ """Delete user by ID (admin only).
130
+
131
+ Raises NotFoundError if user does not exist.
132
+ """
133
+ await user_service.delete(user_id)
134
+
135
+
136
+ {%- elif cookiecutter.use_mongodb %}
137
+
138
+
139
+ @router.get("/me", response_model=UserRead)
140
+ async def read_current_user(
141
+ current_user: Annotated[User, Depends(get_current_user)],
142
+ ):
143
+ """Get current user.
144
+
145
+ Returns the authenticated user's profile including their role.
146
+ """
147
+ return current_user
148
+
149
+
150
+ @router.patch("/me", response_model=UserRead)
151
+ async def update_current_user(
152
+ user_in: UserUpdate,
153
+ current_user: Annotated[User, Depends(get_current_user)],
154
+ user_service: UserSvc,
155
+ ):
156
+ """Update current user.
157
+
158
+ Users can update their own profile (email, full_name).
159
+ Role changes require admin privileges.
160
+ """
161
+ # Prevent non-admin users from changing their own role
162
+ if user_in.role is not None and not current_user.has_role(UserRole.ADMIN):
163
+ user_in.role = None
164
+ user = await user_service.update(str(current_user.id), user_in)
165
+ return user
166
+
167
+
168
+ @router.get("", response_model=list[UserRead])
169
+ async def read_users(
170
+ user_service: UserSvc,
171
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
172
+ skip: int = 0,
173
+ limit: int = 100,
174
+ ):
175
+ """Get all users (admin only)."""
176
+ users = await user_service.get_multi(skip=skip, limit=limit)
177
+ return users
178
+
179
+
180
+ @router.get("/{user_id}", response_model=UserRead)
181
+ async def read_user(
182
+ user_id: str,
183
+ user_service: UserSvc,
184
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
185
+ ):
186
+ """Get user by ID (admin only).
187
+
188
+ Raises NotFoundError if user does not exist.
189
+ """
190
+ user = await user_service.get_by_id(user_id)
191
+ return user
192
+
193
+
194
+ @router.patch("/{user_id}", response_model=UserRead)
195
+ async def update_user_by_id(
196
+ user_id: str,
197
+ user_in: UserUpdate,
198
+ user_service: UserSvc,
199
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
200
+ ):
201
+ """Update user by ID (admin only).
202
+
203
+ Admins can update any user including their role.
204
+
205
+ Raises NotFoundError if user does not exist.
206
+ """
207
+ user = await user_service.update(user_id, user_in)
208
+ return user
209
+
210
+
211
+ @router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
212
+ async def delete_user_by_id(
213
+ user_id: str,
214
+ user_service: UserSvc,
215
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
216
+ ):
217
+ """Delete user by ID (admin only).
218
+
219
+ Raises NotFoundError if user does not exist.
220
+ """
221
+ await user_service.delete(user_id)
222
+
223
+
224
+ {%- elif cookiecutter.use_sqlite %}
225
+
226
+
227
+ @router.get("/me", response_model=UserRead)
228
+ def read_current_user(
229
+ current_user: Annotated[User, Depends(get_current_user)],
230
+ ):
231
+ """Get current user.
232
+
233
+ Returns the authenticated user's profile including their role.
234
+ """
235
+ return current_user
236
+
237
+
238
+ @router.patch("/me", response_model=UserRead)
239
+ def update_current_user(
240
+ user_in: UserUpdate,
241
+ current_user: Annotated[User, Depends(get_current_user)],
242
+ user_service: UserSvc,
243
+ ):
244
+ """Update current user.
245
+
246
+ Users can update their own profile (email, full_name).
247
+ Role changes require admin privileges.
248
+ """
249
+ # Prevent non-admin users from changing their own role
250
+ if user_in.role is not None and not current_user.has_role(UserRole.ADMIN):
251
+ user_in.role = None
252
+ user = user_service.update(current_user.id, user_in)
253
+ return user
254
+
255
+
256
+ {%- if cookiecutter.enable_pagination %}
257
+
258
+
259
+ @router.get("", response_model=Page[UserRead])
260
+ def read_users(
261
+ db: DBSession,
262
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
263
+ ):
264
+ """Get all users (admin only)."""
265
+ return paginate(db, select(User))
266
+
267
+
268
+ {%- else %}
269
+
270
+
271
+ @router.get("", response_model=list[UserRead])
272
+ def read_users(
273
+ user_service: UserSvc,
274
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
275
+ skip: int = 0,
276
+ limit: int = 100,
277
+ ):
278
+ """Get all users (admin only)."""
279
+ users = user_service.get_multi(skip=skip, limit=limit)
280
+ return users
281
+
282
+
283
+ {%- endif %}
284
+
285
+
286
+ @router.get("/{user_id}", response_model=UserRead)
287
+ def read_user(
288
+ user_id: str,
289
+ user_service: UserSvc,
290
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
291
+ ):
292
+ """Get user by ID (admin only).
293
+
294
+ Raises NotFoundError if user does not exist.
295
+ """
296
+ user = user_service.get_by_id(user_id)
297
+ return user
298
+
299
+
300
+ @router.patch("/{user_id}", response_model=UserRead)
301
+ def update_user_by_id(
302
+ user_id: str,
303
+ user_in: UserUpdate,
304
+ user_service: UserSvc,
305
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
306
+ ):
307
+ """Update user by ID (admin only).
308
+
309
+ Admins can update any user including their role.
310
+
311
+ Raises NotFoundError if user does not exist.
312
+ """
313
+ user = user_service.update(user_id, user_in)
314
+ return user
315
+
316
+
317
+ @router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
318
+ def delete_user_by_id(
319
+ user_id: str,
320
+ user_service: UserSvc,
321
+ current_user: Annotated[User, Depends(RoleChecker(UserRole.ADMIN))],
322
+ ):
323
+ """Delete user by ID (admin only).
324
+
325
+ Raises NotFoundError if user does not exist.
326
+ """
327
+ user_service.delete(user_id)
328
+
329
+
330
+ {%- endif %}
331
+ {%- else %}
332
+ """User routes - not configured."""
333
+ {%- endif %}