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,363 @@
1
+ {%- if cookiecutter.use_jwt %}
2
+ """Tests for service layer."""
3
+ {%- if cookiecutter.use_postgresql or cookiecutter.use_mongodb %}
4
+
5
+ from unittest.mock import AsyncMock, patch
6
+ {%- elif cookiecutter.use_sqlite %}
7
+
8
+ from unittest.mock import MagicMock, patch
9
+ {%- endif %}
10
+ from uuid import uuid4
11
+
12
+ import pytest
13
+
14
+ from app.core.exceptions import AlreadyExistsError, AuthenticationError, NotFoundError
15
+ from app.schemas.user import UserCreate, UserUpdate
16
+ from app.services.user import UserService
17
+
18
+
19
+ class MockUser:
20
+ """Mock user for testing."""
21
+
22
+ def __init__(
23
+ self,
24
+ id=None,
25
+ email="test@example.com",
26
+ full_name="Test User",
27
+ hashed_password="$2b$12$hashedpassword",
28
+ is_active=True,
29
+ is_superuser=False,
30
+ ):
31
+ {%- if cookiecutter.use_postgresql %}
32
+ self.id = id or uuid4()
33
+ {%- else %}
34
+ self.id = id or str(uuid4())
35
+ {%- endif %}
36
+ self.email = email
37
+ self.full_name = full_name
38
+ self.hashed_password = hashed_password
39
+ self.is_active = is_active
40
+ self.is_superuser = is_superuser
41
+
42
+
43
+ {%- if cookiecutter.use_postgresql %}
44
+
45
+
46
+ class TestUserServicePostgresql:
47
+ """Tests for UserService with PostgreSQL."""
48
+
49
+ @pytest.fixture
50
+ def mock_db(self) -> AsyncMock:
51
+ """Create mock database session."""
52
+ return AsyncMock()
53
+
54
+ @pytest.fixture
55
+ def user_service(self, mock_db: AsyncMock) -> UserService:
56
+ """Create UserService instance with mock db."""
57
+ return UserService(mock_db)
58
+
59
+ @pytest.fixture
60
+ def mock_user(self) -> MockUser:
61
+ """Create a mock user."""
62
+ return MockUser()
63
+
64
+ @pytest.mark.anyio
65
+ async def test_get_by_id_success(self, user_service: UserService, mock_user: MockUser):
66
+ """Test getting user by ID successfully."""
67
+ with patch("app.services.user.user_repo") as mock_repo:
68
+ mock_repo.get_by_id = AsyncMock(return_value=mock_user)
69
+
70
+ result = await user_service.get_by_id(mock_user.id)
71
+
72
+ assert result == mock_user
73
+ mock_repo.get_by_id.assert_called_once()
74
+
75
+ @pytest.mark.anyio
76
+ async def test_get_by_id_not_found(self, user_service: UserService):
77
+ """Test getting non-existent user raises NotFoundError."""
78
+ with patch("app.services.user.user_repo") as mock_repo:
79
+ mock_repo.get_by_id = AsyncMock(return_value=None)
80
+
81
+ with pytest.raises(NotFoundError):
82
+ await user_service.get_by_id(uuid4())
83
+
84
+ @pytest.mark.anyio
85
+ async def test_get_by_email(self, user_service: UserService, mock_user: MockUser):
86
+ """Test getting user by email."""
87
+ with patch("app.services.user.user_repo") as mock_repo:
88
+ mock_repo.get_by_email = AsyncMock(return_value=mock_user)
89
+
90
+ result = await user_service.get_by_email("test@example.com")
91
+
92
+ assert result == mock_user
93
+
94
+ @pytest.mark.anyio
95
+ async def test_get_multi(self, user_service: UserService, mock_user: MockUser):
96
+ """Test getting multiple users."""
97
+ with patch("app.services.user.user_repo") as mock_repo:
98
+ mock_repo.get_multi = AsyncMock(return_value=[mock_user])
99
+
100
+ result = await user_service.get_multi(skip=0, limit=10)
101
+
102
+ assert len(result) == 1
103
+ assert result[0] == mock_user
104
+
105
+ @pytest.mark.anyio
106
+ async def test_register_success(self, user_service: UserService, mock_user: MockUser):
107
+ """Test registering a new user."""
108
+ with patch("app.services.user.user_repo") as mock_repo:
109
+ mock_repo.get_by_email = AsyncMock(return_value=None)
110
+ mock_repo.create = AsyncMock(return_value=mock_user)
111
+
112
+ user_in = UserCreate(
113
+ email="new@example.com",
114
+ password="password123",
115
+ full_name="New User",
116
+ )
117
+ result = await user_service.register(user_in)
118
+
119
+ assert result == mock_user
120
+ mock_repo.create.assert_called_once()
121
+
122
+ @pytest.mark.anyio
123
+ async def test_register_duplicate_email(self, user_service: UserService, mock_user: MockUser):
124
+ """Test registering with existing email raises AlreadyExistsError."""
125
+ with patch("app.services.user.user_repo") as mock_repo:
126
+ mock_repo.get_by_email = AsyncMock(return_value=mock_user)
127
+
128
+ user_in = UserCreate(
129
+ email="existing@example.com",
130
+ password="password123",
131
+ full_name="Test",
132
+ )
133
+
134
+ with pytest.raises(AlreadyExistsError):
135
+ await user_service.register(user_in)
136
+
137
+ @pytest.mark.anyio
138
+ async def test_authenticate_success(self, user_service: UserService, mock_user: MockUser):
139
+ """Test successful authentication."""
140
+ with (
141
+ patch("app.services.user.user_repo") as mock_repo,
142
+ patch("app.services.user.verify_password", return_value=True),
143
+ ):
144
+ mock_repo.get_by_email = AsyncMock(return_value=mock_user)
145
+
146
+ result = await user_service.authenticate("test@example.com", "password123")
147
+
148
+ assert result == mock_user
149
+
150
+ @pytest.mark.anyio
151
+ async def test_authenticate_invalid_password(self, user_service: UserService, mock_user: MockUser):
152
+ """Test authentication with wrong password."""
153
+ with (
154
+ patch("app.services.user.user_repo") as mock_repo,
155
+ patch("app.services.user.verify_password", return_value=False),
156
+ ):
157
+ mock_repo.get_by_email = AsyncMock(return_value=mock_user)
158
+
159
+ with pytest.raises(AuthenticationError):
160
+ await user_service.authenticate("test@example.com", "wrongpassword")
161
+
162
+ @pytest.mark.anyio
163
+ async def test_authenticate_user_not_found(self, user_service: UserService):
164
+ """Test authentication with non-existent user."""
165
+ with patch("app.services.user.user_repo") as mock_repo:
166
+ mock_repo.get_by_email = AsyncMock(return_value=None)
167
+
168
+ with pytest.raises(AuthenticationError):
169
+ await user_service.authenticate("unknown@example.com", "password")
170
+
171
+ @pytest.mark.anyio
172
+ async def test_authenticate_inactive_user(self, user_service: UserService):
173
+ """Test authentication with inactive user."""
174
+ inactive_user = MockUser(is_active=False)
175
+ with (
176
+ patch("app.services.user.user_repo") as mock_repo,
177
+ patch("app.services.user.verify_password", return_value=True),
178
+ ):
179
+ mock_repo.get_by_email = AsyncMock(return_value=inactive_user)
180
+
181
+ with pytest.raises(AuthenticationError):
182
+ await user_service.authenticate("test@example.com", "password")
183
+
184
+ @pytest.mark.anyio
185
+ async def test_update_success(self, user_service: UserService, mock_user: MockUser):
186
+ """Test updating user."""
187
+ with patch("app.services.user.user_repo") as mock_repo:
188
+ mock_repo.get_by_id = AsyncMock(return_value=mock_user)
189
+ mock_repo.update = AsyncMock(return_value=mock_user)
190
+
191
+ user_update = UserUpdate(full_name="Updated Name")
192
+ result = await user_service.update(mock_user.id, user_update)
193
+
194
+ assert result == mock_user
195
+
196
+ @pytest.mark.anyio
197
+ async def test_update_with_password(self, user_service: UserService, mock_user: MockUser):
198
+ """Test updating user with password change."""
199
+ with patch("app.services.user.user_repo") as mock_repo:
200
+ mock_repo.get_by_id = AsyncMock(return_value=mock_user)
201
+ mock_repo.update = AsyncMock(return_value=mock_user)
202
+
203
+ user_update = UserUpdate(password="newpassword123")
204
+ result = await user_service.update(mock_user.id, user_update)
205
+
206
+ assert result == mock_user
207
+ # Verify hashed_password was passed to update
208
+ call_args = mock_repo.update.call_args
209
+ assert "hashed_password" in call_args[1]["update_data"]
210
+
211
+ @pytest.mark.anyio
212
+ async def test_delete_success(self, user_service: UserService, mock_user: MockUser):
213
+ """Test deleting user."""
214
+ with patch("app.services.user.user_repo") as mock_repo:
215
+ mock_repo.delete = AsyncMock(return_value=mock_user)
216
+
217
+ result = await user_service.delete(mock_user.id)
218
+
219
+ assert result == mock_user
220
+
221
+ @pytest.mark.anyio
222
+ async def test_delete_not_found(self, user_service: UserService):
223
+ """Test deleting non-existent user."""
224
+ with patch("app.services.user.user_repo") as mock_repo:
225
+ mock_repo.delete = AsyncMock(return_value=None)
226
+
227
+ with pytest.raises(NotFoundError):
228
+ await user_service.delete(uuid4())
229
+ {%- endif %}
230
+
231
+
232
+ {%- if cookiecutter.use_sqlite %}
233
+
234
+
235
+ class TestUserServiceSQLite:
236
+ """Tests for UserService with SQLite."""
237
+
238
+ @pytest.fixture
239
+ def mock_db(self) -> MagicMock:
240
+ """Create mock database session."""
241
+ return MagicMock()
242
+
243
+ @pytest.fixture
244
+ def user_service(self, mock_db: MagicMock) -> UserService:
245
+ """Create UserService instance with mock db."""
246
+ return UserService(mock_db)
247
+
248
+ @pytest.fixture
249
+ def mock_user(self) -> MockUser:
250
+ """Create a mock user."""
251
+ return MockUser()
252
+
253
+ def test_get_by_id_success(self, user_service: UserService, mock_user: MockUser):
254
+ """Test getting user by ID successfully."""
255
+ with patch("app.services.user.user_repo") as mock_repo:
256
+ mock_repo.get_by_id = MagicMock(return_value=mock_user)
257
+
258
+ result = user_service.get_by_id(mock_user.id)
259
+
260
+ assert result == mock_user
261
+
262
+ def test_get_by_id_not_found(self, user_service: UserService):
263
+ """Test getting non-existent user raises NotFoundError."""
264
+ with patch("app.services.user.user_repo") as mock_repo:
265
+ mock_repo.get_by_id = MagicMock(return_value=None)
266
+
267
+ with pytest.raises(NotFoundError):
268
+ user_service.get_by_id("nonexistent")
269
+
270
+ def test_authenticate_success(self, user_service: UserService, mock_user: MockUser):
271
+ """Test successful authentication."""
272
+ with (
273
+ patch("app.services.user.user_repo") as mock_repo,
274
+ patch("app.services.user.verify_password", return_value=True),
275
+ ):
276
+ mock_repo.get_by_email = MagicMock(return_value=mock_user)
277
+
278
+ result = user_service.authenticate("test@example.com", "password123")
279
+
280
+ assert result == mock_user
281
+
282
+ def test_register_success(self, user_service: UserService, mock_user: MockUser):
283
+ """Test registering a new user."""
284
+ with patch("app.services.user.user_repo") as mock_repo:
285
+ mock_repo.get_by_email = MagicMock(return_value=None)
286
+ mock_repo.create = MagicMock(return_value=mock_user)
287
+
288
+ user_in = UserCreate(
289
+ email="new@example.com",
290
+ password="password123",
291
+ full_name="New User",
292
+ )
293
+ result = user_service.register(user_in)
294
+
295
+ assert result == mock_user
296
+ {%- endif %}
297
+
298
+
299
+ {%- if cookiecutter.use_mongodb %}
300
+
301
+
302
+ class TestUserServiceMongoDB:
303
+ """Tests for UserService with MongoDB."""
304
+
305
+ @pytest.fixture
306
+ def user_service(self) -> UserService:
307
+ """Create UserService instance."""
308
+ return UserService()
309
+
310
+ @pytest.fixture
311
+ def mock_user(self) -> MockUser:
312
+ """Create a mock user."""
313
+ return MockUser()
314
+
315
+ @pytest.mark.anyio
316
+ async def test_get_by_id_success(self, user_service: UserService, mock_user: MockUser):
317
+ """Test getting user by ID successfully."""
318
+ with patch("app.services.user.user_repo") as mock_repo:
319
+ mock_repo.get_by_id = AsyncMock(return_value=mock_user)
320
+
321
+ result = await user_service.get_by_id(mock_user.id)
322
+
323
+ assert result == mock_user
324
+
325
+ @pytest.mark.anyio
326
+ async def test_get_by_id_not_found(self, user_service: UserService):
327
+ """Test getting non-existent user raises NotFoundError."""
328
+ with patch("app.services.user.user_repo") as mock_repo:
329
+ mock_repo.get_by_id = AsyncMock(return_value=None)
330
+
331
+ with pytest.raises(NotFoundError):
332
+ await user_service.get_by_id("nonexistent")
333
+
334
+ @pytest.mark.anyio
335
+ async def test_authenticate_success(self, user_service: UserService, mock_user: MockUser):
336
+ """Test successful authentication."""
337
+ with (
338
+ patch("app.services.user.user_repo") as mock_repo,
339
+ patch("app.services.user.verify_password", return_value=True),
340
+ ):
341
+ mock_repo.get_by_email = AsyncMock(return_value=mock_user)
342
+
343
+ result = await user_service.authenticate("test@example.com", "password123")
344
+
345
+ assert result == mock_user
346
+
347
+ @pytest.mark.anyio
348
+ async def test_register_success(self, user_service: UserService, mock_user: MockUser):
349
+ """Test registering a new user."""
350
+ with patch("app.services.user.user_repo") as mock_repo:
351
+ mock_repo.get_by_email = AsyncMock(return_value=None)
352
+ mock_repo.create = AsyncMock(return_value=mock_user)
353
+
354
+ user_in = UserCreate(
355
+ email="new@example.com",
356
+ password="password123",
357
+ full_name="New User",
358
+ )
359
+ result = await user_service.register(user_in)
360
+
361
+ assert result == mock_user
362
+ {%- endif %}
363
+ {%- endif %}
@@ -0,0 +1,85 @@
1
+ {%- if cookiecutter.use_celery %}
2
+ """Tests for Celery worker tasks."""
3
+
4
+ from unittest.mock import MagicMock, patch
5
+
6
+ import pytest
7
+
8
+
9
+ class TestExampleTask:
10
+ """Tests for example_task."""
11
+
12
+ def test_example_task_success(self):
13
+ """Test example_task completes successfully."""
14
+ from app.worker.tasks.examples import example_task
15
+
16
+ # Create a mock for self (the task)
17
+ mock_self = MagicMock()
18
+ mock_self.request.id = "test-task-id"
19
+
20
+ with patch("app.worker.tasks.examples.time.sleep"):
21
+ result = example_task.run(mock_self, "test message")
22
+
23
+ assert result["status"] == "completed"
24
+ assert "test message" in result["message"]
25
+ assert result["task_id"] == "test-task-id"
26
+
27
+ def test_example_task_retry_on_error(self):
28
+ """Test example_task retries on error."""
29
+ from app.worker.tasks.examples import example_task
30
+
31
+ mock_self = MagicMock()
32
+ mock_self.request.id = "test-task-id"
33
+ mock_self.request.retries = 0
34
+
35
+ with patch("app.worker.tasks.examples.time.sleep", side_effect=Exception("Test error")):
36
+ mock_self.retry = MagicMock(side_effect=Exception("Retry"))
37
+ with pytest.raises(Exception, match="Retry"):
38
+ example_task.run(mock_self, "test message")
39
+ mock_self.retry.assert_called_once()
40
+
41
+
42
+ class TestLongRunningTask:
43
+ """Tests for long_running_task."""
44
+
45
+ def test_long_running_task_completes(self):
46
+ """Test long_running_task completes with progress."""
47
+ from app.worker.tasks.examples import long_running_task
48
+
49
+ mock_self = MagicMock()
50
+ mock_self.request.id = "test-task-id"
51
+
52
+ with patch("app.worker.tasks.examples.time.sleep"):
53
+ result = long_running_task.run(mock_self, duration=3)
54
+
55
+ assert result["status"] == "completed"
56
+ assert result["duration"] == 3
57
+ # Check progress updates were made
58
+ assert mock_self.update_state.call_count == 3
59
+
60
+
61
+ class TestSendEmailTask:
62
+ """Tests for send_email_task."""
63
+
64
+ def test_send_email_task_success(self):
65
+ """Test send_email_task sends email."""
66
+ from app.worker.tasks.examples import send_email_task
67
+
68
+ with patch("app.worker.tasks.examples.time.sleep"):
69
+ result = send_email_task("test@example.com", "Subject", "Body")
70
+
71
+ assert result["status"] == "sent"
72
+ assert result["to"] == "test@example.com"
73
+ assert result["subject"] == "Subject"
74
+
75
+
76
+ class TestCeleryAppConfiguration:
77
+ """Tests for Celery app configuration."""
78
+
79
+ def test_celery_app_exists(self):
80
+ """Test Celery app is configured."""
81
+ from app.worker.celery_app import celery_app
82
+
83
+ assert celery_app is not None
84
+ assert celery_app.main == "{{ cookiecutter.project_slug }}"
85
+ {%- endif %}
@@ -0,0 +1,242 @@
1
+ {%- if cookiecutter.enable_docker %}
2
+ # Development configuration (alias for docker-compose.yml)
3
+ # Usage: docker-compose -f docker-compose.dev.yml up -d
4
+ #
5
+ # This file is identical to docker-compose.yml for explicit naming preference.
6
+ # Use docker-compose.yml for default development.
7
+
8
+ services:
9
+ app:
10
+ build:
11
+ context: ./backend
12
+ dockerfile: Dockerfile
13
+ container_name: {{ cookiecutter.project_slug }}_backend
14
+ ports:
15
+ - "{{ cookiecutter.backend_port }}:{{ cookiecutter.backend_port }}"
16
+ volumes:
17
+ - ./backend/app:/app/app:ro
18
+ - ./backend/cli:/app/cli:ro
19
+ env_file:
20
+ - ./backend/.env
21
+ environment:
22
+ - DEBUG=true
23
+ - ENVIRONMENT=local
24
+ {%- if cookiecutter.use_postgresql %}
25
+ - POSTGRES_HOST=db
26
+ {%- endif %}
27
+ {%- if cookiecutter.enable_redis %}
28
+ - REDIS_HOST=redis
29
+ {%- endif %}
30
+ {%- if cookiecutter.use_celery %}
31
+ - CELERY_BROKER_URL=redis://redis:6379/0
32
+ - CELERY_RESULT_BACKEND=redis://redis:6379/0
33
+ {%- endif %}
34
+ {%- if cookiecutter.use_taskiq %}
35
+ - TASKIQ_BROKER_URL=redis://redis:6379/1
36
+ - TASKIQ_RESULT_BACKEND=redis://redis:6379/1
37
+ {%- endif %}
38
+ command: uvicorn app.main:app --host 0.0.0.0 --port {{ cookiecutter.backend_port }} --reload
39
+ networks:
40
+ - backend
41
+ {%- if cookiecutter.use_postgresql or cookiecutter.enable_redis %}
42
+ depends_on:
43
+ {%- if cookiecutter.use_postgresql %}
44
+ db:
45
+ condition: service_healthy
46
+ {%- endif %}
47
+ {%- if cookiecutter.enable_redis %}
48
+ redis:
49
+ condition: service_healthy
50
+ {%- endif %}
51
+ {%- endif %}
52
+ restart: unless-stopped
53
+
54
+ {%- if cookiecutter.use_postgresql %}
55
+
56
+ db:
57
+ image: postgres:16-alpine
58
+ container_name: {{ cookiecutter.project_slug }}_db
59
+ environment:
60
+ - POSTGRES_USER=${POSTGRES_USER:-postgres}
61
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
62
+ - POSTGRES_DB=${POSTGRES_DB:-{{ cookiecutter.project_slug }}}
63
+ volumes:
64
+ - postgres_data:/var/lib/postgresql/data
65
+ ports:
66
+ - "5432:5432"
67
+ networks:
68
+ - backend
69
+ healthcheck:
70
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
71
+ interval: 10s
72
+ timeout: 5s
73
+ retries: 5
74
+ restart: unless-stopped
75
+ {%- endif %}
76
+
77
+ {%- if cookiecutter.enable_redis %}
78
+
79
+ redis:
80
+ image: redis:7-alpine
81
+ container_name: {{ cookiecutter.project_slug }}_redis
82
+ ports:
83
+ - "6379:6379"
84
+ volumes:
85
+ - redis_data:/data
86
+ networks:
87
+ - backend
88
+ healthcheck:
89
+ test: ["CMD", "redis-cli", "ping"]
90
+ interval: 10s
91
+ timeout: 5s
92
+ retries: 5
93
+ restart: unless-stopped
94
+ {%- endif %}
95
+
96
+ {%- if cookiecutter.use_celery %}
97
+
98
+ celery_worker:
99
+ build:
100
+ context: ./backend
101
+ dockerfile: Dockerfile
102
+ container_name: {{ cookiecutter.project_slug }}_celery_worker
103
+ volumes:
104
+ - ./backend/app:/app/app:ro
105
+ command: celery -A app.worker.celery_app worker --loglevel=debug
106
+ env_file:
107
+ - ./backend/.env
108
+ environment:
109
+ - DEBUG=true
110
+ {%- if cookiecutter.use_postgresql %}
111
+ - POSTGRES_HOST=db
112
+ {%- endif %}
113
+ - REDIS_HOST=redis
114
+ - CELERY_BROKER_URL=redis://redis:6379/0
115
+ - CELERY_RESULT_BACKEND=redis://redis:6379/0
116
+ networks:
117
+ - backend
118
+ depends_on:
119
+ redis:
120
+ condition: service_healthy
121
+ {%- if cookiecutter.use_postgresql %}
122
+ db:
123
+ condition: service_healthy
124
+ {%- endif %}
125
+ restart: unless-stopped
126
+
127
+ celery_beat:
128
+ build:
129
+ context: ./backend
130
+ dockerfile: Dockerfile
131
+ container_name: {{ cookiecutter.project_slug }}_celery_beat
132
+ volumes:
133
+ - ./backend/app:/app/app:ro
134
+ command: celery -A app.worker.celery_app beat --loglevel=debug
135
+ env_file:
136
+ - ./backend/.env
137
+ environment:
138
+ - DEBUG=true
139
+ - REDIS_HOST=redis
140
+ - CELERY_BROKER_URL=redis://redis:6379/0
141
+ - CELERY_RESULT_BACKEND=redis://redis:6379/0
142
+ networks:
143
+ - backend
144
+ depends_on:
145
+ redis:
146
+ condition: service_healthy
147
+ restart: unless-stopped
148
+
149
+ flower:
150
+ build:
151
+ context: ./backend
152
+ dockerfile: Dockerfile
153
+ container_name: {{ cookiecutter.project_slug }}_flower
154
+ command: celery -A app.worker.celery_app flower --port=5555
155
+ ports:
156
+ - "5555:5555"
157
+ env_file:
158
+ - ./backend/.env
159
+ environment:
160
+ - DEBUG=true
161
+ - REDIS_HOST=redis
162
+ - CELERY_BROKER_URL=redis://redis:6379/0
163
+ - CELERY_RESULT_BACKEND=redis://redis:6379/0
164
+ networks:
165
+ - backend
166
+ depends_on:
167
+ redis:
168
+ condition: service_healthy
169
+ restart: unless-stopped
170
+ {%- endif %}
171
+
172
+ {%- if cookiecutter.use_taskiq %}
173
+
174
+ taskiq_worker:
175
+ build:
176
+ context: ./backend
177
+ dockerfile: Dockerfile
178
+ container_name: {{ cookiecutter.project_slug }}_taskiq_worker
179
+ volumes:
180
+ - ./backend/app:/app/app:ro
181
+ command: taskiq worker app.worker.taskiq_app:broker --workers 1 --reload
182
+ env_file:
183
+ - ./backend/.env
184
+ environment:
185
+ - DEBUG=true
186
+ {%- if cookiecutter.use_postgresql %}
187
+ - POSTGRES_HOST=db
188
+ {%- endif %}
189
+ - REDIS_HOST=redis
190
+ - TASKIQ_BROKER_URL=redis://redis:6379/1
191
+ - TASKIQ_RESULT_BACKEND=redis://redis:6379/1
192
+ networks:
193
+ - backend
194
+ depends_on:
195
+ redis:
196
+ condition: service_healthy
197
+ {%- if cookiecutter.use_postgresql %}
198
+ db:
199
+ condition: service_healthy
200
+ {%- endif %}
201
+ restart: unless-stopped
202
+
203
+ taskiq_scheduler:
204
+ build:
205
+ context: ./backend
206
+ dockerfile: Dockerfile
207
+ container_name: {{ cookiecutter.project_slug }}_taskiq_scheduler
208
+ volumes:
209
+ - ./backend/app:/app/app:ro
210
+ command: taskiq scheduler app.worker.taskiq_app:scheduler
211
+ env_file:
212
+ - ./backend/.env
213
+ environment:
214
+ - DEBUG=true
215
+ - REDIS_HOST=redis
216
+ - TASKIQ_BROKER_URL=redis://redis:6379/1
217
+ - TASKIQ_RESULT_BACKEND=redis://redis:6379/1
218
+ networks:
219
+ - backend
220
+ depends_on:
221
+ redis:
222
+ condition: service_healthy
223
+ restart: unless-stopped
224
+ {%- endif %}
225
+
226
+ networks:
227
+ backend:
228
+ driver: bridge
229
+
230
+ {%- if cookiecutter.use_postgresql or cookiecutter.enable_redis %}
231
+
232
+ volumes:
233
+ {%- if cookiecutter.use_postgresql %}
234
+ postgres_data:
235
+ {%- endif %}
236
+ {%- if cookiecutter.enable_redis %}
237
+ redis_data:
238
+ {%- endif %}
239
+ {%- endif %}
240
+ {%- else %}
241
+ # Docker is disabled for this project
242
+ {%- endif %}