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,76 @@
1
+ import type { NextConfig } from "next";
2
+ {%- if cookiecutter.enable_i18n %}
3
+ import createNextIntlPlugin from 'next-intl/plugin';
4
+
5
+ const withNextIntl = createNextIntlPlugin('./src/i18n.ts');
6
+ {%- endif %}
7
+
8
+ // Content Security Policy directives
9
+ const ContentSecurityPolicy = `
10
+ default-src 'self';
11
+ script-src 'self' 'unsafe-eval' 'unsafe-inline';
12
+ style-src 'self' 'unsafe-inline';
13
+ img-src 'self' blob: data: https:;
14
+ font-src 'self' data:;
15
+ connect-src 'self' ws: wss: http://localhost:* https://localhost:*;
16
+ frame-ancestors 'none';
17
+ base-uri 'self';
18
+ form-action 'self';
19
+ `.replace(/\n/g, " ").trim();
20
+
21
+ const securityHeaders = [
22
+ {
23
+ key: "Content-Security-Policy",
24
+ value: ContentSecurityPolicy,
25
+ },
26
+ {
27
+ key: "X-Content-Type-Options",
28
+ value: "nosniff",
29
+ },
30
+ {
31
+ key: "X-Frame-Options",
32
+ value: "DENY",
33
+ },
34
+ {
35
+ key: "X-XSS-Protection",
36
+ value: "1; mode=block",
37
+ },
38
+ {
39
+ key: "Referrer-Policy",
40
+ value: "strict-origin-when-cross-origin",
41
+ },
42
+ {
43
+ key: "Permissions-Policy",
44
+ value: "camera=(), microphone=(), geolocation=()",
45
+ },
46
+ ];
47
+
48
+ const nextConfig: NextConfig = {
49
+ output: "standalone",
50
+
51
+ // Security headers
52
+ async headers() {
53
+ return [
54
+ {
55
+ source: "/(.*)",
56
+ headers: securityHeaders,
57
+ },
58
+ ];
59
+ },
60
+
61
+ // Environment variables available on the server side only
62
+ serverRuntimeConfig: {
63
+ apiUrl: process.env.BACKEND_URL || "http://localhost:{{ cookiecutter.backend_port }}",
64
+ },
65
+
66
+ // Environment variables available on both server and client
67
+ publicRuntimeConfig: {
68
+ appName: "{{ cookiecutter.project_name }}",
69
+ },
70
+ };
71
+
72
+ {%- if cookiecutter.enable_i18n %}
73
+ export default withNextIntl(nextConfig);
74
+ {%- else %}
75
+ export default nextConfig;
76
+ {%- endif %}
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "{{ cookiecutter.project_slug }}-frontend",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev -p {{ cookiecutter.frontend_port }}",
7
+ "build": "next build",
8
+ "start": "next start -p {{ cookiecutter.frontend_port }}",
9
+ "lint": "next lint",
10
+ "lint:fix": "next lint --fix",
11
+ "format": "prettier --write .",
12
+ "format:check": "prettier --check .",
13
+ "type-check": "tsc --noEmit",
14
+ "test:e2e": "playwright test",
15
+ "test:e2e:ui": "playwright test --ui",
16
+ "test:e2e:headed": "playwright test --headed",
17
+ "test:e2e:debug": "playwright test --debug",
18
+ "test:e2e:report": "playwright show-report",
19
+ "test": "vitest",
20
+ "test:run": "vitest run",
21
+ "test:coverage": "vitest run --coverage",
22
+ "test:ui": "vitest --ui"
23
+ },
24
+ "dependencies": {
25
+ "next": "^15.1.0",
26
+ "react": "^19.0.0",
27
+ "react-dom": "^19.0.0",
28
+ "@tanstack/react-query": "^5.62.0",
29
+ "zustand": "^5.0.2",
30
+ "nanoid": "^5.0.9",
31
+ "lucide-react": "^0.468.0",
32
+ "clsx": "^2.1.1",
33
+ "tailwind-merge": "^2.6.0",
34
+ {%- if cookiecutter.enable_logfire %}
35
+ "@vercel/otel": "^1.10.0",
36
+ "@opentelemetry/api": "^1.9.0",
37
+ {%- endif %}
38
+ {%- if cookiecutter.enable_i18n %}
39
+ "next-intl": "^3.25.3",
40
+ {%- endif %}
41
+ "class-variance-authority": "^0.7.1"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.7.2",
45
+ "@types/node": "^22.10.2",
46
+ "@types/react": "^19.0.1",
47
+ "@types/react-dom": "^19.0.2",
48
+ "tailwindcss": "^4.0.0-beta.8",
49
+ "@tailwindcss/postcss": "^4.0.0-beta.8",
50
+ "postcss": "^8.4.49",
51
+ "eslint": "^9.17.0",
52
+ "eslint-config-next": "^15.1.0",
53
+ "eslint-config-prettier": "^9.1.0",
54
+ "prettier": "^3.4.2",
55
+ "prettier-plugin-tailwindcss": "^0.6.9",
56
+ "@playwright/test": "^1.49.1",
57
+ "vitest": "^2.1.8",
58
+ "@vitejs/plugin-react": "^4.3.4",
59
+ "@testing-library/react": "^16.1.0",
60
+ "@testing-library/jest-dom": "^6.6.3",
61
+ "@testing-library/user-event": "^14.5.2",
62
+ "jsdom": "^25.0.1",
63
+ "@vitest/coverage-v8": "^2.1.8",
64
+ "@vitest/ui": "^2.1.8"
65
+ }
66
+ }
@@ -0,0 +1,101 @@
1
+ {%- if cookiecutter.use_frontend %}
2
+ import { defineConfig, devices } from "@playwright/test";
3
+
4
+ /**
5
+ * Playwright E2E test configuration.
6
+ *
7
+ * See https://playwright.dev/docs/test-configuration.
8
+ */
9
+ export default defineConfig({
10
+ testDir: "./e2e",
11
+ /* Run tests in files in parallel */
12
+ fullyParallel: true,
13
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
14
+ forbidOnly: !!process.env.CI,
15
+ /* Retry on CI only */
16
+ retries: process.env.CI ? 2 : 0,
17
+ /* Opt out of parallel tests on CI. */
18
+ workers: process.env.CI ? 1 : undefined,
19
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
20
+ reporter: [
21
+ ["list"],
22
+ ["html", { outputFolder: "playwright-report" }],
23
+ ],
24
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
25
+ use: {
26
+ /* Base URL to use in actions like `await page.goto('/')`. */
27
+ baseURL: process.env.PLAYWRIGHT_BASE_URL || "http://localhost:{{ cookiecutter.frontend_port }}",
28
+
29
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30
+ trace: "on-first-retry",
31
+
32
+ /* Capture screenshot on failure */
33
+ screenshot: "only-on-failure",
34
+
35
+ /* Video recording on failure */
36
+ video: "on-first-retry",
37
+ },
38
+
39
+ /* Configure projects for major browsers */
40
+ projects: [
41
+ /* Authentication setup - runs first */
42
+ {
43
+ name: "setup",
44
+ testMatch: /.*\.setup\.ts/,
45
+ },
46
+
47
+ {
48
+ name: "chromium",
49
+ use: {
50
+ ...devices["Desktop Chrome"],
51
+ },
52
+ dependencies: ["setup"],
53
+ },
54
+
55
+ {
56
+ name: "firefox",
57
+ use: {
58
+ ...devices["Desktop Firefox"],
59
+ },
60
+ dependencies: ["setup"],
61
+ },
62
+
63
+ {
64
+ name: "webkit",
65
+ use: {
66
+ ...devices["Desktop Safari"],
67
+ },
68
+ dependencies: ["setup"],
69
+ },
70
+
71
+ /* Test against mobile viewports. */
72
+ {
73
+ name: "Mobile Chrome",
74
+ use: {
75
+ ...devices["Pixel 5"],
76
+ },
77
+ dependencies: ["setup"],
78
+ },
79
+ {
80
+ name: "Mobile Safari",
81
+ use: {
82
+ ...devices["iPhone 12"],
83
+ },
84
+ dependencies: ["setup"],
85
+ },
86
+ ],
87
+
88
+ /* Run your local dev server before starting the tests */
89
+ webServer: process.env.CI
90
+ ? undefined
91
+ : {
92
+ command: "bun run dev",
93
+ url: "http://localhost:{{ cookiecutter.frontend_port }}",
94
+ reuseExistingServer: !process.env.CI,
95
+ timeout: 120 * 1000,
96
+ },
97
+ });
98
+ {%- else %}
99
+ /* Playwright config - frontend not configured */
100
+ export {};
101
+ {%- endif %}
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,11 @@
1
+ export default function AuthLayout({
2
+ children,
3
+ }: {
4
+ children: React.ReactNode;
5
+ }) {
6
+ return (
7
+ <div className="min-h-screen flex items-center justify-center bg-background px-4">
8
+ {children}
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,5 @@
1
+ import { LoginForm } from "@/components/auth";
2
+
3
+ export default function LoginPage() {
4
+ return <LoginForm />;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { RegisterForm } from "@/components/auth";
2
+
3
+ export default function RegisterPage() {
4
+ return <RegisterForm />;
5
+ }
@@ -0,0 +1,20 @@
1
+ {%- if cookiecutter.enable_conversation_persistence and cookiecutter.use_database %}
2
+ import { ChatContainer, ConversationSidebar } from "@/components/chat";
3
+
4
+ export default function ChatPage() {
5
+ return (
6
+ <div className="flex h-full">
7
+ <ConversationSidebar />
8
+ <div className="flex-1 min-w-0">
9
+ <ChatContainer />
10
+ </div>
11
+ </div>
12
+ );
13
+ }
14
+ {%- else %}
15
+ import { ChatContainer } from "@/components/chat";
16
+
17
+ export default function ChatPage() {
18
+ return <ChatContainer />;
19
+ }
20
+ {%- endif %}
@@ -0,0 +1,99 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui";
5
+ import { apiClient } from "@/lib/api-client";
6
+ import { useAuth } from "@/hooks";
7
+ import type { HealthResponse } from "@/types";
8
+ import { CheckCircle, XCircle, Loader2 } from "lucide-react";
9
+
10
+ export default function DashboardPage() {
11
+ const { user } = useAuth();
12
+ const [health, setHealth] = useState<HealthResponse | null>(null);
13
+ const [healthLoading, setHealthLoading] = useState(true);
14
+ const [healthError, setHealthError] = useState(false);
15
+
16
+ useEffect(() => {
17
+ const checkHealth = async () => {
18
+ try {
19
+ const data = await apiClient.get<HealthResponse>("/health");
20
+ setHealth(data);
21
+ setHealthError(false);
22
+ } catch {
23
+ setHealthError(true);
24
+ } finally {
25
+ setHealthLoading(false);
26
+ }
27
+ };
28
+
29
+ checkHealth();
30
+ }, []);
31
+
32
+ return (
33
+ <div className="space-y-6">
34
+ <div>
35
+ <h1 className="text-3xl font-bold">Dashboard</h1>
36
+ <p className="text-muted-foreground">
37
+ Welcome back{user?.name ? `, ${user.name}` : ""}!
38
+ </p>
39
+ </div>
40
+
41
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
42
+ <Card>
43
+ <CardHeader>
44
+ <CardTitle className="flex items-center gap-2">
45
+ API Status
46
+ {healthLoading ? (
47
+ <Loader2 className="h-4 w-4 animate-spin" />
48
+ ) : healthError ? (
49
+ <XCircle className="h-4 w-4 text-destructive" />
50
+ ) : (
51
+ <CheckCircle className="h-4 w-4 text-green-500" />
52
+ )}
53
+ </CardTitle>
54
+ </CardHeader>
55
+ <CardContent>
56
+ {healthLoading ? (
57
+ <p className="text-muted-foreground">Checking...</p>
58
+ ) : healthError ? (
59
+ <p className="text-destructive">Backend unavailable</p>
60
+ ) : (
61
+ <div className="space-y-1">
62
+ <p className="text-sm">
63
+ Status: <span className="font-medium">{health?.status}</span>
64
+ </p>
65
+ {health?.version && (
66
+ <p className="text-sm text-muted-foreground">
67
+ Version: {health.version}
68
+ </p>
69
+ )}
70
+ </div>
71
+ )}
72
+ </CardContent>
73
+ </Card>
74
+
75
+ <Card>
76
+ <CardHeader>
77
+ <CardTitle>Your Account</CardTitle>
78
+ </CardHeader>
79
+ <CardContent>
80
+ {user ? (
81
+ <div className="space-y-1">
82
+ <p className="text-sm">
83
+ Email: <span className="font-medium">{user.email}</span>
84
+ </p>
85
+ {user.name && (
86
+ <p className="text-sm">
87
+ Name: <span className="font-medium">{user.name}</span>
88
+ </p>
89
+ )}
90
+ </div>
91
+ ) : (
92
+ <p className="text-muted-foreground">Loading...</p>
93
+ )}
94
+ </CardContent>
95
+ </Card>
96
+ </div>
97
+ </div>
98
+ );
99
+ }
@@ -0,0 +1,17 @@
1
+ import { Header, Sidebar } from "@/components/layout";
2
+
3
+ export default function DashboardLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return (
9
+ <div className="flex h-screen overflow-hidden">
10
+ <Sidebar />
11
+ <div className="flex-1 flex flex-col min-w-0">
12
+ <Header />
13
+ <main className="flex-1 overflow-hidden">{children}</main>
14
+ </div>
15
+ </div>
16
+ );
17
+ }
@@ -0,0 +1,156 @@
1
+ {%- if cookiecutter.use_frontend and cookiecutter.use_jwt %}
2
+ "use client";
3
+
4
+ import { useState } from "react";
5
+ import { useAuth } from "@/hooks";
6
+ import { Button, Card, Input, Label, Badge } from "@/components/ui";
7
+ import { ThemeToggle } from "@/components/theme";
8
+ import { User, Mail, Calendar, Shield, Settings } from "lucide-react";
9
+
10
+ export default function ProfilePage() {
11
+ const { user, isAuthenticated, logout } = useAuth();
12
+ const [isEditing, setIsEditing] = useState(false);
13
+
14
+ if (!isAuthenticated || !user) {
15
+ return (
16
+ <div className="flex min-h-[50vh] items-center justify-center">
17
+ <Card className="p-8 text-center">
18
+ <p className="text-muted-foreground">Please log in to view your profile.</p>
19
+ </Card>
20
+ </div>
21
+ );
22
+ }
23
+
24
+ return (
25
+ <div className="container mx-auto max-w-4xl py-8">
26
+ <div className="mb-8">
27
+ <h1 className="text-3xl font-bold tracking-tight">Profile</h1>
28
+ <p className="text-muted-foreground">
29
+ Manage your account settings and preferences
30
+ </p>
31
+ </div>
32
+
33
+ <div className="grid gap-6">
34
+ {/* Profile Card */}
35
+ <Card className="p-6">
36
+ <div className="flex items-start justify-between">
37
+ <div className="flex items-center gap-4">
38
+ <div className="flex h-16 w-16 items-center justify-center rounded-full bg-primary/10">
39
+ <User className="h-8 w-8 text-primary" />
40
+ </div>
41
+ <div>
42
+ <h2 className="text-xl font-semibold">{user.email}</h2>
43
+ <div className="mt-1 flex items-center gap-2">
44
+ {user.is_superuser && (
45
+ <Badge variant="secondary">
46
+ <Shield className="mr-1 h-3 w-3" />
47
+ Admin
48
+ </Badge>
49
+ )}
50
+ {user.is_active && (
51
+ <Badge variant="outline" className="text-green-600">
52
+ Active
53
+ </Badge>
54
+ )}
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <Button
59
+ variant="outline"
60
+ size="sm"
61
+ onClick={() => setIsEditing(!isEditing)}
62
+ >
63
+ <Settings className="mr-2 h-4 w-4" />
64
+ {isEditing ? "Cancel" : "Edit"}
65
+ </Button>
66
+ </div>
67
+ </Card>
68
+
69
+ {/* Account Information */}
70
+ <Card className="p-6">
71
+ <h3 className="mb-4 text-lg font-semibold">Account Information</h3>
72
+ <div className="grid gap-4">
73
+ <div className="grid gap-2">
74
+ <Label htmlFor="email" className="flex items-center gap-2">
75
+ <Mail className="h-4 w-4 text-muted-foreground" />
76
+ Email Address
77
+ </Label>
78
+ <Input
79
+ id="email"
80
+ type="email"
81
+ value={user.email}
82
+ disabled={!isEditing}
83
+ className={!isEditing ? "bg-muted" : ""}
84
+ />
85
+ </div>
86
+
87
+ {user.created_at && (
88
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
89
+ <Calendar className="h-4 w-4" />
90
+ <span>Member since {new Date(user.created_at).toLocaleDateString()}</span>
91
+ </div>
92
+ )}
93
+ </div>
94
+
95
+ {isEditing && (
96
+ <div className="mt-4 flex justify-end gap-2">
97
+ <Button variant="outline" onClick={() => setIsEditing(false)}>
98
+ Cancel
99
+ </Button>
100
+ <Button>Save Changes</Button>
101
+ </div>
102
+ )}
103
+ </Card>
104
+
105
+ {/* Preferences */}
106
+ <Card className="p-6">
107
+ <h3 className="mb-4 text-lg font-semibold">Preferences</h3>
108
+ <div className="flex items-center justify-between">
109
+ <div>
110
+ <p className="font-medium">Theme</p>
111
+ <p className="text-sm text-muted-foreground">
112
+ Choose your preferred color scheme
113
+ </p>
114
+ </div>
115
+ <ThemeToggle variant="dropdown" />
116
+ </div>
117
+ </Card>
118
+
119
+ {/* Danger Zone */}
120
+ <Card className="border-destructive/50 p-6">
121
+ <h3 className="mb-4 text-lg font-semibold text-destructive">
122
+ Danger Zone
123
+ </h3>
124
+ <div className="flex items-center justify-between">
125
+ <div>
126
+ <p className="font-medium">Sign out</p>
127
+ <p className="text-sm text-muted-foreground">
128
+ Sign out from your account on this device
129
+ </p>
130
+ </div>
131
+ <Button variant="destructive" onClick={logout}>
132
+ Sign Out
133
+ </Button>
134
+ </div>
135
+ </Card>
136
+ </div>
137
+ </div>
138
+ );
139
+ }
140
+ {%- elif cookiecutter.use_frontend %}
141
+ export default function ProfilePage() {
142
+ return (
143
+ <div className="container mx-auto py-8">
144
+ <h1 className="text-3xl font-bold">Profile</h1>
145
+ <p className="mt-4 text-muted-foreground">
146
+ User authentication is not enabled.
147
+ </p>
148
+ </div>
149
+ );
150
+ }
151
+ {%- else %}
152
+ /* Profile page - frontend not configured */
153
+ export default function ProfilePage() {
154
+ return null;
155
+ }
156
+ {%- endif %}
@@ -0,0 +1,58 @@
1
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
2
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
3
+ import type { LoginResponse } from "@/types";
4
+
5
+ export async function POST(request: NextRequest) {
6
+ try {
7
+ const body = await request.json();
8
+
9
+ // Backend expects OAuth2 form data format
10
+ const formData = new URLSearchParams();
11
+ formData.append("username", body.email);
12
+ formData.append("password", body.password);
13
+
14
+ const data = await backendFetch<LoginResponse>("/api/v1/auth/login", {
15
+ method: "POST",
16
+ headers: {
17
+ "Content-Type": "application/x-www-form-urlencoded",
18
+ },
19
+ body: formData.toString(),
20
+ });
21
+
22
+ // Set HTTP-only cookies for tokens
23
+ const response = NextResponse.json({
24
+ user: data.user,
25
+ message: "Login successful",
26
+ });
27
+
28
+ // Set access token cookie (short-lived)
29
+ response.cookies.set("access_token", data.access_token, {
30
+ httpOnly: true,
31
+ secure: process.env.NODE_ENV === "production",
32
+ sameSite: "lax",
33
+ maxAge: 60 * 15, // 15 minutes
34
+ path: "/",
35
+ });
36
+
37
+ // Set refresh token cookie (long-lived)
38
+ response.cookies.set("refresh_token", data.refresh_token, {
39
+ httpOnly: true,
40
+ secure: process.env.NODE_ENV === "production",
41
+ sameSite: "lax",
42
+ maxAge: 60 * 60 * 24 * 7, // 7 days
43
+ path: "/",
44
+ });
45
+
46
+ return response;
47
+ } catch (error) {
48
+ if (error instanceof BackendApiError) {
49
+ const detail =
50
+ (error.data as { detail?: string })?.detail || "Login failed";
51
+ return NextResponse.json({ detail }, { status: error.status });
52
+ }
53
+ return NextResponse.json(
54
+ { detail: "Internal server error" },
55
+ { status: 500 }
56
+ );
57
+ }
58
+ }{% endraw %}
@@ -0,0 +1,24 @@
1
+ import { NextResponse } from "next/server";
2
+
3
+ export async function POST() {
4
+ const response = NextResponse.json({ message: "Logged out successfully" });
5
+
6
+ // Clear auth cookies
7
+ response.cookies.set("access_token", "", {
8
+ httpOnly: true,
9
+ secure: process.env.NODE_ENV === "production",
10
+ sameSite: "lax",
11
+ maxAge: 0,
12
+ path: "/",
13
+ });
14
+
15
+ response.cookies.set("refresh_token", "", {
16
+ httpOnly: true,
17
+ secure: process.env.NODE_ENV === "production",
18
+ sameSite: "lax",
19
+ maxAge: 0,
20
+ path: "/",
21
+ });
22
+
23
+ return response;
24
+ }