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,39 @@
1
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
2
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
3
+ import type { User } from "@/types";
4
+
5
+ export async function GET(request: NextRequest) {
6
+ try {
7
+ const accessToken = request.cookies.get("access_token")?.value;
8
+
9
+ if (!accessToken) {
10
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
11
+ }
12
+
13
+ const data = await backendFetch<User>("/api/v1/auth/me", {
14
+ headers: {
15
+ Authorization: `Bearer ${accessToken}`,
16
+ },
17
+ });
18
+
19
+ return NextResponse.json(data);
20
+ } catch (error) {
21
+ if (error instanceof BackendApiError) {
22
+ if (error.status === 401) {
23
+ // Token expired, try to refresh
24
+ return NextResponse.json(
25
+ { detail: "Token expired" },
26
+ { status: 401 }
27
+ );
28
+ }
29
+ return NextResponse.json(
30
+ { detail: "Failed to get user" },
31
+ { status: error.status }
32
+ );
33
+ }
34
+ return NextResponse.json(
35
+ { detail: "Internal server error" },
36
+ { status: 500 }
37
+ );
38
+ }
39
+ }{% endraw %}
@@ -0,0 +1,50 @@
1
+ {%- if cookiecutter.enable_oauth %}
2
+ import { cookies } from "next/headers";
3
+ import { NextRequest, NextResponse } from "next/server";
4
+
5
+ export async function POST(request: NextRequest) {
6
+ try {
7
+ const { accessToken, refreshToken } = await request.json();
8
+
9
+ if (!accessToken || !refreshToken) {
10
+ return NextResponse.json(
11
+ { error: "Missing tokens" },
12
+ { status: 400 }
13
+ );
14
+ }
15
+
16
+ const cookieStore = await cookies();
17
+
18
+ // Set access token cookie
19
+ cookieStore.set("access_token", accessToken, {
20
+ httpOnly: true,
21
+ secure: process.env.NODE_ENV === "production",
22
+ sameSite: "lax",
23
+ maxAge: 60 * 60 * 24, // 24 hours
24
+ path: "/",
25
+ });
26
+
27
+ // Set refresh token cookie
28
+ cookieStore.set("refresh_token", refreshToken, {
29
+ httpOnly: true,
30
+ secure: process.env.NODE_ENV === "production",
31
+ sameSite: "lax",
32
+ maxAge: 60 * 60 * 24 * 7, // 7 days
33
+ path: "/",
34
+ });
35
+
36
+ return NextResponse.json({ success: true });
37
+ } catch {
38
+ return NextResponse.json(
39
+ { error: "Failed to process OAuth callback" },
40
+ { status: 500 }
41
+ );
42
+ }
43
+ }
44
+ {%- else %}
45
+ import { NextResponse } from "next/server";
46
+
47
+ export async function POST() {
48
+ return NextResponse.json({ error: "OAuth not enabled" }, { status: 404 });
49
+ }
50
+ {%- endif %}
@@ -0,0 +1,54 @@
1
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
2
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
3
+ import type { RefreshTokenResponse } from "@/types";
4
+
5
+ export async function POST(request: NextRequest) {
6
+ try {
7
+ const refreshToken = request.cookies.get("refresh_token")?.value;
8
+
9
+ if (!refreshToken) {
10
+ return NextResponse.json(
11
+ { detail: "No refresh token" },
12
+ { status: 401 }
13
+ );
14
+ }
15
+
16
+ const data = await backendFetch<RefreshTokenResponse>(
17
+ "/api/v1/auth/refresh",
18
+ {
19
+ method: "POST",
20
+ body: JSON.stringify({ refresh_token: refreshToken }),
21
+ }
22
+ );
23
+
24
+ const response = NextResponse.json({ message: "Token refreshed" });
25
+
26
+ // Update access token cookie
27
+ response.cookies.set("access_token", data.access_token, {
28
+ httpOnly: true,
29
+ secure: process.env.NODE_ENV === "production",
30
+ sameSite: "lax",
31
+ maxAge: 60 * 15, // 15 minutes
32
+ path: "/",
33
+ });
34
+
35
+ return response;
36
+ } catch (error) {
37
+ if (error instanceof BackendApiError) {
38
+ // Clear cookies on refresh failure
39
+ const response = NextResponse.json(
40
+ { detail: "Session expired" },
41
+ { status: 401 }
42
+ );
43
+
44
+ response.cookies.set("access_token", "", { maxAge: 0, path: "/" });
45
+ response.cookies.set("refresh_token", "", { maxAge: 0, path: "/" });
46
+
47
+ return response;
48
+ }
49
+ return NextResponse.json(
50
+ { detail: "Internal server error" },
51
+ { status: 500 }
52
+ );
53
+ }
54
+ }{% endraw %}
@@ -0,0 +1,26 @@
1
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
2
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
3
+ import type { RegisterResponse } from "@/types";
4
+
5
+ export async function POST(request: NextRequest) {
6
+ try {
7
+ const body = await request.json();
8
+
9
+ const data = await backendFetch<RegisterResponse>("/api/v1/auth/register", {
10
+ method: "POST",
11
+ body: JSON.stringify(body),
12
+ });
13
+
14
+ return NextResponse.json(data, { status: 201 });
15
+ } catch (error) {
16
+ if (error instanceof BackendApiError) {
17
+ const detail =
18
+ (error.data as { detail?: string })?.detail || "Registration failed";
19
+ return NextResponse.json({ detail }, { status: error.status });
20
+ }
21
+ return NextResponse.json(
22
+ { detail: "Internal server error" },
23
+ { status: 500 }
24
+ );
25
+ }
26
+ }{% endraw %}
@@ -0,0 +1,41 @@
1
+ {%- if cookiecutter.enable_conversation_persistence and cookiecutter.use_database %}
2
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
3
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
4
+
5
+ interface RouteParams {
6
+ params: Promise<{ id: string }>;
7
+ }
8
+
9
+ export async function GET(request: NextRequest, { params }: RouteParams) {
10
+ try {
11
+ const accessToken = request.cookies.get("access_token")?.value;
12
+
13
+ if (!accessToken) {
14
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
15
+ }
16
+
17
+ const { id } = await params;
18
+
19
+ const data = await backendFetch(`/api/v1/conversations/${id}/messages`, {
20
+ headers: {
21
+ Authorization: `Bearer ${accessToken}`,
22
+ },
23
+ });
24
+
25
+ return NextResponse.json(data);
26
+ } catch (error) {
27
+ if (error instanceof BackendApiError) {
28
+ return NextResponse.json(
29
+ { detail: error.message || "Failed to fetch messages" },
30
+ { status: error.status }
31
+ );
32
+ }
33
+ return NextResponse.json(
34
+ { detail: "Internal server error" },
35
+ { status: 500 }
36
+ );
37
+ }
38
+ }{% endraw %}
39
+ {%- else %}
40
+ // Conversation messages API route - not configured (enable_conversation_persistence is false)
41
+ {%- endif %}
@@ -0,0 +1,108 @@
1
+ {%- if cookiecutter.enable_conversation_persistence and cookiecutter.use_database %}
2
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
3
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
4
+
5
+ interface RouteParams {
6
+ params: Promise<{ id: string }>;
7
+ }
8
+
9
+ export async function GET(request: NextRequest, { params }: RouteParams) {
10
+ try {
11
+ const accessToken = request.cookies.get("access_token")?.value;
12
+
13
+ if (!accessToken) {
14
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
15
+ }
16
+
17
+ const { id } = await params;
18
+
19
+ const data = await backendFetch(`/api/v1/conversations/${id}`, {
20
+ headers: {
21
+ Authorization: `Bearer ${accessToken}`,
22
+ },
23
+ });
24
+
25
+ return NextResponse.json(data);
26
+ } catch (error) {
27
+ if (error instanceof BackendApiError) {
28
+ return NextResponse.json(
29
+ { detail: error.message || "Failed to fetch conversation" },
30
+ { status: error.status }
31
+ );
32
+ }
33
+ return NextResponse.json(
34
+ { detail: "Internal server error" },
35
+ { status: 500 }
36
+ );
37
+ }
38
+ }
39
+
40
+ export async function PATCH(request: NextRequest, { params }: RouteParams) {
41
+ try {
42
+ const accessToken = request.cookies.get("access_token")?.value;
43
+
44
+ if (!accessToken) {
45
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
46
+ }
47
+
48
+ const { id } = await params;
49
+ const body = await request.json();
50
+
51
+ const data = await backendFetch(`/api/v1/conversations/${id}`, {
52
+ method: "PATCH",
53
+ headers: {
54
+ Authorization: `Bearer ${accessToken}`,
55
+ "Content-Type": "application/json",
56
+ },
57
+ body: JSON.stringify(body),
58
+ });
59
+
60
+ return NextResponse.json(data);
61
+ } catch (error) {
62
+ if (error instanceof BackendApiError) {
63
+ return NextResponse.json(
64
+ { detail: error.message || "Failed to update conversation" },
65
+ { status: error.status }
66
+ );
67
+ }
68
+ return NextResponse.json(
69
+ { detail: "Internal server error" },
70
+ { status: 500 }
71
+ );
72
+ }
73
+ }
74
+
75
+ export async function DELETE(request: NextRequest, { params }: RouteParams) {
76
+ try {
77
+ const accessToken = request.cookies.get("access_token")?.value;
78
+
79
+ if (!accessToken) {
80
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
81
+ }
82
+
83
+ const { id } = await params;
84
+
85
+ await backendFetch(`/api/v1/conversations/${id}`, {
86
+ method: "DELETE",
87
+ headers: {
88
+ Authorization: `Bearer ${accessToken}`,
89
+ },
90
+ });
91
+
92
+ return new NextResponse(null, { status: 204 });
93
+ } catch (error) {
94
+ if (error instanceof BackendApiError) {
95
+ return NextResponse.json(
96
+ { detail: error.message || "Failed to delete conversation" },
97
+ { status: error.status }
98
+ );
99
+ }
100
+ return NextResponse.json(
101
+ { detail: "Internal server error" },
102
+ { status: 500 }
103
+ );
104
+ }
105
+ }{% endraw %}
106
+ {%- else %}
107
+ // Conversation detail API route - not configured (enable_conversation_persistence is false)
108
+ {%- endif %}
@@ -0,0 +1,73 @@
1
+ {%- if cookiecutter.enable_conversation_persistence and cookiecutter.use_database %}
2
+ {% raw %}import { NextRequest, NextResponse } from "next/server";
3
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
4
+
5
+ export async function GET(request: NextRequest) {
6
+ try {
7
+ const accessToken = request.cookies.get("access_token")?.value;
8
+
9
+ if (!accessToken) {
10
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
11
+ }
12
+
13
+ const searchParams = request.nextUrl.searchParams;
14
+ const skip = searchParams.get("skip") || "0";
15
+ const limit = searchParams.get("limit") || "50";
16
+
17
+ const data = await backendFetch(`/api/v1/conversations?skip=${skip}&limit=${limit}`, {
18
+ headers: {
19
+ Authorization: `Bearer ${accessToken}`,
20
+ },
21
+ });
22
+
23
+ return NextResponse.json(data);
24
+ } catch (error) {
25
+ if (error instanceof BackendApiError) {
26
+ return NextResponse.json(
27
+ { detail: error.message || "Failed to fetch conversations" },
28
+ { status: error.status }
29
+ );
30
+ }
31
+ return NextResponse.json(
32
+ { detail: "Internal server error" },
33
+ { status: 500 }
34
+ );
35
+ }
36
+ }
37
+
38
+ export async function POST(request: NextRequest) {
39
+ try {
40
+ const accessToken = request.cookies.get("access_token")?.value;
41
+
42
+ if (!accessToken) {
43
+ return NextResponse.json({ detail: "Not authenticated" }, { status: 401 });
44
+ }
45
+
46
+ const body = await request.json();
47
+
48
+ const data = await backendFetch("/api/v1/conversations", {
49
+ method: "POST",
50
+ headers: {
51
+ Authorization: `Bearer ${accessToken}`,
52
+ "Content-Type": "application/json",
53
+ },
54
+ body: JSON.stringify(body),
55
+ });
56
+
57
+ return NextResponse.json(data, { status: 201 });
58
+ } catch (error) {
59
+ if (error instanceof BackendApiError) {
60
+ return NextResponse.json(
61
+ { detail: error.message || "Failed to create conversation" },
62
+ { status: error.status }
63
+ );
64
+ }
65
+ return NextResponse.json(
66
+ { detail: "Internal server error" },
67
+ { status: 500 }
68
+ );
69
+ }
70
+ }{% endraw %}
71
+ {%- else %}
72
+ // Conversations API route - not configured (enable_conversation_persistence is false)
73
+ {%- endif %}
@@ -0,0 +1,21 @@
1
+ import { NextResponse } from "next/server";
2
+ import { backendFetch, BackendApiError } from "@/lib/server-api";
3
+ import type { HealthResponse } from "@/types";
4
+
5
+ export async function GET() {
6
+ try {
7
+ const data = await backendFetch<HealthResponse>("/api/v1/health");
8
+ return NextResponse.json(data);
9
+ } catch (error) {
10
+ if (error instanceof BackendApiError) {
11
+ return NextResponse.json(
12
+ { detail: "Backend service unavailable" },
13
+ { status: error.status }
14
+ );
15
+ }
16
+ return NextResponse.json(
17
+ { detail: "Internal server error" },
18
+ { status: 500 }
19
+ );
20
+ }
21
+ }
@@ -0,0 +1,96 @@
1
+ {%- if cookiecutter.enable_oauth %}
2
+ "use client";
3
+
4
+ import { useEffect, useState } from "react";
5
+ import { useRouter, useSearchParams } from "next/navigation";
6
+ import { useAuthStore } from "@/stores/auth-store";
7
+ import { Card, CardContent } from "@/components/ui";
8
+ import { ROUTES } from "@/lib/constants";
9
+
10
+ export default function AuthCallbackPage() {
11
+ const router = useRouter();
12
+ const searchParams = useSearchParams();
13
+ const [error, setError] = useState<string | null>(null);
14
+ const { checkAuth } = useAuthStore();
15
+
16
+ useEffect(() => {
17
+ const handleCallback = async () => {
18
+ const accessToken = searchParams.get("access_token");
19
+ const refreshToken = searchParams.get("refresh_token");
20
+ const errorParam = searchParams.get("error");
21
+
22
+ if (errorParam) {
23
+ setError(errorParam);
24
+ setTimeout(() => {
25
+ router.push(ROUTES.LOGIN);
26
+ }, 3000);
27
+ return;
28
+ }
29
+
30
+ if (accessToken && refreshToken) {
31
+ // Store tokens - the API route will handle this
32
+ try {
33
+ const response = await fetch("/api/auth/oauth-callback", {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ },
38
+ body: JSON.stringify({ accessToken, refreshToken }),
39
+ });
40
+
41
+ if (response.ok) {
42
+ // Refresh auth state
43
+ await checkAuth();
44
+ router.push(ROUTES.DASHBOARD);
45
+ } else {
46
+ setError("Failed to complete authentication");
47
+ setTimeout(() => {
48
+ router.push(ROUTES.LOGIN);
49
+ }, 3000);
50
+ }
51
+ } catch {
52
+ setError("Authentication error");
53
+ setTimeout(() => {
54
+ router.push(ROUTES.LOGIN);
55
+ }, 3000);
56
+ }
57
+ } else {
58
+ setError("Missing authentication tokens");
59
+ setTimeout(() => {
60
+ router.push(ROUTES.LOGIN);
61
+ }, 3000);
62
+ }
63
+ };
64
+
65
+ handleCallback();
66
+ }, [searchParams, router, checkAuth]);
67
+
68
+ return (
69
+ <div className="min-h-screen flex items-center justify-center">
70
+ <Card className="w-full max-w-md">
71
+ <CardContent className="pt-6">
72
+ {error ? (
73
+ <div className="text-center">
74
+ <p className="text-destructive mb-2">{error}</p>
75
+ <p className="text-sm text-muted-foreground">
76
+ Redirecting to login...
77
+ </p>
78
+ </div>
79
+ ) : (
80
+ <div className="text-center">
81
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4" />
82
+ <p className="text-muted-foreground">
83
+ Completing authentication...
84
+ </p>
85
+ </div>
86
+ )}
87
+ </CardContent>
88
+ </Card>
89
+ </div>
90
+ );
91
+ }
92
+ {%- else %}
93
+ export default function AuthCallbackPage() {
94
+ return <div>OAuth not enabled</div>;
95
+ }
96
+ {%- endif %}
@@ -0,0 +1,108 @@
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ --color-background: oklch(100% 0 0);
5
+ --color-foreground: oklch(14.5% 0 0);
6
+ --color-card: oklch(100% 0 0);
7
+ --color-card-foreground: oklch(14.5% 0 0);
8
+ --color-popover: oklch(100% 0 0);
9
+ --color-popover-foreground: oklch(14.5% 0 0);
10
+ --color-primary: oklch(20.5% 0 0);
11
+ --color-primary-foreground: oklch(98.5% 0 0);
12
+ --color-secondary: oklch(96.5% 0 0);
13
+ --color-secondary-foreground: oklch(20.5% 0 0);
14
+ --color-muted: oklch(96.5% 0 0);
15
+ --color-muted-foreground: oklch(55.6% 0 0);
16
+ --color-accent: oklch(96.5% 0 0);
17
+ --color-accent-foreground: oklch(20.5% 0 0);
18
+ --color-destructive: oklch(57.7% 0.245 27.325);
19
+ --color-destructive-foreground: oklch(98.5% 0 0);
20
+ --color-border: oklch(91.4% 0 0);
21
+ --color-input: oklch(91.4% 0 0);
22
+ --color-ring: oklch(14.5% 0 0);
23
+ --radius: 0.5rem;
24
+ }
25
+
26
+ /* Dark theme - triggered by system preference or .dark class */
27
+ @media (prefers-color-scheme: dark) {
28
+ :root:not(.light) {
29
+ --color-background: oklch(14.5% 0 0);
30
+ --color-foreground: oklch(98.5% 0 0);
31
+ --color-card: oklch(14.5% 0 0);
32
+ --color-card-foreground: oklch(98.5% 0 0);
33
+ --color-popover: oklch(14.5% 0 0);
34
+ --color-popover-foreground: oklch(98.5% 0 0);
35
+ --color-primary: oklch(98.5% 0 0);
36
+ --color-primary-foreground: oklch(20.5% 0 0);
37
+ --color-secondary: oklch(26.9% 0 0);
38
+ --color-secondary-foreground: oklch(98.5% 0 0);
39
+ --color-muted: oklch(26.9% 0 0);
40
+ --color-muted-foreground: oklch(70.7% 0 0);
41
+ --color-accent: oklch(26.9% 0 0);
42
+ --color-accent-foreground: oklch(98.5% 0 0);
43
+ --color-destructive: oklch(57.7% 0.245 27.325);
44
+ --color-destructive-foreground: oklch(98.5% 0 0);
45
+ --color-border: oklch(26.9% 0 0);
46
+ --color-input: oklch(26.9% 0 0);
47
+ --color-ring: oklch(83.9% 0 0);
48
+ }
49
+ }
50
+
51
+ /* Manual dark mode via .dark class */
52
+ :root.dark {
53
+ --color-background: oklch(14.5% 0 0);
54
+ --color-foreground: oklch(98.5% 0 0);
55
+ --color-card: oklch(14.5% 0 0);
56
+ --color-card-foreground: oklch(98.5% 0 0);
57
+ --color-popover: oklch(14.5% 0 0);
58
+ --color-popover-foreground: oklch(98.5% 0 0);
59
+ --color-primary: oklch(98.5% 0 0);
60
+ --color-primary-foreground: oklch(20.5% 0 0);
61
+ --color-secondary: oklch(26.9% 0 0);
62
+ --color-secondary-foreground: oklch(98.5% 0 0);
63
+ --color-muted: oklch(26.9% 0 0);
64
+ --color-muted-foreground: oklch(70.7% 0 0);
65
+ --color-accent: oklch(26.9% 0 0);
66
+ --color-accent-foreground: oklch(98.5% 0 0);
67
+ --color-destructive: oklch(57.7% 0.245 27.325);
68
+ --color-destructive-foreground: oklch(98.5% 0 0);
69
+ --color-border: oklch(26.9% 0 0);
70
+ --color-input: oklch(26.9% 0 0);
71
+ --color-ring: oklch(83.9% 0 0);
72
+ }
73
+
74
+ @layer base {
75
+ * {
76
+ @apply border-border;
77
+ }
78
+ body {
79
+ @apply bg-background text-foreground;
80
+ }
81
+ }
82
+
83
+ /* Custom scrollbar */
84
+ @layer utilities {
85
+ .scrollbar-thin {
86
+ scrollbar-width: thin;
87
+ scrollbar-color: oklch(50% 0 0 / 0.3) transparent;
88
+ }
89
+
90
+ .scrollbar-thin::-webkit-scrollbar {
91
+ width: 6px;
92
+ height: 6px;
93
+ }
94
+
95
+ .scrollbar-thin::-webkit-scrollbar-track {
96
+ background: transparent;
97
+ border-radius: 3px;
98
+ }
99
+
100
+ .scrollbar-thin::-webkit-scrollbar-thumb {
101
+ background: oklch(50% 0 0 / 0.3);
102
+ border-radius: 3px;
103
+ }
104
+
105
+ .scrollbar-thin::-webkit-scrollbar-thumb:hover {
106
+ background: oklch(50% 0 0 / 0.5);
107
+ }
108
+ }
@@ -0,0 +1,25 @@
1
+ import type { Metadata } from "next";
2
+ import { Inter } from "next/font/google";
3
+ import "./globals.css";
4
+ import { Providers } from "./providers";
5
+
6
+ const inter = Inter({ subsets: ["latin"] });
7
+
8
+ export const metadata: Metadata = {
9
+ title: "{{ cookiecutter.project_name }}",
10
+ description: "{{ cookiecutter.project_description }}",
11
+ };
12
+
13
+ export default function RootLayout({
14
+ children,
15
+ }: Readonly<{
16
+ children: React.ReactNode;
17
+ }>) {
18
+ return (
19
+ <html lang="en" suppressHydrationWarning>
20
+ <body className={inter.className}>
21
+ <Providers>{children}</Providers>
22
+ </body>
23
+ </html>
24
+ );
25
+ }