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,355 @@
1
+ #!/usr/bin/env python
2
+ """Post-generation hook for cookiecutter template."""
3
+
4
+ import os
5
+ import shutil
6
+ import subprocess
7
+ import sys
8
+
9
+ # Get cookiecutter variables
10
+ use_frontend = "{{ cookiecutter.use_frontend }}" == "True"
11
+ generate_env = "{{ cookiecutter.generate_env }}" == "True"
12
+ enable_i18n = "{{ cookiecutter.enable_i18n }}" == "True"
13
+
14
+ # Feature flags
15
+ use_database = "{{ cookiecutter.use_database }}" == "True"
16
+ use_postgresql = "{{ cookiecutter.use_postgresql }}" == "True"
17
+ use_sqlite = "{{ cookiecutter.use_sqlite }}" == "True"
18
+ use_mongodb = "{{ cookiecutter.use_mongodb }}" == "True"
19
+ include_example_crud = "{{ cookiecutter.include_example_crud }}" == "True"
20
+ enable_ai_agent = "{{ cookiecutter.enable_ai_agent }}" == "True"
21
+ use_pydantic_ai = "{{ cookiecutter.use_pydantic_ai }}" == "True"
22
+ use_langchain = "{{ cookiecutter.use_langchain }}" == "True"
23
+ enable_admin_panel = "{{ cookiecutter.enable_admin_panel }}" == "True"
24
+ enable_websockets = "{{ cookiecutter.enable_websockets }}" == "True"
25
+ enable_redis = "{{ cookiecutter.enable_redis }}" == "True"
26
+ enable_caching = "{{ cookiecutter.enable_caching }}" == "True"
27
+ enable_rate_limiting = "{{ cookiecutter.enable_rate_limiting }}" == "True"
28
+ enable_session_management = "{{ cookiecutter.enable_session_management }}" == "True"
29
+ enable_conversation_persistence = "{{ cookiecutter.enable_conversation_persistence }}" == "True"
30
+ enable_webhooks = "{{ cookiecutter.enable_webhooks }}" == "True"
31
+ enable_oauth = "{{ cookiecutter.enable_oauth }}" == "True"
32
+ use_jwt = "{{ cookiecutter.use_jwt }}" == "True"
33
+ use_celery = "{{ cookiecutter.use_celery }}" == "True"
34
+ use_taskiq = "{{ cookiecutter.use_taskiq }}" == "True"
35
+ use_arq = "{{ cookiecutter.use_arq }}" == "True"
36
+
37
+
38
+ def remove_file(path: str) -> None:
39
+ """Remove a file if it exists."""
40
+ if os.path.exists(path):
41
+ os.remove(path)
42
+ print(f" Removed: {os.path.relpath(path)}")
43
+
44
+
45
+ def remove_dir(path: str) -> None:
46
+ """Remove a directory if it exists."""
47
+ if os.path.exists(path):
48
+ shutil.rmtree(path)
49
+ print(f" Removed: {os.path.relpath(path)}/")
50
+
51
+
52
+ # Base directories
53
+ backend_app = os.path.join(os.getcwd(), "backend", "app")
54
+
55
+ # ============================================================================
56
+ # Cleanup stub files based on disabled features
57
+ # ============================================================================
58
+ print("Cleaning up unused files...")
59
+
60
+ # --- AI Agent files ---
61
+ if not enable_ai_agent:
62
+ # Remove entire agents directory when AI is disabled
63
+ remove_dir(os.path.join(backend_app, "agents"))
64
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "agent.py"))
65
+ else:
66
+ # Remove framework-specific files based on selection
67
+ if not use_pydantic_ai:
68
+ remove_file(os.path.join(backend_app, "agents", "assistant.py"))
69
+ if not use_langchain:
70
+ remove_file(os.path.join(backend_app, "agents", "langchain_assistant.py"))
71
+
72
+ # --- Example CRUD files ---
73
+ if not include_example_crud or not use_database:
74
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "items.py"))
75
+ remove_file(os.path.join(backend_app, "db", "models", "item.py"))
76
+ remove_file(os.path.join(backend_app, "repositories", "item.py"))
77
+ remove_file(os.path.join(backend_app, "services", "item.py"))
78
+ remove_file(os.path.join(backend_app, "schemas", "item.py"))
79
+
80
+ # --- Conversation persistence files ---
81
+ if not enable_conversation_persistence:
82
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "conversations.py"))
83
+ remove_file(os.path.join(backend_app, "db", "models", "conversation.py"))
84
+ remove_file(os.path.join(backend_app, "repositories", "conversation.py"))
85
+ remove_file(os.path.join(backend_app, "services", "conversation.py"))
86
+ remove_file(os.path.join(backend_app, "schemas", "conversation.py"))
87
+
88
+ # --- Webhook files ---
89
+ if not enable_webhooks or not use_database:
90
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "webhooks.py"))
91
+ remove_file(os.path.join(backend_app, "db", "models", "webhook.py"))
92
+ remove_file(os.path.join(backend_app, "repositories", "webhook.py"))
93
+ remove_file(os.path.join(backend_app, "services", "webhook.py"))
94
+ remove_file(os.path.join(backend_app, "schemas", "webhook.py"))
95
+
96
+ # --- Session management files ---
97
+ if not enable_session_management or not use_jwt:
98
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "sessions.py"))
99
+ remove_file(os.path.join(backend_app, "db", "models", "session.py"))
100
+ remove_file(os.path.join(backend_app, "repositories", "session.py"))
101
+ remove_file(os.path.join(backend_app, "services", "session.py"))
102
+ remove_file(os.path.join(backend_app, "schemas", "session.py"))
103
+
104
+ # --- WebSocket files ---
105
+ if not enable_websockets:
106
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "ws.py"))
107
+
108
+ # --- Admin panel ---
109
+ if not enable_admin_panel or (not use_postgresql and not use_sqlite):
110
+ remove_file(os.path.join(backend_app, "admin.py"))
111
+
112
+ # --- Redis/Cache files ---
113
+ if not enable_redis:
114
+ remove_file(os.path.join(backend_app, "clients", "redis.py"))
115
+
116
+ if not enable_caching:
117
+ remove_file(os.path.join(backend_app, "core", "cache.py"))
118
+
119
+ # --- Rate limiting ---
120
+ if not enable_rate_limiting:
121
+ remove_file(os.path.join(backend_app, "core", "rate_limit.py"))
122
+
123
+ # --- OAuth ---
124
+ if not enable_oauth:
125
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "oauth.py"))
126
+ remove_file(os.path.join(backend_app, "core", "oauth.py"))
127
+
128
+ # --- Worker/Background tasks ---
129
+ use_any_background_tasks = use_celery or use_taskiq or use_arq
130
+ if not use_any_background_tasks:
131
+ remove_dir(os.path.join(backend_app, "worker"))
132
+ else:
133
+ # Remove specific worker files based on selection
134
+ worker_dir = os.path.join(backend_app, "worker")
135
+ if not use_celery:
136
+ remove_file(os.path.join(worker_dir, "celery_app.py"))
137
+ remove_file(os.path.join(worker_dir, "tasks", "examples.py"))
138
+ remove_file(os.path.join(worker_dir, "tasks", "schedules.py"))
139
+ if not use_taskiq:
140
+ remove_file(os.path.join(worker_dir, "taskiq_app.py"))
141
+ remove_file(os.path.join(worker_dir, "tasks", "taskiq_examples.py"))
142
+ if not use_arq:
143
+ remove_file(os.path.join(worker_dir, "arq_app.py"))
144
+
145
+
146
+ # --- Cleanup empty directories ---
147
+ def remove_empty_dirs(path: str) -> None:
148
+ """Recursively remove empty directories."""
149
+ if not os.path.isdir(path):
150
+ return
151
+ for item in os.listdir(path):
152
+ item_path = os.path.join(path, item)
153
+ if os.path.isdir(item_path):
154
+ remove_empty_dirs(item_path)
155
+ # Check if directory is now empty (except __init__.py)
156
+ remaining = os.listdir(path)
157
+ if not remaining:
158
+ os.rmdir(path)
159
+ print(f" Removed empty: {os.path.relpath(path)}/")
160
+ elif remaining == ["__init__.py"]:
161
+ # Directory only has __init__.py - remove it
162
+ os.remove(os.path.join(path, "__init__.py"))
163
+ os.rmdir(path)
164
+ print(f" Removed empty: {os.path.relpath(path)}/")
165
+
166
+
167
+ # Clean up empty directories in key locations
168
+ for subdir in ["clients", "agents", "worker", "worker/tasks"]:
169
+ dir_path = os.path.join(backend_app, subdir)
170
+ if os.path.exists(dir_path):
171
+ remove_empty_dirs(dir_path)
172
+
173
+ print("File cleanup complete.")
174
+
175
+ # Remove frontend folder if not using frontend
176
+ if not use_frontend:
177
+ frontend_dir = os.path.join(os.getcwd(), "frontend")
178
+ if os.path.exists(frontend_dir):
179
+ shutil.rmtree(frontend_dir)
180
+ print("Removed frontend/ directory (frontend not enabled)")
181
+
182
+ # Handle i18n disabled: move files from [locale]/ to app root
183
+ if use_frontend and not enable_i18n:
184
+ app_dir = os.path.join(os.getcwd(), "frontend", "src", "app")
185
+ locale_dir = os.path.join(app_dir, "[locale]")
186
+
187
+ if os.path.exists(locale_dir):
188
+ # Move all contents from [locale]/ to app/
189
+ for item in os.listdir(locale_dir):
190
+ src = os.path.join(locale_dir, item)
191
+ dst = os.path.join(app_dir, item)
192
+ # Skip the layout.tsx from [locale] - we'll use the root layout
193
+ if item == "layout.tsx":
194
+ continue
195
+ if os.path.exists(dst):
196
+ if os.path.isdir(dst):
197
+ shutil.rmtree(dst)
198
+ else:
199
+ os.remove(dst)
200
+ shutil.move(src, dst)
201
+
202
+ # Remove the now-empty [locale] directory
203
+ shutil.rmtree(locale_dir)
204
+ print("Moved routes from [locale]/ to app/ (i18n not enabled)")
205
+
206
+ # Update root layout to include providers
207
+ root_layout = os.path.join(app_dir, "layout.tsx")
208
+ if os.path.exists(root_layout):
209
+ with open(root_layout) as f:
210
+ content = f.read()
211
+ # Add Providers import and wrap children
212
+ content = content.replace(
213
+ 'import "./globals.css";',
214
+ 'import "./globals.css";\nimport { Providers } from "./providers";',
215
+ )
216
+ content = content.replace(
217
+ "<body className={inter.className}>{children}</body>",
218
+ "<body className={inter.className}>\n <Providers>{children}</Providers>\n </body>",
219
+ )
220
+ with open(root_layout, "w") as f:
221
+ f.write(content)
222
+
223
+ # Remove middleware.ts
224
+ middleware_file = os.path.join(os.getcwd(), "frontend", "src", "middleware.ts")
225
+ if os.path.exists(middleware_file):
226
+ os.remove(middleware_file)
227
+
228
+ # Remove i18n related files
229
+ i18n_file = os.path.join(os.getcwd(), "frontend", "src", "i18n.ts")
230
+ if os.path.exists(i18n_file):
231
+ os.remove(i18n_file)
232
+
233
+ messages_dir = os.path.join(os.getcwd(), "frontend", "messages")
234
+ if os.path.exists(messages_dir):
235
+ shutil.rmtree(messages_dir)
236
+
237
+ # Remove language-switcher component
238
+ lang_switcher = os.path.join(
239
+ os.getcwd(), "frontend", "src", "components", "language-switcher.tsx"
240
+ )
241
+ if os.path.exists(lang_switcher):
242
+ os.remove(lang_switcher)
243
+
244
+ print("Removed i18n files (i18n not enabled)")
245
+
246
+ # Remove .env files if generate_env is false
247
+ if not generate_env:
248
+ backend_env = os.path.join(os.getcwd(), "backend", ".env")
249
+ if os.path.exists(backend_env):
250
+ os.remove(backend_env)
251
+ print("Removed backend/.env (generate_env disabled)")
252
+
253
+ frontend_env = os.path.join(os.getcwd(), "frontend", ".env.local")
254
+ if os.path.exists(frontend_env):
255
+ os.remove(frontend_env)
256
+ print("Removed frontend/.env.local (generate_env disabled)")
257
+
258
+ # Generate uv.lock for backend (required for Docker builds)
259
+ backend_dir = os.path.join(os.getcwd(), "backend")
260
+ if os.path.exists(backend_dir):
261
+ uv_cmd = shutil.which("uv")
262
+ if uv_cmd:
263
+ print("Generating uv.lock for backend...")
264
+ result = subprocess.run(
265
+ [uv_cmd, "lock"],
266
+ cwd=backend_dir,
267
+ capture_output=True,
268
+ check=False,
269
+ )
270
+ if result.returncode == 0:
271
+ print("uv.lock generated successfully.")
272
+ else:
273
+ print("Warning: Failed to generate uv.lock. Run 'uv lock' in backend/ directory.")
274
+ else:
275
+ print("Warning: uv not found. Run 'uv lock' in backend/ to generate lock file.")
276
+
277
+ # Run ruff to auto-fix import sorting and other linting issues
278
+ if os.path.exists(backend_dir):
279
+ ruff_cmd = None
280
+
281
+ # Try multiple methods to find/run ruff
282
+ # 1. Check if ruff is in PATH
283
+ ruff_path = shutil.which("ruff")
284
+ if ruff_path:
285
+ ruff_cmd = [ruff_path]
286
+ # 2. Try uvx ruff (if uv is installed)
287
+ elif shutil.which("uvx"):
288
+ ruff_cmd = ["uvx", "ruff"]
289
+ # 3. Try python -m ruff
290
+ else:
291
+ # Test if ruff is available as a module
292
+ result = subprocess.run(
293
+ [sys.executable, "-m", "ruff", "--version"],
294
+ capture_output=True,
295
+ check=False,
296
+ )
297
+ if result.returncode == 0:
298
+ ruff_cmd = [sys.executable, "-m", "ruff"]
299
+
300
+ if ruff_cmd:
301
+ print(f"Running ruff to format code (using: {' '.join(ruff_cmd)})...")
302
+ # Run ruff check --fix to auto-fix issues
303
+ subprocess.run(
304
+ [*ruff_cmd, "check", "--fix", "--quiet", backend_dir],
305
+ check=False,
306
+ )
307
+ # Run ruff format for consistent formatting
308
+ subprocess.run(
309
+ [*ruff_cmd, "format", "--quiet", backend_dir],
310
+ check=False,
311
+ )
312
+ print("Code formatting complete.")
313
+ else:
314
+ print("Warning: ruff not found. Run 'ruff format .' in backend/ to format code.")
315
+
316
+ # Format frontend with prettier if it exists
317
+ frontend_dir = os.path.join(os.getcwd(), "frontend")
318
+ if use_frontend and os.path.exists(frontend_dir):
319
+ # Try to find bun or npx for running prettier
320
+ bun_cmd = shutil.which("bun")
321
+ npx_cmd = shutil.which("npx")
322
+
323
+ if bun_cmd:
324
+ print("Installing frontend dependencies and formatting with Prettier...")
325
+ # Install dependencies first (prettier is a devDependency)
326
+ result = subprocess.run(
327
+ [bun_cmd, "install"],
328
+ cwd=frontend_dir,
329
+ capture_output=True,
330
+ check=False,
331
+ )
332
+ if result.returncode == 0:
333
+ # Format with prettier
334
+ subprocess.run(
335
+ [bun_cmd, "run", "format"],
336
+ cwd=frontend_dir,
337
+ capture_output=True,
338
+ check=False,
339
+ )
340
+ print("Frontend formatting complete.")
341
+ else:
342
+ print("Warning: Failed to install frontend dependencies.")
343
+ elif npx_cmd:
344
+ print("Formatting frontend with Prettier...")
345
+ subprocess.run(
346
+ [npx_cmd, "prettier", "--write", "."],
347
+ cwd=frontend_dir,
348
+ capture_output=True,
349
+ check=False,
350
+ )
351
+ print("Frontend formatting complete.")
352
+ else:
353
+ print("Warning: bun/npx not found. Run 'bun run format' in frontend/ to format code.")
354
+
355
+ print("Project generated successfully!")
@@ -0,0 +1,56 @@
1
+ {%- if cookiecutter.enable_docker %}
2
+ # {{ cookiecutter.project_name }} - Production Environment
3
+ # Generated by fastapi-fullstack v{{ cookiecutter.generator_version }}
4
+ #
5
+ # IMPORTANT: Copy this file to .env.prod before deploying
6
+ # cp .env.prod.example .env.prod
7
+ #
8
+ # WARNING: Never commit .env.prod to version control!
9
+
10
+ # === Container Prefix (must be unique per server) ===
11
+ CONTAINER_PREFIX={{ cookiecutter.project_slug }}
12
+
13
+ {%- if cookiecutter.include_traefik_labels %}
14
+
15
+ # === Domain Configuration ===
16
+ DOMAIN=example.com
17
+ ACME_EMAIL=admin@example.com
18
+ {%- endif %}
19
+
20
+ {%- if cookiecutter.use_postgresql %}
21
+
22
+ # === PostgreSQL ===
23
+ POSTGRES_USER=postgres
24
+ POSTGRES_PASSWORD= # Generate: openssl rand -base64 32
25
+ POSTGRES_DB={{ cookiecutter.project_slug }}
26
+ {%- endif %}
27
+
28
+ {%- if cookiecutter.enable_redis %}
29
+
30
+ # === Redis ===
31
+ REDIS_PASSWORD= # Generate: openssl rand -base64 32
32
+ {%- endif %}
33
+
34
+ {%- if cookiecutter.use_jwt %}
35
+
36
+ # === JWT Secret ===
37
+ SECRET_KEY= # Generate: openssl rand -hex 32
38
+ {%- endif %}
39
+
40
+ {%- if cookiecutter.include_traefik_service %}
41
+
42
+ # === Traefik Dashboard ===
43
+ # Generate with: htpasswd -nb admin yourpassword
44
+ # Example: admin:$apr1$xyz$hash
45
+ TRAEFIK_DASHBOARD_AUTH=
46
+ {%- endif %}
47
+
48
+ {%- if cookiecutter.use_celery %}
49
+
50
+ # === Flower Monitoring ===
51
+ FLOWER_USER=admin
52
+ FLOWER_PASSWORD= # Generate: openssl rand -base64 16
53
+ {%- endif %}
54
+ {%- else %}
55
+ # Docker is disabled for this project
56
+ {%- endif %}
@@ -0,0 +1,150 @@
1
+ {%- if cookiecutter.use_github_actions %}
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ branches: [main, master]
7
+ pull_request:
8
+ branches: [main, master]
9
+
10
+ jobs:
11
+ lint:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v4
18
+ with:
19
+ version: "latest"
20
+
21
+ - name: Set up Python
22
+ run: uv python install {{ cookiecutter.python_version }}
23
+
24
+ - name: Install dependencies
25
+ run: uv sync --directory backend --dev
26
+
27
+ - name: Run ruff check
28
+ run: uv run --directory backend ruff check app tests cli
29
+
30
+ - name: Run ruff format check
31
+ run: uv run --directory backend ruff format app tests cli --check
32
+
33
+ - name: Run mypy
34
+ run: uv run --directory backend mypy app
35
+
36
+ test:
37
+ runs-on: ubuntu-latest
38
+ {%- if cookiecutter.use_postgresql or cookiecutter.enable_redis %}
39
+ services:
40
+ {%- if cookiecutter.use_postgresql %}
41
+ postgres:
42
+ image: postgres:16-alpine
43
+ env:
44
+ POSTGRES_USER: postgres
45
+ POSTGRES_PASSWORD: postgres
46
+ POSTGRES_DB: test_db
47
+ ports:
48
+ - 5432:5432
49
+ options: >-
50
+ --health-cmd pg_isready
51
+ --health-interval 10s
52
+ --health-timeout 5s
53
+ --health-retries 5
54
+ {%- endif %}
55
+ {%- if cookiecutter.enable_redis %}
56
+ redis:
57
+ image: redis:7-alpine
58
+ ports:
59
+ - 6379:6379
60
+ options: >-
61
+ --health-cmd "redis-cli ping"
62
+ --health-interval 10s
63
+ --health-timeout 5s
64
+ --health-retries 5
65
+ {%- endif %}
66
+ {%- endif %}
67
+
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+
71
+ - name: Install uv
72
+ uses: astral-sh/setup-uv@v4
73
+ with:
74
+ version: "latest"
75
+
76
+ - name: Set up Python
77
+ run: uv python install {{ cookiecutter.python_version }}
78
+
79
+ - name: Install dependencies
80
+ run: uv sync --directory backend --dev
81
+
82
+ - name: Run tests
83
+ run: uv run --directory backend pytest tests/ -v --cov=app --cov-report=xml
84
+ env:
85
+ {%- if cookiecutter.use_postgresql %}
86
+ POSTGRES_HOST: localhost
87
+ POSTGRES_PORT: 5432
88
+ POSTGRES_USER: postgres
89
+ POSTGRES_PASSWORD: postgres
90
+ POSTGRES_DB: test_db
91
+ {%- endif %}
92
+ {%- if cookiecutter.enable_redis %}
93
+ REDIS_HOST: localhost
94
+ REDIS_PORT: 6379
95
+ {%- endif %}
96
+
97
+ - name: Upload coverage to Codecov
98
+ uses: codecov/codecov-action@v4
99
+ with:
100
+ files: ./backend/coverage.xml
101
+ fail_ci_if_error: false
102
+
103
+ security:
104
+ name: Security Scan
105
+ runs-on: ubuntu-latest
106
+ steps:
107
+ - uses: actions/checkout@v4
108
+
109
+ - name: Install uv
110
+ uses: astral-sh/setup-uv@v4
111
+ with:
112
+ version: "latest"
113
+
114
+ - name: Set up Python
115
+ run: uv python install {{ cookiecutter.python_version }}
116
+
117
+ - name: Install dependencies
118
+ run: uv sync --directory backend --dev
119
+
120
+ - name: Install pip-audit
121
+ run: uv pip install pip-audit
122
+
123
+ - name: Run pip-audit
124
+ run: uv run pip-audit --require-hashes=false --progress-spinner=off
125
+ working-directory: backend
126
+
127
+ {%- if cookiecutter.enable_docker %}
128
+
129
+ docker:
130
+ runs-on: ubuntu-latest
131
+ needs: [lint, test]
132
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
133
+ steps:
134
+ - uses: actions/checkout@v4
135
+
136
+ - name: Set up Docker Buildx
137
+ uses: docker/setup-buildx-action@v3
138
+
139
+ - name: Build Docker image
140
+ uses: docker/build-push-action@v6
141
+ with:
142
+ context: ./backend
143
+ push: false
144
+ tags: {{ cookiecutter.project_slug }}:latest
145
+ cache-from: type=gha
146
+ cache-to: type=gha,mode=max
147
+ {%- endif %}
148
+ {%- else %}
149
+ # GitHub Actions CI is disabled for this project
150
+ {%- endif %}
@@ -0,0 +1,109 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ # Python lib directories (but not frontend src/lib)
18
+ /lib/
19
+ /lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+
28
+ # PyInstaller
29
+ *.manifest
30
+ *.spec
31
+
32
+ # Installer logs
33
+ pip-log.txt
34
+ pip-delete-this-directory.txt
35
+
36
+ # Unit test / coverage reports
37
+ htmlcov/
38
+ .tox/
39
+ .nox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ nosetests.xml
44
+ coverage.xml
45
+ *.cover
46
+ *.py,cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+
50
+ # Translations
51
+ *.mo
52
+ *.pot
53
+
54
+ # Environments
55
+ .env
56
+ .env.local
57
+ .env.*.local
58
+ .env.prod
59
+ .venv
60
+ env/
61
+ venv/
62
+ ENV/
63
+ env.bak/
64
+ venv.bak/
65
+
66
+ # IDE
67
+ .idea/
68
+ .vscode/
69
+ *.swp
70
+ *.swo
71
+ *~
72
+
73
+ # mypy
74
+ .mypy_cache/
75
+ .dmypy.json
76
+ dmypy.json
77
+
78
+ # ruff
79
+ .ruff_cache/
80
+
81
+ # Jupyter Notebook
82
+ .ipynb_checkpoints
83
+
84
+ # pytype
85
+ .pytype/
86
+
87
+ # Cython debug symbols
88
+ cython_debug/
89
+
90
+ # Local development
91
+ *.db
92
+ *.sqlite
93
+ *.sqlite3
94
+
95
+ # Logs
96
+ *.log
97
+ logs/
98
+
99
+ # Docker
100
+ .docker/
101
+
102
+ # OS
103
+ .DS_Store
104
+ Thumbs.db
105
+
106
+ # Project specific
107
+ {%- if cookiecutter.use_sqlite %}
108
+ {{ cookiecutter.project_slug }}.db
109
+ {%- endif %}