fastapi-fullstack 0.1.12__tar.gz → 0.1.14__tar.gz

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 (257) hide show
  1. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/PKG-INFO +4 -2
  2. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/README.md +3 -1
  3. fastapi_fullstack-0.1.14/fastapi_gen/__init__.py +8 -0
  4. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/fastapi_gen/config.py +77 -0
  5. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/fastapi_gen/generator.py +34 -14
  6. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/fastapi_gen/prompts.py +126 -31
  7. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/pyproject.toml +7 -1
  8. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/hooks/post_gen_project.py +55 -2
  9. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/admin.py +1 -1
  10. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/langchain_assistant.py +4 -3
  11. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +3 -7
  12. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +2 -2
  13. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +7 -2
  14. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +12 -7
  15. fastapi_fullstack-0.1.14/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +14 -0
  16. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +10 -2
  17. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +1 -2
  18. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/main.py +8 -2
  19. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +6 -0
  20. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +4 -4
  21. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +9 -9
  22. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +6 -6
  23. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +7 -7
  24. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +6 -0
  25. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +39 -0
  26. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/.env.example +5 -0
  27. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +1 -1
  28. fastapi_fullstack-0.1.12/fastapi_gen/__init__.py +0 -3
  29. fastapi_fullstack-0.1.12/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +0 -7
  30. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/.gitignore +0 -0
  31. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/LICENSE +0 -0
  32. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/fastapi_gen/cli.py +0 -0
  33. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/VARIABLES.md +0 -0
  34. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/cookiecutter.json +0 -0
  35. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/.env.prod.example +0 -0
  36. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +0 -0
  37. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/.gitignore +0 -0
  38. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/.gitlab-ci.yml +0 -0
  39. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/AGENTS.md +0 -0
  40. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/CLAUDE.md +0 -0
  41. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/Makefile +0 -0
  42. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/README.md +0 -0
  43. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/.dockerignore +0 -0
  44. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/.env.example +0 -0
  45. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +0 -0
  46. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/Dockerfile +0 -0
  47. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +0 -0
  48. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +0 -0
  49. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
  50. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/alembic.ini +0 -0
  51. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +0 -0
  52. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +0 -0
  53. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +0 -0
  54. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/crewai_assistant.py +0 -0
  55. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/langgraph_assistant.py +0 -0
  56. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/prompts.py +0 -0
  57. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +0 -0
  58. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +0 -0
  59. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +0 -0
  60. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +0 -0
  61. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +0 -0
  62. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +0 -0
  63. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +0 -0
  64. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +0 -0
  65. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +0 -0
  66. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +0 -0
  67. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +0 -0
  68. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +0 -0
  69. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +0 -0
  70. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +0 -0
  71. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +0 -0
  72. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +0 -0
  73. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +0 -0
  74. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +0 -0
  75. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +0 -0
  76. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +0 -0
  77. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +0 -0
  78. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +0 -0
  79. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +0 -0
  80. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +0 -0
  81. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +0 -0
  82. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +0 -0
  83. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +0 -0
  84. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +0 -0
  85. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +0 -0
  86. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +0 -0
  87. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +0 -0
  88. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +0 -0
  89. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +0 -0
  90. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +0 -0
  91. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +0 -0
  92. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +0 -0
  93. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +0 -0
  94. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +0 -0
  95. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +0 -0
  96. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +0 -0
  97. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +0 -0
  98. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +0 -0
  99. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +0 -0
  100. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +0 -0
  101. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +0 -0
  102. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +0 -0
  103. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +0 -0
  104. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +0 -0
  105. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +0 -0
  106. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +0 -0
  107. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +0 -0
  108. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +0 -0
  109. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +0 -0
  110. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +0 -0
  111. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +0 -0
  112. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +0 -0
  113. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +0 -0
  114. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/arq_app.py +0 -0
  115. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +0 -0
  116. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +0 -0
  117. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +0 -0
  118. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +0 -0
  119. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +0 -0
  120. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +0 -0
  121. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +0 -0
  122. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +0 -0
  123. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +0 -0
  124. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
  125. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +0 -0
  126. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +0 -0
  127. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +0 -0
  128. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +0 -0
  129. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +0 -0
  130. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +0 -0
  131. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_metrics.py +0 -0
  132. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +0 -0
  133. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +0 -0
  134. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_admin.py +0 -0
  135. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +0 -0
  136. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +0 -0
  137. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +0 -0
  138. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +0 -0
  139. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +0 -0
  140. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +0 -0
  141. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +0 -0
  142. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +0 -0
  143. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +0 -0
  144. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +0 -0
  145. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docker-compose.yml +0 -0
  146. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docs/adding_features.md +0 -0
  147. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docs/architecture.md +0 -0
  148. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docs/patterns.md +0 -0
  149. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/docs/testing.md +0 -0
  150. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/.dockerignore +0 -0
  151. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/.gitignore +0 -0
  152. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +0 -0
  153. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +0 -0
  154. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +0 -0
  155. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/README.md +0 -0
  156. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +0 -0
  157. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +0 -0
  158. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +0 -0
  159. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +0 -0
  160. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +0 -0
  161. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +0 -0
  162. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +0 -0
  163. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +0 -0
  164. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/package.json +0 -0
  165. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +0 -0
  166. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +0 -0
  167. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/layout.tsx +0 -0
  168. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/login/page.tsx +0 -0
  169. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/register/page.tsx +0 -0
  170. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/chat/page.tsx +0 -0
  171. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/dashboard/page.tsx +0 -0
  172. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/layout.tsx +0 -0
  173. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/profile/page.tsx +0 -0
  174. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/auth/callback/page.tsx +0 -0
  175. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/layout.tsx +0 -0
  176. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/page.tsx +0 -0
  177. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +0 -0
  178. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +0 -0
  179. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +0 -0
  180. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +0 -0
  181. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +0 -0
  182. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +0 -0
  183. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +0 -0
  184. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +0 -0
  185. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +0 -0
  186. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +0 -0
  187. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +0 -0
  188. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +0 -0
  189. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +0 -0
  190. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +0 -0
  191. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +0 -0
  192. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +0 -0
  193. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +0 -0
  194. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +0 -0
  195. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +0 -0
  196. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/copy-button.tsx +0 -0
  197. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +0 -0
  198. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/local-conversation-sidebar.tsx +0 -0
  199. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/markdown-content.tsx +0 -0
  200. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +0 -0
  201. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +0 -0
  202. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +0 -0
  203. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +0 -0
  204. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +0 -0
  205. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +0 -0
  206. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +0 -0
  207. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +0 -0
  208. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +0 -0
  209. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +0 -0
  210. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +0 -0
  211. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +0 -0
  212. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +0 -0
  213. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +0 -0
  214. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +0 -0
  215. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +0 -0
  216. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +0 -0
  217. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +0 -0
  218. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +0 -0
  219. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/sheet.tsx +0 -0
  220. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +0 -0
  221. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +0 -0
  222. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +0 -0
  223. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +0 -0
  224. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +0 -0
  225. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +0 -0
  226. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +0 -0
  227. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +0 -0
  228. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +0 -0
  229. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +0 -0
  230. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +0 -0
  231. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +0 -0
  232. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +0 -0
  233. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +0 -0
  234. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-sidebar-store.ts +0 -0
  235. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +0 -0
  236. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +0 -0
  237. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +0 -0
  238. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/local-chat-store.ts +0 -0
  239. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/sidebar-store.ts +0 -0
  240. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +0 -0
  241. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +0 -0
  242. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +0 -0
  243. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +0 -0
  244. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +0 -0
  245. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +0 -0
  246. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +0 -0
  247. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +0 -0
  248. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +0 -0
  249. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/configmap.yaml +0 -0
  250. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/deployment.yaml +0 -0
  251. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/ingress.yaml +0 -0
  252. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/kustomization.yaml +0 -0
  253. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/namespace.yaml +0 -0
  254. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/secret.yaml +0 -0
  255. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/kubernetes/service.yaml +0 -0
  256. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/nginx/nginx.conf +0 -0
  257. {fastapi_fullstack-0.1.12 → fastapi_fullstack-0.1.14}/template/{{cookiecutter.project_slug}}/nginx/ssl/.gitkeep +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-fullstack
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Full-stack FastAPI + Next.js template generator with PydanticAI/LangChain agents, WebSocket streaming, 20+ enterprise integrations, and Logfire/LangSmith observability. Ship AI apps fast. CLI tool to generate production-ready FastAPI + Next.js projects with AI agents, auth, and observability.
5
5
  Project-URL: Homepage, https://github.com/vstorm-co/full-stack-fastapi-nextjs-llm-template
