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,395 @@
1
+ {%- if cookiecutter.use_jwt %}
2
+ """Authentication routes."""
3
+
4
+ from typing import Annotated
5
+ {%- if cookiecutter.use_postgresql and not cookiecutter.enable_session_management %}
6
+ from uuid import UUID
7
+ {%- endif %}
8
+
9
+ from fastapi import APIRouter, Depends{% if cookiecutter.enable_session_management %}, Request{% endif %}, status
10
+ from fastapi.security import OAuth2PasswordRequestForm
11
+
12
+ from app.api.deps import CurrentUser{% if cookiecutter.enable_session_management %}, SessionSvc{% endif %}, UserSvc
13
+ from app.core.exceptions import AuthenticationError
14
+ from app.core.security import create_access_token, create_refresh_token, verify_token
15
+ from app.schemas.token import RefreshTokenRequest, Token
16
+ from app.schemas.user import UserCreate, UserRead
17
+
18
+ router = APIRouter()
19
+
20
+
21
+ {%- if cookiecutter.use_postgresql %}
22
+
23
+
24
+ @router.post("/login", response_model=Token)
25
+ async def login(
26
+ {%- if cookiecutter.enable_session_management %}
27
+ request: Request,
28
+ {%- endif %}
29
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
30
+ user_service: UserSvc,
31
+ {%- if cookiecutter.enable_session_management %}
32
+ session_service: SessionSvc,
33
+ {%- endif %}
34
+ ):
35
+ """OAuth2 compatible token login.
36
+
37
+ Returns access token and refresh token.
38
+ Raises domain exceptions handled by exception handlers.
39
+ """
40
+ user = await user_service.authenticate(form_data.username, form_data.password)
41
+ access_token = create_access_token(subject=str(user.id))
42
+ refresh_token = create_refresh_token(subject=str(user.id))
43
+ {%- if cookiecutter.enable_session_management %}
44
+
45
+ # Create session to track this login
46
+ await session_service.create_session(
47
+ user_id=user.id,
48
+ refresh_token=refresh_token,
49
+ ip_address=request.client.host if request.client else None,
50
+ user_agent=request.headers.get("User-Agent"),
51
+ )
52
+ {%- endif %}
53
+ return Token(access_token=access_token, refresh_token=refresh_token)
54
+
55
+
56
+ @router.post("/register", response_model=UserRead, status_code=status.HTTP_201_CREATED)
57
+ async def register(
58
+ user_in: UserCreate,
59
+ user_service: UserSvc,
60
+ ):
61
+ """Register a new user.
62
+
63
+ Raises AlreadyExistsError if email is already registered.
64
+ """
65
+ user = await user_service.register(user_in)
66
+ return user
67
+
68
+
69
+ @router.post("/refresh", response_model=Token)
70
+ async def refresh_token(
71
+ {%- if cookiecutter.enable_session_management %}
72
+ request: Request,
73
+ {%- endif %}
74
+ body: RefreshTokenRequest,
75
+ user_service: UserSvc,
76
+ {%- if cookiecutter.enable_session_management %}
77
+ session_service: SessionSvc,
78
+ {%- endif %}
79
+ ):
80
+ """Get new access token using refresh token.
81
+
82
+ Raises AuthenticationError if refresh token is invalid or expired.
83
+ """
84
+ {%- if cookiecutter.enable_session_management %}
85
+
86
+ # Validate refresh token against stored session
87
+ session = await session_service.validate_refresh_token(body.refresh_token)
88
+ if not session:
89
+ raise AuthenticationError(message="Invalid or expired refresh token")
90
+
91
+ user = await user_service.get_by_id(session.user_id)
92
+ {%- else %}
93
+
94
+ payload = verify_token(body.refresh_token)
95
+ if payload is None:
96
+ raise AuthenticationError(message="Invalid or expired refresh token")
97
+
98
+ if payload.get("type") != "refresh":
99
+ raise AuthenticationError(message="Invalid token type")
100
+
101
+ user_id = payload.get("sub")
102
+ if user_id is None:
103
+ raise AuthenticationError(message="Invalid token payload")
104
+
105
+ # Verify user still exists and is active
106
+ user = await user_service.get_by_id(UUID(user_id))
107
+ {%- endif %}
108
+ if not user.is_active:
109
+ raise AuthenticationError(message="User account is disabled")
110
+
111
+ access_token = create_access_token(subject=str(user.id))
112
+ new_refresh_token = create_refresh_token(subject=str(user.id))
113
+ {%- if cookiecutter.enable_session_management %}
114
+
115
+ # Invalidate old session and create new one
116
+ await session_service.logout_by_refresh_token(body.refresh_token)
117
+ await session_service.create_session(
118
+ user_id=user.id,
119
+ refresh_token=new_refresh_token,
120
+ ip_address=request.client.host if request.client else None,
121
+ user_agent=request.headers.get("User-Agent"),
122
+ )
123
+ {%- endif %}
124
+ return Token(access_token=access_token, refresh_token=new_refresh_token)
125
+
126
+ {%- if cookiecutter.enable_session_management %}
127
+
128
+
129
+ @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT)
130
+ async def logout(
131
+ body: RefreshTokenRequest,
132
+ session_service: SessionSvc,
133
+ ):
134
+ """Logout and invalidate the current session.
135
+
136
+ Invalidates the refresh token, preventing further token refresh.
137
+ """
138
+ await session_service.logout_by_refresh_token(body.refresh_token)
139
+ {%- endif %}
140
+
141
+
142
+ @router.get("/me", response_model=UserRead)
143
+ async def get_current_user_info(current_user: CurrentUser):
144
+ """Get current authenticated user information."""
145
+ return current_user
146
+ {%- elif cookiecutter.use_mongodb %}
147
+
148
+
149
+ @router.post("/login", response_model=Token)
150
+ async def login(
151
+ {%- if cookiecutter.enable_session_management %}
152
+ request: Request,
153
+ {%- endif %}
154
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
155
+ user_service: UserSvc,
156
+ {%- if cookiecutter.enable_session_management %}
157
+ session_service: SessionSvc,
158
+ {%- endif %}
159
+ ):
160
+ """OAuth2 compatible token login.
161
+
162
+ Returns access token and refresh token.
163
+ Raises domain exceptions handled by exception handlers.
164
+ """
165
+ user = await user_service.authenticate(form_data.username, form_data.password)
166
+ access_token = create_access_token(subject=str(user.id))
167
+ refresh_token = create_refresh_token(subject=str(user.id))
168
+ {%- if cookiecutter.enable_session_management %}
169
+
170
+ # Create session to track this login
171
+ await session_service.create_session(
172
+ user_id=str(user.id),
173
+ refresh_token=refresh_token,
174
+ ip_address=request.client.host if request.client else None,
175
+ user_agent=request.headers.get("User-Agent"),
176
+ )
177
+ {%- endif %}
178
+ return Token(access_token=access_token, refresh_token=refresh_token)
179
+
180
+
181
+ @router.post("/register", response_model=UserRead, status_code=status.HTTP_201_CREATED)
182
+ async def register(
183
+ user_in: UserCreate,
184
+ user_service: UserSvc,
185
+ ):
186
+ """Register a new user.
187
+
188
+ Raises AlreadyExistsError if email is already registered.
189
+ """
190
+ user = await user_service.register(user_in)
191
+ return user
192
+
193
+
194
+ @router.post("/refresh", response_model=Token)
195
+ async def refresh_token(
196
+ {%- if cookiecutter.enable_session_management %}
197
+ request: Request,
198
+ {%- endif %}
199
+ body: RefreshTokenRequest,
200
+ user_service: UserSvc,
201
+ {%- if cookiecutter.enable_session_management %}
202
+ session_service: SessionSvc,
203
+ {%- endif %}
204
+ ):
205
+ """Get new access token using refresh token.
206
+
207
+ Raises AuthenticationError if refresh token is invalid or expired.
208
+ """
209
+ {%- if cookiecutter.enable_session_management %}
210
+ # Validate refresh token against stored session
211
+ session = await session_service.validate_refresh_token(body.refresh_token)
212
+ if not session:
213
+ raise AuthenticationError(message="Invalid or expired refresh token")
214
+
215
+ user = await user_service.get_by_id(session.user_id)
216
+ {%- else %}
217
+ payload = verify_token(body.refresh_token)
218
+ if payload is None:
219
+ raise AuthenticationError(message="Invalid or expired refresh token")
220
+
221
+ if payload.get("type") != "refresh":
222
+ raise AuthenticationError(message="Invalid token type")
223
+
224
+ user_id = payload.get("sub")
225
+ if user_id is None:
226
+ raise AuthenticationError(message="Invalid token payload")
227
+
228
+ # Verify user still exists and is active
229
+ user = await user_service.get_by_id(user_id)
230
+ {%- endif %}
231
+ if not user.is_active:
232
+ raise AuthenticationError(message="User account is disabled")
233
+
234
+ access_token = create_access_token(subject=str(user.id))
235
+ new_refresh_token = create_refresh_token(subject=str(user.id))
236
+ {%- if cookiecutter.enable_session_management %}
237
+
238
+ # Invalidate old session and create new one
239
+ await session_service.logout_by_refresh_token(body.refresh_token)
240
+ await session_service.create_session(
241
+ user_id=str(user.id),
242
+ refresh_token=new_refresh_token,
243
+ ip_address=request.client.host if request.client else None,
244
+ user_agent=request.headers.get("User-Agent"),
245
+ )
246
+ {%- endif %}
247
+ return Token(access_token=access_token, refresh_token=new_refresh_token)
248
+
249
+ {%- if cookiecutter.enable_session_management %}
250
+
251
+
252
+ @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT)
253
+ async def logout(
254
+ body: RefreshTokenRequest,
255
+ session_service: SessionSvc,
256
+ ):
257
+ """Logout and invalidate the current session.
258
+
259
+ Invalidates the refresh token, preventing further token refresh.
260
+ """
261
+ await session_service.logout_by_refresh_token(body.refresh_token)
262
+ {%- endif %}
263
+
264
+
265
+ @router.get("/me", response_model=UserRead)
266
+ async def get_current_user_info(current_user: CurrentUser):
267
+ """Get current authenticated user information."""
268
+ return current_user
269
+ {%- elif cookiecutter.use_sqlite %}
270
+
271
+
272
+ @router.post("/login", response_model=Token)
273
+ def login(
274
+ {%- if cookiecutter.enable_session_management %}
275
+ request: Request,
276
+ {%- endif %}
277
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
278
+ user_service: UserSvc,
279
+ {%- if cookiecutter.enable_session_management %}
280
+ session_service: SessionSvc,
281
+ {%- endif %}
282
+ ):
283
+ """OAuth2 compatible token login.
284
+
285
+ Returns access token and refresh token.
286
+ Raises domain exceptions handled by exception handlers.
287
+ """
288
+ user = user_service.authenticate(form_data.username, form_data.password)
289
+ access_token = create_access_token(subject=user.id)
290
+ refresh_token = create_refresh_token(subject=user.id)
291
+ {%- if cookiecutter.enable_session_management %}
292
+
293
+ # Create session to track this login
294
+ session_service.create_session(
295
+ user_id=user.id,
296
+ refresh_token=refresh_token,
297
+ ip_address=request.client.host if request.client else None,
298
+ user_agent=request.headers.get("User-Agent"),
299
+ )
300
+ {%- endif %}
301
+ return Token(access_token=access_token, refresh_token=refresh_token)
302
+
303
+
304
+ @router.post("/register", response_model=UserRead, status_code=status.HTTP_201_CREATED)
305
+ def register(
306
+ user_in: UserCreate,
307
+ user_service: UserSvc,
308
+ ):
309
+ """Register a new user.
310
+
311
+ Raises AlreadyExistsError if email is already registered.
312
+ """
313
+ user = user_service.register(user_in)
314
+ return user
315
+
316
+
317
+ @router.post("/refresh", response_model=Token)
318
+ def refresh_token(
319
+ {%- if cookiecutter.enable_session_management %}
320
+ request: Request,
321
+ {%- endif %}
322
+ body: RefreshTokenRequest,
323
+ user_service: UserSvc,
324
+ {%- if cookiecutter.enable_session_management %}
325
+ session_service: SessionSvc,
326
+ {%- endif %}
327
+ ):
328
+ """Get new access token using refresh token.
329
+
330
+ Raises AuthenticationError if refresh token is invalid or expired.
331
+ """
332
+ {%- if cookiecutter.enable_session_management %}
333
+ # Validate refresh token against stored session
334
+ session = session_service.validate_refresh_token(body.refresh_token)
335
+ if not session:
336
+ raise AuthenticationError(message="Invalid or expired refresh token")
337
+
338
+ user = user_service.get_by_id(session.user_id)
339
+ {%- else %}
340
+ payload = verify_token(body.refresh_token)
341
+ if payload is None:
342
+ raise AuthenticationError(message="Invalid or expired refresh token")
343
+
344
+ if payload.get("type") != "refresh":
345
+ raise AuthenticationError(message="Invalid token type")
346
+
347
+ user_id = payload.get("sub")
348
+ if user_id is None:
349
+ raise AuthenticationError(message="Invalid token payload")
350
+
351
+ # Verify user still exists and is active
352
+ user = user_service.get_by_id(user_id)
353
+ {%- endif %}
354
+ if not user.is_active:
355
+ raise AuthenticationError(message="User account is disabled")
356
+
357
+ access_token = create_access_token(subject=user.id)
358
+ new_refresh_token = create_refresh_token(subject=user.id)
359
+ {%- if cookiecutter.enable_session_management %}
360
+
361
+ # Invalidate old session and create new one
362
+ session_service.logout_by_refresh_token(body.refresh_token)
363
+ session_service.create_session(
364
+ user_id=user.id,
365
+ refresh_token=new_refresh_token,
366
+ ip_address=request.client.host if request.client else None,
367
+ user_agent=request.headers.get("User-Agent"),
368
+ )
369
+ {%- endif %}
370
+ return Token(access_token=access_token, refresh_token=new_refresh_token)
371
+
372
+ {%- if cookiecutter.enable_session_management %}
373
+
374
+
375
+ @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT)
376
+ def logout(
377
+ body: RefreshTokenRequest,
378
+ session_service: SessionSvc,
379
+ ):
380
+ """Logout and invalidate the current session.
381
+
382
+ Invalidates the refresh token, preventing further token refresh.
383
+ """
384
+ session_service.logout_by_refresh_token(body.refresh_token)
385
+ {%- endif %}
386
+
387
+
388
+ @router.get("/me", response_model=UserRead)
389
+ def get_current_user_info(current_user: CurrentUser):
390
+ """Get current authenticated user information."""
391
+ return current_user
392
+ {%- endif %}
393
+ {%- else %}
394
+ """Auth routes - not configured."""
395
+ {%- endif %}