fastapi-fullstack 0.1.2__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 (221) hide show
  1. fastapi_fullstack-0.1.2.dist-info/METADATA +545 -0
  2. fastapi_fullstack-0.1.2.dist-info/RECORD +221 -0
  3. fastapi_fullstack-0.1.2.dist-info/WHEEL +4 -0
  4. fastapi_fullstack-0.1.2.dist-info/entry_points.txt +2 -0
  5. fastapi_fullstack-0.1.2.dist-info/licenses/LICENSE +21 -0
  6. fastapi_gen/__init__.py +3 -0
  7. fastapi_gen/cli.py +256 -0
  8. fastapi_gen/config.py +255 -0
  9. fastapi_gen/generator.py +181 -0
  10. fastapi_gen/prompts.py +648 -0
  11. fastapi_gen/template/cookiecutter.json +76 -0
  12. fastapi_gen/template/hooks/post_gen_project.py +111 -0
  13. fastapi_gen/template/{{cookiecutter.project_slug}}/.env.example +136 -0
  14. fastapi_gen/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +150 -0
  15. fastapi_gen/template/{{cookiecutter.project_slug}}/.gitignore +108 -0
  16. fastapi_gen/template/{{cookiecutter.project_slug}}/CLAUDE.md +357 -0
  17. fastapi_gen/template/{{cookiecutter.project_slug}}/Makefile +298 -0
  18. fastapi_gen/template/{{cookiecutter.project_slug}}/README.md +723 -0
  19. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.dockerignore +60 -0
  20. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +32 -0
  21. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/Dockerfile +56 -0
  22. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +76 -0
  23. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +30 -0
  24. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
  25. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic.ini +48 -0
  26. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +3 -0
  27. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py +115 -0
  28. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +13 -0
  29. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +202 -0
  30. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +13 -0
  31. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +17 -0
  32. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +1 -0
  33. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +528 -0
  34. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +85 -0
  35. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +10 -0
  36. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +9 -0
  37. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +87 -0
  38. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +448 -0
  39. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +395 -0
  40. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +490 -0
  41. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +227 -0
  42. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +275 -0
  43. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +205 -0
  44. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +168 -0
  45. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +333 -0
  46. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +477 -0
  47. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +46 -0
  48. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +221 -0
  49. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +14 -0
  50. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +88 -0
  51. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +117 -0
  52. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +75 -0
  53. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +28 -0
  54. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +266 -0
  55. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +5 -0
  56. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +23 -0
  57. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +247 -0
  58. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +153 -0
  59. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +122 -0
  60. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +101 -0
  61. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +99 -0
  62. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +23 -0
  63. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +58 -0
  64. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +271 -0
  65. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +102 -0
  66. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +7 -0
  67. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +41 -0
  68. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +31 -0
  69. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +319 -0
  70. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +96 -0
  71. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +126 -0
  72. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +218 -0
  73. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +244 -0
  74. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +113 -0
  75. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py +326 -0
  76. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +9 -0
  77. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +73 -0
  78. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +49 -0
  79. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +154 -0
  80. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +760 -0
  81. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +222 -0
  82. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +318 -0
  83. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +322 -0
  84. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +358 -0
  85. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +50 -0
  86. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +57 -0
  87. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +195 -0
  88. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +52 -0
  89. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +42 -0
  90. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +31 -0
  91. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +64 -0
  92. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +89 -0
  93. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +38 -0
  94. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +797 -0
  95. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +246 -0
  96. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +333 -0
  97. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +432 -0
  98. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +561 -0
  99. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +5 -0
  100. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +64 -0
  101. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +38 -0
  102. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +25 -0
  103. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +106 -0
  104. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +29 -0
  105. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +92 -0
  106. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +1 -0
  107. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +438 -0
  108. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +158 -0
  109. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
  110. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +1 -0
  111. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +1 -0
  112. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +242 -0
  113. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +151 -0
  114. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +113 -0
  115. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +310 -0
  116. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +253 -0
  117. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +151 -0
  118. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +121 -0
  119. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +183 -0
  120. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +173 -0
  121. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +143 -0
  122. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +118 -0
  123. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +181 -0
  124. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +124 -0
  125. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +363 -0
  126. fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +85 -0
  127. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +242 -0
  128. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +31 -0
  129. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +382 -0
  130. fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.yml +241 -0
  131. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.env.example +12 -0
  132. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.gitignore +45 -0
  133. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +19 -0
  134. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +11 -0
  135. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +44 -0
  136. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/README.md +693 -0
  137. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +49 -0
  138. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +134 -0
  139. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +207 -0
  140. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +73 -0
  141. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +14 -0
  142. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +84 -0
  143. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +84 -0
  144. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +76 -0
  145. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/package.json +66 -0
  146. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +101 -0
  147. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +7 -0
  148. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/layout.tsx +11 -0
  149. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/login/page.tsx +5 -0
  150. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/register/page.tsx +5 -0
  151. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/chat/page.tsx +20 -0
  152. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/dashboard/page.tsx +99 -0
  153. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/layout.tsx +17 -0
  154. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/profile/page.tsx +156 -0
  155. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +58 -0
  156. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +24 -0
  157. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +39 -0
  158. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +50 -0
  159. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +54 -0
  160. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +26 -0
  161. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +41 -0
  162. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +108 -0
  163. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +73 -0
  164. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +21 -0
  165. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/auth/callback/page.tsx +96 -0
  166. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +108 -0
  167. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +25 -0
  168. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/page.tsx +73 -0
  169. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +29 -0
  170. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +2 -0
  171. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +120 -0
  172. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +153 -0
  173. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +135 -0
  174. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +73 -0
  175. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +261 -0
  176. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +8 -0
  177. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +63 -0
  178. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +18 -0
  179. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +60 -0
  180. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +32 -0
  181. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +3 -0
  182. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +97 -0
  183. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +45 -0
  184. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +2 -0
  185. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +48 -0
  186. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +7 -0
  187. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +53 -0
  188. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +83 -0
  189. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +35 -0
  190. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +75 -0
  191. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +54 -0
  192. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +82 -0
  193. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +12 -0
  194. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +21 -0
  195. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +21 -0
  196. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +6 -0
  197. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +97 -0
  198. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +203 -0
  199. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +175 -0
  200. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +105 -0
  201. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +32 -0
  202. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +90 -0
  203. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +39 -0
  204. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +78 -0
  205. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +44 -0
  206. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +44 -0
  207. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +33 -0
  208. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +72 -0
  209. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +48 -0
  210. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +65 -0
  211. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +76 -0
  212. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +6 -0
  213. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +44 -0
  214. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +27 -0
  215. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +52 -0
  216. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +81 -0
  217. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +49 -0
  218. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +10 -0
  219. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +28 -0
  220. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +36 -0
  221. fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +56 -0