6
6
  Project-URL: Documentation, https://github.com/vstorm-co/full-stack-fastapi-nextjs-llm-template#readme
@@ -199,8 +199,10 @@ make docker-db
199
199
 
200
200
  #### 3. Create and apply database migrations
201
201
 
202
+ > ⚠️ **Important:** Both commands are required! `db-migrate` creates the migration file, `db-upgrade` applies it to the database.
203
+
202
204
  ```bash
203
- # Create initial migration (first time only)
205
+ # Create initial migration (REQUIRED first time)
204
206
  make db-migrate
205
207
  # Enter message: "Initial migration"
206
208
 
@@ -163,8 +163,10 @@ make docker-db
163
163
 
164
164
  #### 3. Create and apply database migrations
165
165
 
166
+ > ⚠️ **Important:** Both commands are required! `db-migrate` creates the migration file, `db-upgrade` applies it to the database.
167
+
166
168
  ```bash
167
- # Create initial migration (first time only)
169
+ # Create initial migration (REQUIRED first time)
168
170
  make db-migrate
169
171
  # Enter message: "Initial migration"
170
172
 
@@ -0,0 +1,8 @@
1
+ """FastAPI Project Generator with Logfire observability."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("fastapi-fullstack")
7
+ except PackageNotFoundError:
8
+ __version__ = "0.0.0" # Development/editable install fallback
@@ -283,6 +283,83 @@ class ProjectConfig(BaseModel):
283
283
  and not self.enable_redis
284
284
  ):
285
285
  raise ValueError("Rate limiting with Redis storage requires Redis to be enabled")
286
+
287
+ # WebSocket JWT auth requires main JWT auth
288
+ if self.websocket_auth == WebSocketAuthType.JWT and self.auth not in (
289
+ AuthType.JWT,
290
+ AuthType.BOTH,
291
+ ):
292
+ raise ValueError("WebSocket JWT authentication requires JWT auth to be enabled")
293
+
294
+ # WebSocket API key auth requires main API key auth
295
+ if self.websocket_auth == WebSocketAuthType.API_KEY and self.auth not in (
296
+ AuthType.API_KEY,
297
+ AuthType.BOTH,
298
+ ):
299
+ raise ValueError("WebSocket API key authentication requires API key auth to be enabled")
300
+
301
+ # Admin panel authentication requires JWT (for User model and security functions)
302
+ if (
303
+ self.enable_admin_panel
304
+ and self.admin_require_auth
305
+ and self.auth not in (AuthType.JWT, AuthType.BOTH)
306
+ ):
307
+ raise ValueError(
308
+ "Admin panel authentication requires JWT auth to be enabled. "
309
+ "Either enable JWT auth or set admin_require_auth=False"
310
+ )
311
+
312
+ # Conversation persistence requires AI agent
313
+ if self.enable_conversation_persistence and not self.enable_ai_agent:
314
+ raise ValueError("Conversation persistence requires AI agent to be enabled")
315
+
316
+ # Admin panel requires SQLAlchemy (SQLAdmin doesn't fully support SQLModel)
317
+ if self.enable_admin_panel and self.orm_type == OrmType.SQLMODEL:
318
+ raise ValueError(
319
+ "Admin panel (SQLAdmin) requires SQLAlchemy ORM. "
320
+ "SQLModel is not fully supported. Use orm_type=sqlalchemy or disable admin panel."
321
+ )
322
+
323
+ # Session management requires JWT auth
324
+ if self.enable_session_management and self.auth not in (AuthType.JWT, AuthType.BOTH):
325
+ raise ValueError("Session management requires JWT auth to be enabled")
326
+
327
+ # Webhooks require a database
328
+ if self.enable_webhooks and self.database == DatabaseType.NONE:
329
+ raise ValueError(
330
+ "Webhooks require a database to store subscriptions and delivery history"
331
+ )
332
+
333
+ # Background task queues require Redis
334
+ if (
335
+ self.background_tasks
336
+ in (
337
+ BackgroundTaskType.CELERY,
338
+ BackgroundTaskType.TASKIQ,
339
+ BackgroundTaskType.ARQ,
340
+ )
341
+ and not self.enable_redis
342
+ ):
343
+ raise ValueError(
344
+ f"{self.background_tasks.value.title()} requires Redis to be enabled. "
345
+ "All task queue systems use Redis as broker/backend."
346
+ )
347
+
348
+ # Logfire feature-specific validations (only when logfire is enabled)
349
+ if self.enable_logfire:
350
+ if self.logfire_features.database and self.database == DatabaseType.NONE:
351
+ raise ValueError(
352
+ "Logfire database instrumentation requires a database to be enabled"
353
+ )
354
+
355
+ if self.logfire_features.redis and not self.enable_redis:
356
+ raise ValueError("Logfire Redis instrumentation requires Redis to be enabled")
357
+
358
+ if self.logfire_features.celery and self.background_tasks != BackgroundTaskType.CELERY:
359
+ raise ValueError(
360
+ "Logfire Celery instrumentation requires Celery as background task system"
361
+ )
362
+
286
363
  return self
287
364
 
288
365
  def to_cookiecutter_context(self) -> dict[str, Any]:
@@ -12,31 +12,31 @@ from .config import DatabaseType, FrontendType, ProjectConfig
12
12
  console = Console()
13
13
 
14
14
 
15
- def _get_database_setup_commands(database: DatabaseType) -> list[str]:
15
+ def _get_database_setup_commands(database: DatabaseType) -> list[tuple[str, str]]:
16
16
  """Get database-specific setup commands for post-generation messages.
