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,432 @@
1
+ {%- if cookiecutter.use_jwt and cookiecutter.use_postgresql %}
2
+ """User service (PostgreSQL async).
3
+
4
+ Contains business logic for user operations. Uses UserRepository for database access.
5
+ """
6
+
7
+ from uuid import UUID
8
+
9
+ from sqlalchemy.ext.asyncio import AsyncSession
10
+
11
+ from app.core.exceptions import AlreadyExistsError, AuthenticationError, NotFoundError
12
+ from app.core.security import get_password_hash, verify_password
13
+ from app.db.models.user import User
14
+ from app.repositories import user_repo
15
+ from app.schemas.user import UserCreate, UserUpdate
16
+
17
+
18
+ class UserService:
19
+ """Service for user-related business logic."""
20
+
21
+ def __init__(self, db: AsyncSession):
22
+ self.db = db
23
+
24
+ async def get_by_id(self, user_id: UUID) -> User:
25
+ """Get user by ID.
26
+
27
+ Raises:
28
+ NotFoundError: If user does not exist.
29
+ """
30
+ user = await user_repo.get_by_id(self.db, user_id)
31
+ if not user:
32
+ raise NotFoundError(
33
+ message="User not found",
34
+ details={"user_id": user_id},
35
+ )
36
+ return user
37
+
38
+ async def get_by_email(self, email: str) -> User | None:
39
+ """Get user by email. Returns None if not found."""
40
+ return await user_repo.get_by_email(self.db, email)
41
+
42
+ async def get_multi(
43
+ self,
44
+ *,
45
+ skip: int = 0,
46
+ limit: int = 100,
47
+ ) -> list[User]:
48
+ """Get multiple users with pagination."""
49
+ return await user_repo.get_multi(self.db, skip=skip, limit=limit)
50
+
51
+ async def register(self, user_in: UserCreate) -> User:
52
+ """Register a new user.
53
+
54
+ Raises:
55
+ AlreadyExistsError: If email is already registered.
56
+ """
57
+ existing = await user_repo.get_by_email(self.db, user_in.email)
58
+ if existing:
59
+ raise AlreadyExistsError(
60
+ message="Email already registered",
61
+ details={"email": user_in.email},
62
+ )
63
+
64
+ hashed_password = get_password_hash(user_in.password)
65
+ return await user_repo.create(
66
+ self.db,
67
+ email=user_in.email,
68
+ hashed_password=hashed_password,
69
+ full_name=user_in.full_name,
70
+ role=user_in.role.value,
71
+ )
72
+
73
+ async def authenticate(self, email: str, password: str) -> User:
74
+ """Authenticate user by email and password.
75
+
76
+ Raises:
77
+ AuthenticationError: If credentials are invalid or user is inactive.
78
+ """
79
+ user = await user_repo.get_by_email(self.db, email)
80
+ if not user or not verify_password(password, user.hashed_password):
81
+ raise AuthenticationError(message="Invalid email or password")
82
+ if not user.is_active:
83
+ raise AuthenticationError(message="User account is disabled")
84
+ return user
85
+
86
+ async def update(self, user_id: UUID, user_in: UserUpdate) -> User:
87
+ """Update user.
88
+
89
+ Raises:
90
+ NotFoundError: If user does not exist.
91
+ """
92
+ user = await self.get_by_id(user_id)
93
+
94
+ update_data = user_in.model_dump(exclude_unset=True)
95
+ if "password" in update_data:
96
+ update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
97
+
98
+ return await user_repo.update(self.db, db_user=user, update_data=update_data)
99
+
100
+ async def delete(self, user_id: UUID) -> User:
101
+ """Delete user.
102
+
103
+ Raises:
104
+ NotFoundError: If user does not exist.
105
+ """
106
+ user = await user_repo.delete(self.db, user_id)
107
+ if not user:
108
+ raise NotFoundError(
109
+ message="User not found",
110
+ details={"user_id": str(user_id)},
111
+ )
112
+ return user
113
+
114
+ {%- if cookiecutter.enable_oauth %}
115
+
116
+ async def get_by_oauth(self, provider: str, oauth_id: str) -> User | None:
117
+ """Get user by OAuth provider and ID."""
118
+ return await user_repo.get_by_oauth(self.db, provider, oauth_id)
119
+
120
+ async def link_oauth(self, user_id: UUID, provider: str, oauth_id: str) -> User:
121
+ """Link OAuth account to existing user."""
122
+ user = await self.get_by_id(user_id)
123
+ return await user_repo.update(
124
+ self.db,
125
+ db_user=user,
126
+ update_data={"oauth_provider": provider, "oauth_id": oauth_id},
127
+ )
128
+
129
+ async def create_oauth_user(
130
+ self,
131
+ email: str,
132
+ full_name: str | None,
133
+ oauth_provider: str,
134
+ oauth_id: str,
135
+ ) -> User:
136
+ """Create a new user from OAuth data."""
137
+ return await user_repo.create(
138
+ self.db,
139
+ email=email,
140
+ hashed_password=None,
141
+ full_name=full_name,
142
+ oauth_provider=oauth_provider,
143
+ oauth_id=oauth_id,
144
+ )
145
+ {%- endif %}
146
+
147
+
148
+ {%- elif cookiecutter.use_jwt and cookiecutter.use_sqlite %}
149
+ """User service (SQLite sync).
150
+
151
+ Contains business logic for user operations. Uses UserRepository for database access.
152
+ """
153
+
154
+ from sqlalchemy.orm import Session
155
+
156
+ from app.core.exceptions import AlreadyExistsError, AuthenticationError, NotFoundError
157
+ from app.core.security import get_password_hash, verify_password
158
+ from app.db.models.user import User
159
+ from app.repositories import user_repo
160
+ from app.schemas.user import UserCreate, UserUpdate
161
+
162
+
163
+ class UserService:
164
+ """Service for user-related business logic."""
165
+
166
+ def __init__(self, db: Session):
167
+ self.db = db
168
+
169
+ def get_by_id(self, user_id: str) -> User:
170
+ """Get user by ID.
171
+
172
+ Raises:
173
+ NotFoundError: If user does not exist.
174
+ """
175
+ user = user_repo.get_by_id(self.db, user_id)
176
+ if not user:
177
+ raise NotFoundError(
178
+ message="User not found",
179
+ details={"user_id": user_id},
180
+ )
181
+ return user
182
+
183
+ def get_by_email(self, email: str) -> User | None:
184
+ """Get user by email. Returns None if not found."""
185
+ return user_repo.get_by_email(self.db, email)
186
+
187
+ def get_multi(
188
+ self,
189
+ *,
190
+ skip: int = 0,
191
+ limit: int = 100,
192
+ ) -> list[User]:
193
+ """Get multiple users with pagination."""
194
+ return user_repo.get_multi(self.db, skip=skip, limit=limit)
195
+
196
+ def register(self, user_in: UserCreate) -> User:
197
+ """Register a new user.
198
+
199
+ Raises:
200
+ AlreadyExistsError: If email is already registered.
201
+ """
202
+ existing = user_repo.get_by_email(self.db, user_in.email)
203
+ if existing:
204
+ raise AlreadyExistsError(
205
+ message="Email already registered",
206
+ details={"email": user_in.email},
207
+ )
208
+
209
+ hashed_password = get_password_hash(user_in.password)
210
+ return user_repo.create(
211
+ self.db,
212
+ email=user_in.email,
213
+ hashed_password=hashed_password,
214
+ full_name=user_in.full_name,
215
+ role=user_in.role.value,
216
+ )
217
+
218
+ def authenticate(self, email: str, password: str) -> User:
219
+ """Authenticate user by email and password.
220
+
221
+ Raises:
222
+ AuthenticationError: If credentials are invalid or user is inactive.
223
+ """
224
+ user = user_repo.get_by_email(self.db, email)
225
+ if not user or not verify_password(password, user.hashed_password):
226
+ raise AuthenticationError(message="Invalid email or password")
227
+ if not user.is_active:
228
+ raise AuthenticationError(message="User account is disabled")
229
+ return user
230
+
231
+ def update(self, user_id: str, user_in: UserUpdate) -> User:
232
+ """Update user.
233
+
234
+ Raises:
235
+ NotFoundError: If user does not exist.
236
+ """
237
+ user = self.get_by_id(user_id)
238
+
239
+ update_data = user_in.model_dump(exclude_unset=True)
240
+ if "password" in update_data:
241
+ update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
242
+
243
+ return user_repo.update(self.db, db_user=user, update_data=update_data)
244
+
245
+ def delete(self, user_id: str) -> User:
246
+ """Delete user.
247
+
248
+ Raises:
249
+ NotFoundError: If user does not exist.
250
+ """
251
+ user = user_repo.delete(self.db, user_id)
252
+ if not user:
253
+ raise NotFoundError(
254
+ message="User not found",
255
+ details={"user_id": user_id},
256
+ )
257
+ return user
258
+
259
+ {%- if cookiecutter.enable_oauth %}
260
+
261
+ def get_by_oauth(self, provider: str, oauth_id: str) -> User | None:
262
+ """Get user by OAuth provider and ID."""
263
+ return user_repo.get_by_oauth(self.db, provider, oauth_id)
264
+
265
+ def link_oauth(self, user_id: str, provider: str, oauth_id: str) -> User:
266
+ """Link OAuth account to existing user."""
267
+ user = self.get_by_id(user_id)
268
+ return user_repo.update(
269
+ self.db,
270
+ db_user=user,
271
+ update_data={"oauth_provider": provider, "oauth_id": oauth_id},
272
+ )
273
+
274
+ def create_oauth_user(
275
+ self,
276
+ email: str,
277
+ full_name: str | None,
278
+ oauth_provider: str,
279
+ oauth_id: str,
280
+ ) -> User:
281
+ """Create a new user from OAuth data."""
282
+ return user_repo.create(
283
+ self.db,
284
+ email=email,
285
+ hashed_password=None,
286
+ full_name=full_name,
287
+ oauth_provider=oauth_provider,
288
+ oauth_id=oauth_id,
289
+ )
290
+ {%- endif %}
291
+
292
+
293
+ {%- elif cookiecutter.use_jwt and cookiecutter.use_mongodb %}
294
+ """User service (MongoDB).
295
+
296
+ Contains business logic for user operations. Uses UserRepository for database access.
297
+ """
298
+
299
+ from app.core.exceptions import AlreadyExistsError, AuthenticationError, NotFoundError
300
+ from app.core.security import get_password_hash, verify_password
301
+ from app.db.models.user import User
302
+ from app.repositories import user_repo
303
+ from app.schemas.user import UserCreate, UserUpdate
304
+
305
+
306
+ class UserService:
307
+ """Service for user-related business logic."""
308
+
309
+ async def get_by_id(self, user_id: str) -> User:
310
+ """Get user by ID.
311
+
312
+ Raises:
313
+ NotFoundError: If user does not exist.
314
+ """
315
+ user = await user_repo.get_by_id(user_id)
316
+ if not user:
317
+ raise NotFoundError(
318
+ message="User not found",
319
+ details={"user_id": user_id},
320
+ )
321
+ return user
322
+
323
+ async def get_by_email(self, email: str) -> User | None:
324
+ """Get user by email. Returns None if not found."""
325
+ return await user_repo.get_by_email(email)
326
+
327
+ async def get_multi(
328
+ self,
329
+ *,
330
+ skip: int = 0,
331
+ limit: int = 100,
332
+ ) -> list[User]:
333
+ """Get multiple users with pagination."""
334
+ return await user_repo.get_multi(skip=skip, limit=limit)
335
+
336
+ async def register(self, user_in: UserCreate) -> User:
337
+ """Register a new user.
338
+
339
+ Raises:
340
+ AlreadyExistsError: If email is already registered.
341
+ """
342
+ existing = await user_repo.get_by_email(user_in.email)
343
+ if existing:
344
+ raise AlreadyExistsError(
345
+ message="Email already registered",
346
+ details={"email": user_in.email},
347
+ )
348
+
349
+ hashed_password = get_password_hash(user_in.password)
350
+ return await user_repo.create(
351
+ email=user_in.email,
352
+ hashed_password=hashed_password,
353
+ full_name=user_in.full_name,
354
+ role=user_in.role.value,
355
+ )
356
+
357
+ async def authenticate(self, email: str, password: str) -> User:
358
+ """Authenticate user by email and password.
359
+
360
+ Raises:
361
+ AuthenticationError: If credentials are invalid or user is inactive.
362
+ """
363
+ user = await user_repo.get_by_email(email)
364
+ if not user or not verify_password(password, user.hashed_password):
365
+ raise AuthenticationError(message="Invalid email or password")
366
+ if not user.is_active:
367
+ raise AuthenticationError(message="User account is disabled")
368
+ return user
369
+
370
+ async def update(self, user_id: str, user_in: UserUpdate) -> User:
371
+ """Update user.
372
+
373
+ Raises:
374
+ NotFoundError: If user does not exist.
375
+ """
376
+ user = await self.get_by_id(user_id)
377
+
378
+ update_data = user_in.model_dump(exclude_unset=True)
379
+ if "password" in update_data:
380
+ update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
381
+
382
+ return await user_repo.update(db_user=user, update_data=update_data)
383
+
384
+ async def delete(self, user_id: str) -> User:
385
+ """Delete user.
386
+
387
+ Raises:
388
+ NotFoundError: If user does not exist.
389
+ """
390
+ user = await user_repo.delete(user_id)
391
+ if not user:
392
+ raise NotFoundError(
393
+ message="User not found",
394
+ details={"user_id": user_id},
395
+ )
396
+ return user
397
+
398
+ {%- if cookiecutter.enable_oauth %}
399
+
400
+ async def get_by_oauth(self, provider: str, oauth_id: str) -> User | None:
401
+ """Get user by OAuth provider and ID."""
402
+ return await user_repo.get_by_oauth(provider, oauth_id)
403
+
404
+ async def link_oauth(self, user_id: str, provider: str, oauth_id: str) -> User:
405
+ """Link OAuth account to existing user."""
406
+ user = await self.get_by_id(user_id)
407
+ return await user_repo.update(
408
+ db_user=user,
409
+ update_data={"oauth_provider": provider, "oauth_id": oauth_id},
410
+ )
411
+
412
+ async def create_oauth_user(
413
+ self,
414
+ email: str,
415
+ full_name: str | None,
416
+ oauth_provider: str,
417
+ oauth_id: str,
418
+ ) -> User:
419
+ """Create a new user from OAuth data."""
420
+ return await user_repo.create(
421
+ email=email,
422
+ hashed_password=None,
423
+ full_name=full_name,
424
+ oauth_provider=oauth_provider,
425
+ oauth_id=oauth_id,
426
+ )
427
+ {%- endif %}
428
+
429
+
430
+ {%- else %}
431
+ """User service - not configured."""
432
+ {%- endif %}