@@ -0,0 +1,60 @@
1
+ {%- if cookiecutter.enable_docker %}
2
+ # Git
3
+ .git
4
+ .gitignore
5
+
6
+ # Python
7
+ __pycache__
8
+ *.py[cod]
9
+ *$py.class
10
+ *.so
11
+ .Python
12
+ .venv
13
+ venv/
14
+ ENV/
15
+
16
+ # IDE
17
+ .idea
18
+ .vscode
19
+ *.swp
20
+ *.swo
21
+
22
+ # Testing
23
+ .pytest_cache
24
+ .coverage
25
+ htmlcov/
26
+ .tox
27
+ .nox
28
+
29
+ # Documentation
30
+ docs/_build/
31
+ *.md
32
+ !README.md
33
+
34
+ # Build artifacts
35
+ dist/
36
+ build/
37
+ *.egg-info/
38
+
39
+ # Development files
40
+ .env
41
+ .env.local
42
+ *.db
43
+ *.sqlite
44
+
45
+ # Docker
46
+ Dockerfile*
47
+ docker-compose*.yml
48
+ .docker
49
+
50
+ # CI/CD
51
+ .github/
52
+ .gitlab-ci.yml
53
+
54
+ # Misc
55
+ .DS_Store
56
+ Thumbs.db
57
+ *.log
58
+ {%- else %}
59
+ # Docker is disabled
60
+ {%- endif %}
@@ -0,0 +1,32 @@
1
+ {%- if cookiecutter.enable_precommit %}
2
+ repos:
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v5.0.0
5
+ hooks:
6
+ - id: trailing-whitespace
7
+ - id: end-of-file-fixer
8
+ - id: check-yaml
9
+ - id: check-toml
10
+ - id: check-added-large-files
11
+ args: ['--maxkb=1000']
12
+ - id: check-merge-conflict
13
+ - id: detect-private-key
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.8.0
17
+ hooks:
18
+ - id: ruff
19
+ args: [--fix]
20
+ - id: ruff-format
21
+
22
+ - repo: https://github.com/pre-commit/mirrors-mypy
23
+ rev: v1.13.0
24
+ hooks:
25
+ - id: mypy
26
+ additional_dependencies:
27
+ - pydantic>=2.0.0
28
+ - pydantic-settings>=2.0.0
29
+ args: [--ignore-missing-imports]
30
+ {%- else %}
31
+ # Pre-commit is disabled for this project
32
+ {%- endif %}
@@ -0,0 +1,56 @@
1
+ {%- if cookiecutter.enable_docker %}
2
+ # Build stage
3
+ FROM python:{{ cookiecutter.python_version }}-slim AS builder
4
+
5
+ ENV PYTHONUNBUFFERED=1
6
+ ENV PYTHONDONTWRITEBYTECODE=1
7
+ WORKDIR /app
8
+
9
+ # Install uv
10
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
11
+ ENV UV_COMPILE_BYTECODE=1
12
+ ENV UV_LINK_MODE=copy
13
+
14
+ # Install dependencies
15
+ RUN --mount=type=cache,target=/root/.cache/uv \
16
+ --mount=type=bind,source=uv.lock,target=uv.lock \
17
+ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
18
+ uv sync --frozen --no-install-project --no-dev
19
+
20
+ # Copy application
21
+ COPY . /app
22
+
23
+ # Install project
24
+ RUN --mount=type=cache,target=/root/.cache/uv \
25
+ uv sync --frozen --no-dev
26
+
27
+
28
+ # Runtime stage
29
+ FROM python:{{ cookiecutter.python_version }}-slim
30
+
31
+ ENV PYTHONUNBUFFERED=1
32
+ ENV PYTHONDONTWRITEBYTECODE=1
33
+ WORKDIR /app
34
+
35
+ # Copy virtual environment from builder
36
+ COPY --from=builder /app/.venv /app/.venv
37
+ COPY --from=builder /app /app
38
+
39
+ # Add venv to path
40
+ ENV PATH="/app/.venv/bin:$PATH"
41
+
42
+ # Create non-root user
43
+ RUN adduser --disabled-password --gecos "" appuser && \
44
+ chown -R appuser:appuser /app
45
+ USER appuser
46
+
47
+ EXPOSE {{ cookiecutter.backend_port }}
48
+
49
+ # Health check
50
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
51
+ CMD python -c "import httpx; httpx.get('http://localhost:{{ cookiecutter.backend_port }}/api/v1/health')" || exit 1
52
+
53
+ CMD ["python", "-m", "cli.commands", "server", "run", "--host", "0.0.0.0", "--port", "{{ cookiecutter.backend_port }}"]
54
+ {%- else %}
55
+ # Docker is disabled for this project
56
+ {%- endif %}
@@ -0,0 +1,76 @@
1
+ {%- if cookiecutter.use_postgresql or cookiecutter.use_sqlite %}
2
+ """Alembic migration environment."""
3
+ # ruff: noqa: I001 - Imports structured for Jinja2 template conditionals
4
+
5
+ from logging.config import fileConfig
6
+
7
+ from alembic import context
8
+ from sqlalchemy import engine_from_config, pool
9
+
10
+ from app.core.config import settings
11
+ from app.db.base import Base
12
+
13
+ # Import all models here to ensure they are registered with Base.metadata
14
+ {%- if cookiecutter.use_jwt %}
15
+ from app.db.models.user import User # noqa: F401
16
+ {%- endif %}
17
+
18
+ config = context.config
19
+
20
+ if config.config_file_name is not None:
21
+ fileConfig(config.config_file_name)
22
+
23
+ target_metadata = Base.metadata
24
+
25
+
26
+ def get_url() -> str:
27
+ """Get database URL from settings."""
28
+ {%- if cookiecutter.use_postgresql %}
29
+ return settings.DATABASE_URL_SYNC
30
+ {%- else %}
31
+ return settings.DATABASE_URL
32
+ {%- endif %}
33
+
34
+
35
+ def run_migrations_offline() -> None:
36
+ """Run migrations in 'offline' mode."""
37
+ url = get_url()
38
+ context.configure(
39
+ url=url,
40
+ target_metadata=target_metadata,
41
+ literal_binds=True,
42
+ dialect_opts={"paramstyle": "named"},
43
+ )
44
+
45
+ with context.begin_transaction():
46
+ context.run_migrations()
47
+
48
+
49
+ def run_migrations_online() -> None:
50
+ """Run migrations in 'online' mode."""
51
+ configuration = config.get_section(config.config_ini_section)
52
+ configuration["sqlalchemy.url"] = get_url()
53
+
54
+ connectable = engine_from_config(
55
+ configuration,
56
+ prefix="sqlalchemy.",
57
+ poolclass=pool.NullPool,
58
+ )
59
+
60
+ with connectable.connect() as connection:
61
+ context.configure(
62
+ connection=connection,
63
+ target_metadata=target_metadata,
64
+ )
65
+
66
+ with context.begin_transaction():
67
+ context.run_migrations()
68
+
69
+
70
+ if context.is_offline_mode():
71
+ run_migrations_offline()
72
+ else:
73
+ run_migrations_online()
74
+ {%- else %}
75
+ # Alembic - not configured (no SQL database)
76
+ {%- endif %}
@@ -0,0 +1,30 @@
1
+ {%- if cookiecutter.use_postgresql or cookiecutter.use_sqlite %}
2
+ """${message}
3
+
4
+ Revision ID: ${up_revision}
5
+ Revises: ${down_revision | comma,n}
6
+ Create Date: ${create_date}
7
+
8
+ """
9
+ from typing import Sequence, Union
10
+
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+ ${imports if imports else ""}
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision: str = ${repr(up_revision)}
17
+ down_revision: Union[str, None] = ${repr(down_revision)}
18
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
19
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
20
+
21
+
22
+ def upgrade() -> None:
23
+ ${upgrades if upgrades else "pass"}
24
+
25
+
26
+ def downgrade() -> None:
27
+ ${downgrades if downgrades else "pass"}
28
+ {%- else %}
29
+ # Alembic - not configured
30
+ {%- endif %}
@@ -0,0 +1,48 @@
1
+ {%- if cookiecutter.use_postgresql or cookiecutter.use_sqlite %}
2
+ # Alembic Configuration
3
+
4
+ [alembic]
5
+ script_location = alembic
6
+ prepend_sys_path = .
7
+ version_path_separator = os
8
+ # Human-readable migration file names: 2024-01-15_add_users_table.py
9
+ file_template = %%(year)d-%%(month).2d-%%(day).2d_%%(slug)s
10
+
11
+ [post_write_hooks]
12
+
13
+ [loggers]
14
+ keys = root,sqlalchemy,alembic
15
+
16
+ [handlers]
17
+ keys = console
18
+
19
+ [formatters]
20
+ keys = generic
21
+
22
+ [logger_root]
23
+ level = WARN
24
+ handlers = console
25
+ qualname =
26
+
27
+ [logger_sqlalchemy]
28
+ level = WARN
29
+ handlers =
30
+ qualname = sqlalchemy.engine
31
+
32
+ [logger_alembic]
33
+ level = INFO
34
+ handlers =
35
+ qualname = alembic
36
+
37
+ [handler_console]
38
+ class = StreamHandler
39
+ args = (sys.stderr,)
40
+ level = NOTSET
41
+ formatter = generic
42
+
43
+ [formatter_generic]
44
+ format = %(levelname)-5.5s [%(name)s] %(message)s
45
+ datefmt = %H:%M:%S
46
+ {%- else %}
47
+ # Alembic - not configured (no SQL database)
48
+ {%- endif %}
@@ -0,0 +1,3 @@
1
+ """{{ cookiecutter.project_description }}"""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,115 @@
1
+ {%- if cookiecutter.enable_admin_panel and cookiecutter.use_postgresql %}
2
+ """SQLAdmin configuration."""
3
+
4
+ from typing import ClassVar
5
+
6
+ from sqlalchemy import create_engine
7
+ from sqladmin import Admin, ModelView
8
+ {%- if cookiecutter.admin_require_auth %}
9
+ from sqladmin.authentication import AuthenticationBackend
10
+ from starlette.requests import Request
11
+ {%- endif %}
12
+
13
+ from app.core.config import settings
14
+ from app.db.models.user import User
15
+ {%- if cookiecutter.admin_require_auth %}
16
+ from app.core.security import verify_password
17
+ {%- endif %}
18
+
19
+ # SQLAdmin requires a synchronous engine
20
+ sync_engine = create_engine(settings.DATABASE_URL_SYNC, echo=settings.DEBUG)
21
+
22
+ {%- if cookiecutter.admin_require_auth %}
23
+
24
+
25
+ class AdminAuth(AuthenticationBackend):
26
+ """Admin panel authentication backend.
27
+
28
+ Requires superuser credentials to access the admin panel.
29
+ """
30
+
31
+ async def login(self, request: Request) -> bool:
32
+ """Validate admin login credentials."""
33
+ form = await request.form()
34
+ email = form.get("username")
35
+ password = form.get("password")
36
+
37
+ if not email or not password:
38
+ return False
39
+
40
+ # Get user from database
41
+ from sqlalchemy.orm import Session
42
+ with Session(sync_engine) as session:
43
+ user = session.query(User).filter(User.email == email).first()
44
+
45
+ if (
46
+ user
47
+ and verify_password(str(password), user.hashed_password)
48
+ and user.is_superuser
49
+ ):
50
+ # Store user info in session
51
+ request.session["admin_user_id"] = str(user.id)
52
+ request.session["admin_email"] = user.email
53
+ return True
54
+
55
+ return False
56
+
57
+ async def logout(self, request: Request) -> bool:
58
+ """Clear admin session."""
59
+ request.session.clear()
60
+ return True
61
+
62
+ async def authenticate(self, request: Request) -> bool:
63
+ """Check if user is authenticated."""
64
+ admin_user_id = request.session.get("admin_user_id")
65
+ if not admin_user_id:
66
+ return False
67
+
68
+ # Verify user still exists and is superuser
69
+ from sqlalchemy.orm import Session
70
+ with Session(sync_engine) as session:
71
+ user = session.query(User).filter(User.id == admin_user_id).first()
72
+ if user and user.is_superuser and user.is_active:
73
+ return True
74
+
75
+ # User no longer valid, clear session
76
+ request.session.clear()
77
+ return False
78
+ {%- endif %}
79
+
80
+
81
+ class UserAdmin(ModelView, model=User): # type: ignore[call-arg]
82
+ """User admin view."""
83
+
84
+ column_list: ClassVar = [User.id, User.email, User.is_active, User.is_superuser, User.created_at]
85
+ column_searchable_list: ClassVar = [User.email, User.full_name]
86
+ column_sortable_list: ClassVar = [User.id, User.email, User.is_active, User.created_at]
87
+ form_excluded_columns: ClassVar = [User.hashed_password, User.created_at, User.updated_at]
88
+ can_create: ClassVar = True
89
+ can_edit: ClassVar = True
90
+ can_delete: ClassVar = True
91
+ can_view_details: ClassVar = True
92
+
93
+
94
+ def setup_admin(app):
95
+ """Setup SQLAdmin for the FastAPI app."""
96
+ {%- if cookiecutter.admin_require_auth %}
97
+ authentication_backend = AdminAuth(secret_key=settings.SECRET_KEY)
98
+ admin = Admin(
99
+ app,
100
+ sync_engine,
101
+ title="{{ cookiecutter.project_name }} Admin",
102
+ authentication_backend=authentication_backend,
103
+ )
104
+ {%- else %}
105
+ admin = Admin(
106
+ app,
107
+ sync_engine,
108
+ title="{{ cookiecutter.project_name }} Admin",
109
+ )
110
+ {%- endif %}
111
+ admin.add_view(UserAdmin)
112
+ return admin
113
+ {%- else %}
114
+ """Admin panel - not configured."""
115
+ {%- endif %}
@@ -0,0 +1,13 @@
1
+ {%- if cookiecutter.enable_ai_agent %}
2
+ """AI Agents module using PydanticAI.
3
+
4
+ This module contains agents that handle AI-powered interactions.
5
+ Tools are defined in the tools/ subdirectory.
6
+ """
7
+
8
+ from app.agents.assistant import AssistantAgent, Deps
9
+
10
+ __all__ = ["AssistantAgent", "Deps"]
11
+ {%- else %}
12
+ """AI Agents - not configured."""
13
+ {%- endif %}
@@ -0,0 +1,202 @@
1
+ {%- if cookiecutter.enable_ai_agent %}
2
+ """Assistant agent with PydanticAI.
3
+
4
+ The main conversational agent that can be extended with custom tools.
5
+ """
6
+
7
+ import logging
8
+ from dataclasses import dataclass, field
9
+ from typing import Any
10
+
11
+ from pydantic_ai import Agent, RunContext
12
+ from pydantic_ai.messages import (
13
+ ModelRequest,
14
+ ModelResponse,
15
+ SystemPromptPart,
16
+ TextPart,
17
+ UserPromptPart,
18
+ )
19
+ from pydantic_ai.models.openai import OpenAIChatModel
20
+ from pydantic_ai.providers.openai import OpenAIProvider
21
+ from pydantic_ai.settings import ModelSettings
22
+
23
+ from app.agents.tools import get_current_datetime
24
+ from app.core.config import settings
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ @dataclass
30
+ class Deps:
31
+ """Dependencies for the assistant agent.
32
+
33
+ These are passed to tools via RunContext.
34
+ """
35
+
36
+ user_id: str | None = None
37
+ user_name: str | None = None
38
+ metadata: dict[str, Any] = field(default_factory=dict)
39
+
40
+
41
+ class AssistantAgent:
42
+ """Assistant agent wrapper for conversational AI.
43
+
44
+ Encapsulates agent creation and execution with tool support.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ model_name: str | None = None,
50
+ temperature: float | None = None,
51
+ system_prompt: str = "You are a helpful assistant.",
52
+ ):
53
+ self.model_name = model_name or settings.AI_MODEL
54
+ self.temperature = temperature or settings.AI_TEMPERATURE
55
+ self.system_prompt = system_prompt
56
+ self._agent: Agent[Deps, str] | None = None
57
+
58
+ def _create_agent(self) -> Agent[Deps, str]:
59
+ """Create and configure the PydanticAI agent."""
60
+ model = OpenAIChatModel(
61
+ self.model_name,
62
+ provider=OpenAIProvider(api_key=settings.OPENAI_API_KEY),
63
+ )
64
+
65
+ agent = Agent[Deps, str](
66
+ model=model,
67
+ model_settings=ModelSettings(temperature=self.temperature),
68
+ system_prompt=self.system_prompt,
69
+ )
70
+
71
+ self._register_tools(agent)
72
+
73
+ return agent
74
+
75
+ def _register_tools(self, agent: Agent[Deps, str]) -> None:
76
+ """Register all tools on the agent."""
77
+
78
+ @agent.tool
79
+ async def current_datetime(ctx: RunContext[Deps]) -> str:
80
+ """Get the current date and time.
81
+
82
+ Use this tool when you need to know the current date or time.
83
+ """
84
+ return get_current_datetime()
85
+
86
+ @property
87
+ def agent(self) -> Agent[Deps, str]:
88
+ """Get or create the agent instance."""
89
+ if self._agent is None:
90
+ self._agent = self._create_agent()
91
+ return self._agent
92
+
93
+ async def run(
94
+ self,
95
+ user_input: str,
96
+ history: list[dict[str, str]] | None = None,
97
+ deps: Deps | None = None,
98
+ ) -> tuple[str, list[Any], Deps]:
99
+ """Run agent and return the output along with tool call events.
100
+
101
+ Args:
102
+ user_input: User's message.
103
+ history: Conversation history as list of {"role": "...", "content": "..."}.
104
+ deps: Optional dependencies. If not provided, a new Deps will be created.
105
+
106
+ Returns:
107
+ Tuple of (output_text, tool_events, deps).
108
+ """
109
+ model_history: list[ModelRequest | ModelResponse] = []
110
+
111
+ for msg in history or []:
112
+ if msg["role"] == "user":
113
+ model_history.append(ModelRequest(parts=[UserPromptPart(content=msg["content"])]))
114
+ elif msg["role"] == "assistant":
115
+ model_history.append(ModelResponse(parts=[TextPart(content=msg["content"])]))
116
+ elif msg["role"] == "system":
117
+ model_history.append(ModelRequest(parts=[SystemPromptPart(content=msg["content"])]))
118
+
119
+ agent_deps = deps if deps is not None else Deps()
120
+
121
+ logger.info(f"Running agent with user input: {user_input[:100]}...")
122
+ result = await self.agent.run(user_input, deps=agent_deps, message_history=model_history)
123
+
124
+ tool_events: list[Any] = []
125
+ for message in result.all_messages():
126
+ if hasattr(message, "parts"):
127
+ for part in message.parts:
128
+ if hasattr(part, "tool_name"):
129
+ tool_events.append(part)
130
+
131
+ logger.info(f"Agent run complete. Output length: {len(result.output)} chars")
132
+
133
+ return result.output, tool_events, agent_deps
134
+
135
+ async def iter(
136
+ self,
137
+ user_input: str,
138
+ history: list[dict[str, str]] | None = None,
139
+ deps: Deps | None = None,
140
+ ):
141
+ """Stream agent execution with full event access.
142
+
143
+ Args:
144
+ user_input: User's message.
145
+ history: Conversation history.
146
+ deps: Optional dependencies.
147
+
148
+ Yields:
149
+ Agent events for streaming responses.
150
+ """
151
+ model_history: list[ModelRequest | ModelResponse] = []
152
+
153
+ for msg in history or []:
154
+ if msg["role"] == "user":
155
+ model_history.append(ModelRequest(parts=[UserPromptPart(content=msg["content"])]))
156
+ elif msg["role"] == "assistant":
157
+ model_history.append(ModelResponse(parts=[TextPart(content=msg["content"])]))
158
+ elif msg["role"] == "system":
159
+ model_history.append(ModelRequest(parts=[SystemPromptPart(content=msg["content"])]))
160
+
161
+ agent_deps = deps if deps is not None else Deps()
162
+
163
+ async with self.agent.iter(
164
+ user_input,
165
+ deps=agent_deps,
166
+ message_history=model_history,
167
+ ) as run:
168
+ async for event in run:
169
+ yield event
170
+
171
+
172
+ def get_agent() -> AssistantAgent:
173
+ """Factory function to create an AssistantAgent.
174
+
175
+ Returns:
176
+ Configured AssistantAgent instance.
177
+ """
178
+ return AssistantAgent()
179
+
180
+
181
+ async def run_agent(
182
+ user_input: str,
183
+ history: list[dict[str, str]],
184
+ deps: Deps | None = None,
185
+ ) -> tuple[str, list[Any], Deps]:
186
+ """Run agent and return the output along with tool call events.
187
+
188
+ This is a convenience function for backwards compatibility.
189
+
190
+ Args:
191
+ user_input: User's message.
192
+ history: Conversation history.
193
+ deps: Optional dependencies.
194
+
195
+ Returns:
196
+ Tuple of (output_text, tool_events, deps).
197
+ """
198
+ agent = get_agent()
199
+ return await agent.run(user_input, history, deps)
200
+ {%- else %}
201
+ """Assistant agent - not configured."""
202
+ {%- endif %}
@@ -0,0 +1,13 @@
1
+ {%- if cookiecutter.enable_ai_agent %}
2
+ """Agent tools module.
3
+
4
+ This module contains utility functions that can be used as agent tools.
5
+ Tools are registered in the agent definition using @agent.tool decorator.
6
+ """
7
+
8
+ from app.agents.tools.datetime_tool import get_current_datetime
9
+
10
+ __all__ = ["get_current_datetime"]
11
+ {%- else %}
12
+ """Agent tools - not configured."""
13
+ {%- endif %}
@@ -0,0 +1,17 @@
1
+ {%- if cookiecutter.enable_ai_agent %}
2
+ """Date and time utilities for agents."""
3
+
4
+ from datetime import datetime
5
+
6
+
7
+ def get_current_datetime() -> str:
8
+ """Get the current date and time.
9
+
10
+ Returns:
11
+ A string with the current date and time.
12
+ """
13
+ now = datetime.now()
14
+ return f"Current date: {now.strftime('%Y-%m-%d')}, Current time: {now.strftime('%H:%M:%S')}"
15
+ {%- else %}
16
+ """Datetime tools - not configured."""
17
+ {%- endif %}