17
17
 
18
18
  Args:
19
19
  database: The database type selected by the user
20
20
 
21
21
  Returns:
22
- List of command strings to display
22
+ List of (command, description) tuples to display
23
23
  """
24
24
  if database == DatabaseType.SQLITE:
25
25
  return [
26
- "# SQLite database will be created automatically at first run",
27
- "make db-migrate # Create initial migration",
28
- "make db-upgrade # Apply migrations",
26
+ ("# SQLite database will be created automatically", ""),
27
+ ("make db-migrate", "Create initial migration"),
28
+ ("make db-upgrade", "Apply migrations"),
29
29
  ]
30
30
  elif database == DatabaseType.MONGODB:
31
31
  return [
32
- "make docker-mongo # Start MongoDB container",
33
- "# Or configure MongoDB Atlas connection in .env",
32
+ ("make docker-mongo", "Start MongoDB container"),
33
+ ("# Or configure MongoDB Atlas connection in .env", ""),
34
34
  ]
35
35
  else: # PostgreSQL
36
36
  return [
37
- "make docker-db # Start PostgreSQL container",
38
- "make db-migrate # Create initial migration",
39
- "make db-upgrade # Apply migrations",
37
+ ("make docker-db", "Start PostgreSQL container"),
38
+ ("make db-migrate", "Create initial migration"),
39
+ ("make db-upgrade", "Apply migrations"),
40
40
  ]
41
41
 
42
42
 
@@ -153,8 +153,18 @@ def post_generation_tasks(project_path: Path, config: ProjectConfig) -> None:
153
153
  if config.database.value != "none":
154
154
  console.print()
155
155
  console.print(f"[bold]{step}. Database setup:[/]")
156
- for cmd in _get_database_setup_commands(config.database):
157
- console.print(f" {cmd}")
156
+ db_commands = _get_database_setup_commands(config.database)
157
+ for cmd, desc in db_commands:
158
+ if desc:
159
+ console.print(f" {cmd:22}# {desc}")
160
+ else:
161
+ console.print(f" {cmd}")
162
+ if config.database != DatabaseType.MONGODB:
163
+ console.print()
164
+ console.print(
165
+ " [dim]⚠️ Run all commands in order:[/] "
166
+ "[dim]db-migrate creates the migration, db-upgrade applies it[/]"
167
+ )
158
168
  step += 1
159
169
  console.print()
160
170
  console.print(f"[bold]{step}. Run backend:[/]")
@@ -184,8 +194,18 @@ def post_generation_tasks(project_path: Path, config: ProjectConfig) -> None:
184
194
  if config.database.value != "none":
185
195
  console.print()
186
196
  console.print(f"[bold]{step}. Database setup:[/]")
187
- for cmd in _get_database_setup_commands(config.database):
188
- console.print(f" {cmd}")
197
+ db_commands = _get_database_setup_commands(config.database)
198
+ for cmd, desc in db_commands:
199
+ if desc:
200
+ console.print(f" {cmd:22}# {desc}")
201
+ else:
202
+ console.print(f" {cmd}")
203
+ if config.database != DatabaseType.MONGODB:
204
+ console.print()
205
+ console.print(
206
+ " [dim]⚠️ Run all commands in order:[/] "
207
+ "[dim]db-migrate creates the migration, db-upgrade applies it[/]"
208
+ )
189
209
  step += 1
190
210
  console.print()
191
211
  console.print(f"[bold]{step}. Run server:[/]")
@@ -157,11 +157,11 @@ def prompt_orm_type() -> OrmType:
157
157
  """Prompt for ORM library selection."""
158
158
  choices = [
159
159
  questionary.Choice(
160
- "SQLAlchemy (recommended - full control, mature)",
160
+ "SQLAlchemy full control, supports admin panel",
161
161
  value=OrmType.SQLALCHEMY,
162
162
  ),
163
163
  questionary.Choice(
164
- "SQLModel (simplified - less boilerplate, FastAPI-native)",
164
+ "SQLModel less boilerplate, no admin panel support",
165
165
  value=OrmType.SQLMODEL,
166
166
  ),
167
167
  ]
@@ -289,38 +289,120 @@ def prompt_background_tasks() -> BackgroundTaskType:
289
289
  )
290
290
 
291
291
 
292
- def prompt_integrations() -> dict[str, bool]:
293
- """Prompt for optional integrations."""
292
+ def prompt_integrations(
293
+ database: DatabaseType,
294
+ orm_type: OrmType,
295
+ ) -> dict[str, bool]:
296
+ """Prompt for optional integrations.
297
+
298
+ Args:
299
+ database: Selected database type (affects which options are shown).
300
+ orm_type: Selected ORM type (SQLModel doesn't support admin panel).
301
+ """
294
302
  console.print()
295
303
  console.print("[bold cyan]Optional Integrations[/]")
296
304
  console.print()
297
305
 
306
+ # Build choices dynamically based on context
307
+ choices: list[questionary.Choice] = [
308
+ questionary.Choice(
309
+ "Redis — required for caching, rate limiting (Redis), task queues",
310
+ value="redis",
311
+ ),
312
+ questionary.Choice(
313
+ "Caching (fastapi-cache2) — requires Redis",
314
+ value="caching",
315
+ ),
316
+ questionary.Choice(
317
+ "Rate limiting (slowapi) — optional Redis storage",
318
+ value="rate_limiting",
319
+ ),
320
+ questionary.Choice(
321
+ "Pagination (fastapi-pagination)",
322
+ value="pagination",
323
+ checked=True,
324
+ ),
325
+ questionary.Choice(
326
+ "Sentry — error tracking & monitoring",
327
+ value="sentry",
328
+ ),
329
+ questionary.Choice(
330
+ "Prometheus — metrics endpoint for monitoring",
331
+ value="prometheus",
332
+ ),
333
+ ]
334
+
335
+ # Admin Panel only available with SQLAlchemy (not SQLModel) and SQL database
336
+ if (
337
+ database in (DatabaseType.POSTGRESQL, DatabaseType.SQLITE)
338
+ and orm_type == OrmType.SQLALCHEMY
339
+ ):
340
+ choices.append(
341
+ questionary.Choice(
342
+ "Admin Panel (SQLAdmin) — web UI for database management",
343
+ value="admin_panel",
344
+ )
345
+ )
346
+
347
+ choices.extend(
348
+ [
349
+ questionary.Choice(
350
+ "WebSockets — real-time bidirectional communication",
351
+ value="websockets",
352
+ ),
353
+ questionary.Choice(
354
+ "File Storage (S3/MinIO) — file upload/download support",
355
+ value="file_storage",
356
+ ),
357
+ questionary.Choice(
358
+ "AI Agent (PydanticAI/LangGraph/CrewAI) — LLM-powered assistant",
359
+ value="ai_agent",
360
+ checked=True,
361
+ ),
362
+ ]
363
+ )
364
+
365
+ # Webhooks require database
366
+ if database != DatabaseType.NONE:
367
+ choices.append(
368
+ questionary.Choice(
369
+ "Webhooks — outbound event notifications",
370
+ value="webhooks",
371
+ )
372
+ )
373
+
374
+ choices.extend(
375
+ [
376
+ questionary.Choice(
377
+ "Example CRUD (Item model) — sample API endpoints",
378
+ value="example_crud",
379
+ checked=True,
380
+ ),
381
+ questionary.Choice(
382
+ "CORS middleware — cross-origin request support",
383
+ value="cors",
384
+ checked=True,
385
+ ),
386
+ questionary.Choice(
387
+ "orjson — faster JSON serialization",
388
+ value="orjson",
389
+ checked=True,
390
+ ),
391
+ ]
392
+ )
393
+
298
394
  features = _check_cancelled(
299
395
  questionary.checkbox(
300
396
  "Select additional features:",
301
- choices=[
302
- questionary.Choice("Redis (caching/sessions)", value="redis"),
303
- questionary.Choice("Caching (fastapi-cache2)", value="caching"),
304
- questionary.Choice("Rate limiting (slowapi)", value="rate_limiting"),
305
- questionary.Choice(
306
- "Pagination (fastapi-pagination)", value="pagination", checked=True
307
- ),
308
- questionary.Choice("Sentry (error tracking)", value="sentry"),
309
- questionary.Choice("Prometheus (metrics)", value="prometheus"),
310
- questionary.Choice("Admin Panel (SQLAdmin)", value="admin_panel"),
311
- questionary.Choice("WebSockets", value="websockets"),
312
- questionary.Choice("File Storage (S3/MinIO)", value="file_storage"),
313
- questionary.Choice(
314
- "AI Agent (PydanticAI/LangGraph/CrewAI)", value="ai_agent", checked=True
315
- ),
316
- questionary.Choice("Webhooks (outbound events)", value="webhooks"),
317
- questionary.Choice("Example CRUD (Item model)", value="example_crud", checked=True),
318
- questionary.Choice("CORS middleware", value="cors", checked=True),
319
- questionary.Choice("orjson (faster JSON)", value="orjson", checked=True),
320
- ],
397
+ choices=choices,
321
398
  ).ask()
322
399
  )
323
400
 
401
+ # Auto-enable Redis for caching (show info message)
402
+ if "caching" in features and "redis" not in features:
403
+ console.print("[yellow]ℹ Caching requires Redis — auto-enabled[/]")
404
+ features.append("redis")
405
+
324
406
  return {
325
407
  "enable_redis": "redis" in features,
326
408
  "enable_caching": "caching" in features,
@@ -582,18 +664,31 @@ def prompt_llm_provider(ai_framework: AIFrameworkType) -> LLMProviderType:
582
664
  )
583
665
 
584
666
 
585
- def prompt_websocket_auth() -> WebSocketAuthType:
586
- """Prompt for WebSocket authentication method for AI Agent."""
667
+ def prompt_websocket_auth(auth: AuthType) -> WebSocketAuthType:
668
+ """Prompt for WebSocket authentication method for AI Agent.
669
+
670
+ Args:
671
+ auth: The main auth type. JWT WebSocket auth is only available
672
+ if JWT is enabled (JWT or BOTH).
673
+ """
587
674
  console.print()
588
675
  console.print("[bold cyan]AI Agent WebSocket Authentication[/]")
589
676
  console.print()
590
677
 
591
678
  choices = [
592
679
  questionary.Choice("None (public access)", value=WebSocketAuthType.NONE),
593
- questionary.Choice("JWT token required", value=WebSocketAuthType.JWT),
594
- questionary.Choice("API Key required (query param)", value=WebSocketAuthType.API_KEY),
595
680
  ]
596
681
 
682
+ # JWT WebSocket auth only available if main auth uses JWT
683
+ if auth in (AuthType.JWT, AuthType.BOTH):
684
+ choices.append(questionary.Choice("JWT token required", value=WebSocketAuthType.JWT))
685
+
686
+ # API Key WebSocket auth available if main auth uses API keys
687
+ if auth in (AuthType.API_KEY, AuthType.BOTH):
688
+ choices.append(
689
+ questionary.Choice("API Key required (query param)", value=WebSocketAuthType.API_KEY)
690
+ )
691
+
597
692
  return cast(
598
693
  WebSocketAuthType,
599
694
  _check_cancelled(
@@ -744,8 +839,8 @@ def run_interactive_prompts() -> ProjectConfig:
744
839
  # Background tasks
745
840
  background_tasks = prompt_background_tasks()
746
841
 
747
- # Integrations
748
- integrations = prompt_integrations()
842
+ # Integrations (pass context for dynamic option filtering)
843
+ integrations = prompt_integrations(database=database, orm_type=orm_type)
749
844
 
750
845
  # Dev tools
751
846
  dev_tools = prompt_dev_tools()
@@ -780,7 +875,7 @@ def run_interactive_prompts() -> ProjectConfig:
780
875
  if integrations.get("enable_ai_agent"):
781
876
  ai_framework = prompt_ai_framework()
782
877
  llm_provider = prompt_llm_provider(ai_framework)
783
- websocket_auth = prompt_websocket_auth()
878
+ websocket_auth = prompt_websocket_auth(auth=auth)
784
879
  # Only offer persistence if database is enabled
785
880
  if database != DatabaseType.NONE:
786
881
  enable_conversation_persistence = _check_cancelled(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastapi-fullstack"
3
- version = "0.1.12"
3
+ version = "0.1.14"
4
4
  description = "Full-stack FastAPI + Next.js template generator with PydanticAI/LangChain agents, WebSocket streaming, 20+ enterprise integrations, and Logfire/LangSmith observability. Ship AI apps fast. CLI tool to generate production-ready FastAPI + Next.js projects with AI agents, auth, and observability."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -165,3 +165,9 @@ exclude_lines = [
165
165
  "if TYPE_CHECKING:",
166
166
  "raise NotImplementedError",
167
167
  ]
168
+
169
+ [dependency-groups]
170
+ dev = [
171
+ "mypy>=1.19.1",
172
+ "pytest-cov>=7.0.0",
173
+ ]
@@ -16,10 +16,14 @@ use_database = "{{ cookiecutter.use_database }}" == "True"
16
16
  use_postgresql = "{{ cookiecutter.use_postgresql }}" == "True"
17
17
  use_sqlite = "{{ cookiecutter.use_sqlite }}" == "True"
18
18
  use_mongodb = "{{ cookiecutter.use_mongodb }}" == "True"
19
+ use_sqlalchemy = "{{ cookiecutter.use_sqlalchemy }}" == "True"
20
+ use_sqlmodel = "{{ cookiecutter.use_sqlmodel }}" == "True"
19
21
  include_example_crud = "{{ cookiecutter.include_example_crud }}" == "True"
20
22
  enable_ai_agent = "{{ cookiecutter.enable_ai_agent }}" == "True"
21
23
  use_pydantic_ai = "{{ cookiecutter.use_pydantic_ai }}" == "True"
22
24
  use_langchain = "{{ cookiecutter.use_langchain }}" == "True"
25
+ use_langgraph = "{{ cookiecutter.use_langgraph }}" == "True"
26
+ use_crewai = "{{ cookiecutter.use_crewai }}" == "True"
23
27
  enable_admin_panel = "{{ cookiecutter.enable_admin_panel }}" == "True"
24
28
  enable_websockets = "{{ cookiecutter.enable_websockets }}" == "True"
25
29
  enable_redis = "{{ cookiecutter.enable_redis }}" == "True"
@@ -30,6 +34,7 @@ enable_conversation_persistence = "{{ cookiecutter.enable_conversation_persisten
30
34
  enable_webhooks = "{{ cookiecutter.enable_webhooks }}" == "True"
31
35
  enable_oauth = "{{ cookiecutter.enable_oauth }}" == "True"
32
36
  use_jwt = "{{ cookiecutter.use_jwt }}" == "True"
37
+ use_api_key = "{{ cookiecutter.use_api_key }}" == "True"
33
38
  use_celery = "{{ cookiecutter.use_celery }}" == "True"
34
39
  use_taskiq = "{{ cookiecutter.use_taskiq }}" == "True"
35
40
  use_arq = "{{ cookiecutter.use_arq }}" == "True"
@@ -37,6 +42,7 @@ use_github_actions = "{{ cookiecutter.use_github_actions }}" == "True"
37
42
  use_gitlab_ci = "{{ cookiecutter.use_gitlab_ci }}" == "True"
38
43
  enable_kubernetes = "{{ cookiecutter.enable_kubernetes }}" == "True"
39
44
  use_nginx = "{{ cookiecutter.use_nginx }}" == "True"
45
+ enable_logfire = "{{ cookiecutter.enable_logfire }}" == "True"
40
46
 
41
47
 
42
48
  def remove_file(path: str) -> None:
@@ -46,6 +52,23 @@ def remove_file(path: str) -> None:
46
52
  print(f" Removed: {os.path.relpath(path)}")
47
53
 
48
54
 
55
+ def is_stub_file(filepath: str) -> bool:
56
+ """Check if file only contains a docstring stub with no real code."""
57
+ if not os.path.exists(filepath):
58
+ return False
59
+ with open(filepath) as f:
60
+ content = f.read().strip()
61
+ # Empty file
62
+ if not content:
63
+ return True
64
+ # File only has docstring (triple-quoted string)
65
+ if content.startswith('"""') and content.endswith('"""'):
66
+ # Check if there's only one docstring and no code
67
+ inner = content[3:-3].strip()
68
+ return '"""' not in inner and "def " not in content and "class " not in content
69
+ return False
70
+
71
+
49
72
  def remove_dir(path: str) -> None:
50
73
  """Remove a directory if it exists."""
51
74
  if os.path.exists(path):
@@ -72,6 +95,10 @@ else:
72
95
  remove_file(os.path.join(backend_app, "agents", "assistant.py"))
73
96
  if not use_langchain:
74
97
  remove_file(os.path.join(backend_app, "agents", "langchain_assistant.py"))
98
+ if not use_langgraph:
99
+ remove_file(os.path.join(backend_app, "agents", "langgraph_assistant.py"))
100
+ if not use_crewai:
101
+ remove_file(os.path.join(backend_app, "agents", "crewai_assistant.py"))
75
102
 
76
103
  # --- Example CRUD files ---
77
104
  if not include_example_crud or not use_database:
@@ -109,8 +136,8 @@ if not enable_session_management or not use_jwt:
109
136
  if not enable_websockets:
110
137
  remove_file(os.path.join(backend_app, "api", "routes", "v1", "ws.py"))
111
138
 
112
- # --- Admin panel ---
113
- if not enable_admin_panel or (not use_postgresql and not use_sqlite):
139
+ # --- Admin panel (requires SQLAlchemy, not SQLModel) ---
140
+ if not enable_admin_panel or (not use_postgresql and not use_sqlite) or not use_sqlalchemy:
114
141
  remove_file(os.path.join(backend_app, "admin.py"))
115
142
 
116
143
  # --- Redis/Cache files ---
@@ -129,6 +156,32 @@ if not enable_oauth:
129
156
  remove_file(os.path.join(backend_app, "api", "routes", "v1", "oauth.py"))
130
157
  remove_file(os.path.join(backend_app, "core", "oauth.py"))
131
158
 
159
+ # --- Security file (only when no auth at all) ---
160
+ if not use_jwt and not use_api_key:
161
+ remove_file(os.path.join(backend_app, "core", "security.py"))
162
+
163
+ # --- Auth/User files (when JWT is disabled) ---
164
+ if not use_jwt:
165
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "auth.py"))
166
+ remove_file(os.path.join(backend_app, "api", "routes", "v1", "users.py"))
167
+ remove_file(os.path.join(backend_app, "db", "models", "user.py"))
168
+ remove_file(os.path.join(backend_app, "repositories", "user.py"))
169
+ remove_file(os.path.join(backend_app, "services", "user.py"))
170
+ remove_file(os.path.join(backend_app, "schemas", "user.py"))
171
+ remove_file(os.path.join(backend_app, "schemas", "token.py"))
172
+
173
+ # --- Logfire setup file (when logfire is disabled) ---
174
+ if not enable_logfire:
175
+ remove_file(os.path.join(backend_app, "core", "logfire_setup.py"))
176
+
177
+ # --- Cleanup stub files (files with only docstring, no code) ---
178
+ core_dir = os.path.join(backend_app, "core")
179
+ for stub_candidate in ["security.py", "cache.py", "rate_limit.py", "oauth.py", "logfire_setup.py", "csrf.py"]:
180
+ filepath = os.path.join(core_dir, stub_candidate)
181
+ if is_stub_file(filepath):
182
+ remove_file(filepath)
183
+ print(f" Removed stub: {os.path.relpath(filepath)}")
184
+
132
185
  # --- Worker/Background tasks ---
133
186
  use_any_background_tasks = use_celery or use_taskiq or use_arq
134
187
  if not use_any_background_tasks:
@@ -1,4 +1,4 @@
1
- {%- if cookiecutter.enable_admin_panel and cookiecutter.use_postgresql %}
1
+ {%- if cookiecutter.enable_admin_panel and (cookiecutter.use_postgresql or cookiecutter.use_sqlite) and cookiecutter.use_sqlalchemy %}
2
2
  """SQLAdmin configuration with automatic model discovery."""
3
3
 
4
4
  from typing import Any, ClassVar
@@ -163,7 +163,7 @@ class LangChainAssistant:
163
163
 
164
164
  return output, tool_events, agent_context
165
165
 
166
- def stream(
166
+ async def stream(
167
167
  self,
168
168
  user_input: str,
169
169
  history: list[dict[str, str]] | None = None,
@@ -186,11 +186,12 @@ class LangChainAssistant:
186
186
 
187
187
  agent_context: AgentContext = context if context is not None else {}
188
188
 
189
- yield from self.agent.stream(
189
+ async for event in self.agent.astream(
190
190
  {"messages": messages},
191
191
  stream_mode=["messages", "updates"],
192
192
  config={"configurable": agent_context} if agent_context else None,
193
- )
193
+ ):
194
+ yield event
194
195
 
195
196
 
196
197
  def get_agent() -> LangChainAssistant:
@@ -141,19 +141,15 @@ async def google_callback(request: Request, user_service: UserSvc):
141
141
 
142
142
 
143
143
  @router.get("/google/callback")
144
- def google_callback(request: Request, user_service: UserSvc):
144
+ async def google_callback(request: Request, user_service: UserSvc):
145
145
  """Handle Google OAuth2 callback.
146
146
 
147
147
  Creates a new user if one doesn't exist with the Google email,
148
148
  or returns tokens for existing user. Redirects to frontend with tokens.
149
149
  """
150
- import asyncio
151
-
152
150
  try:
153
- # Run async OAuth in sync context
154
- loop = asyncio.new_event_loop()
155
- token = loop.run_until_complete(oauth.google.authorize_access_token(request))
156
- loop.close()
151
+ # OAuth token exchange is async
152
+ token = await oauth.google.authorize_access_token(request)
157
153
 
158
154
  user_info = token.get("userinfo")
159
155
 
@@ -6,7 +6,7 @@ This command is useful for maintenance tasks.
6
6
  """
7
7
 
8
8
  import asyncio
9
- from datetime import datetime, timedelta
9
+ from datetime import UTC, datetime, timedelta
10
10
 
11
11
  import click
12
12
 
@@ -26,7 +26,7 @@ def cleanup(days: int, dry_run: bool, force: bool) -> None:
26
26
  project cmd cleanup --days 30 --dry-run
27
27
  project cmd cleanup --days 7 --force
28
28
  """
29
- cutoff_date = datetime.utcnow() - timedelta(days=days)
29
+ cutoff_date = datetime.now(UTC) - timedelta(days=days)
30
30
 
31
31
  if dry_run:
32
32
  info(f"[DRY RUN] Would delete records older than {cutoff_date}")
@@ -7,13 +7,16 @@ This command is useful for development and testing.
7
7
  Uses random data generation - install faker for better data:
8
8
  uv add faker --group dev
9
9
  """
10
-
10
+ {% if cookiecutter.use_postgresql %}
11
11
  import asyncio
12
+ {% endif %}
12
13
  import random
13
14
  import string
14
15
 
15
16
  import click
17
+ {% if cookiecutter.use_jwt or cookiecutter.include_example_crud %}
16
18
  from sqlalchemy import delete, select
19
+ {% endif %}
17
20
 
18
21
  from app.commands import command, info, success, warning
19
22
 
@@ -109,7 +112,9 @@ def seed(
109
112
  {%- endif %}
110
113
  return
111
114
 
112
- {%- if cookiecutter.use_postgresql %}
115
+ {%- if not cookiecutter.use_jwt and not cookiecutter.include_example_crud %}
116
+ info("No entities configured to seed. Enable JWT users or example CRUD to use this command.")
117
+ {%- elif cookiecutter.use_postgresql %}
113
118
  from app.db.session import async_session_maker
114
119
  {%- if cookiecutter.use_jwt %}
115
120
  from app.db.models.user import User