fastapi-fullstack 0.1.2__tar.gz → 0.1.3__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 (222) hide show
  1. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/PKG-INFO +29 -1
  2. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/README.md +28 -0
  3. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/pyproject.toml +1 -1
  4. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/hooks/post_gen_project.py +8 -0
  5. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/Makefile +6 -1
  6. fastapi_fullstack-0.1.3/template/{{cookiecutter.project_slug}}/backend/app/admin.py +356 -0
  7. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +77 -61
  8. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +3 -3
  9. fastapi_fullstack-0.1.2/template/{{cookiecutter.project_slug}}/backend/app/admin.py +0 -115
  10. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/.gitignore +0 -0
  11. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/LICENSE +0 -0
  12. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/fastapi_gen/__init__.py +0 -0
  13. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/fastapi_gen/cli.py +0 -0
  14. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/fastapi_gen/config.py +0 -0
  15. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/fastapi_gen/generator.py +0 -0
  16. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/fastapi_gen/prompts.py +0 -0
  17. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/cookiecutter.json +0 -0
  18. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/.env.example +0 -0
  19. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +0 -0
  20. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/.gitignore +0 -0
  21. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/CLAUDE.md +0 -0
  22. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/README.md +0 -0
  23. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/.dockerignore +0 -0
  24. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +0 -0
  25. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/Dockerfile +0 -0
  26. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +0 -0
  27. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +0 -0
  28. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
  29. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/alembic.ini +0 -0
  30. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +0 -0
  31. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +0 -0
  32. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +0 -0
  33. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +0 -0
  34. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +0 -0
  35. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +0 -0
  36. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +0 -0
  37. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +0 -0
  38. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +0 -0
  39. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +0 -0
  40. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +0 -0
  41. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +0 -0
  42. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +0 -0
  43. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +0 -0
  44. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +0 -0
  45. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +0 -0
  46. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +0 -0
  47. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +0 -0
  48. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +0 -0
  49. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +0 -0
  50. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +0 -0
  51. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +0 -0
  52. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +0 -0
  53. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +0 -0
  54. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +0 -0
  55. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +0 -0
  56. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +0 -0
  57. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +0 -0
  58. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +0 -0
  59. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +0 -0
  60. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +0 -0
  61. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +0 -0
  62. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +0 -0
  63. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +0 -0
  64. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +0 -0
  65. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +0 -0
  66. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +0 -0
  67. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +0 -0
  68. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +0 -0
  69. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +0 -0
  70. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +0 -0
  71. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +0 -0
  72. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +0 -0
  73. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +0 -0
  74. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +0 -0
  75. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +0 -0
  76. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +0 -0
  77. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/main.py +0 -0
  78. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +0 -0
  79. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +0 -0
  80. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +0 -0
  81. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +0 -0
  82. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +0 -0
  83. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +0 -0
  84. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +0 -0
  85. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +0 -0
  86. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +0 -0
  87. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +0 -0
  88. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +0 -0
  89. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +0 -0
  90. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +0 -0
  91. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +0 -0
  92. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +0 -0
  93. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +0 -0
  94. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +0 -0
  95. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +0 -0
  96. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +0 -0
  97. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +0 -0
  98. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +0 -0
  99. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +0 -0
  100. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +0 -0
  101. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +0 -0
  102. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +0 -0
  103. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +0 -0
  104. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +0 -0
  105. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +0 -0
  106. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +0 -0
  107. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +0 -0
  108. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +0 -0
  109. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +0 -0
  110. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +0 -0
  111. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
  112. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +0 -0
  113. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +0 -0
  114. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +0 -0
  115. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +0 -0
  116. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +0 -0
  117. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +0 -0
  118. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +0 -0
  119. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +0 -0
  120. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +0 -0
  121. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +0 -0
  122. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +0 -0
  123. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +0 -0
  124. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +0 -0
  125. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +0 -0
  126. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +0 -0
  127. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +0 -0
  128. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +0 -0
  129. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +0 -0
  130. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +0 -0
  131. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/docker-compose.yml +0 -0
  132. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/.env.example +0 -0
  133. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/.gitignore +0 -0
  134. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +0 -0
  135. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +0 -0
  136. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +0 -0
  137. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/README.md +0 -0
  138. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +0 -0
  139. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +0 -0
  140. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +0 -0
  141. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +0 -0
  142. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +0 -0
  143. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +0 -0
  144. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +0 -0
  145. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +0 -0
  146. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/package.json +0 -0
  147. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +0 -0
  148. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +0 -0
  149. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/layout.tsx +0 -0
  150. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/login/page.tsx +0 -0
  151. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(auth)/register/page.tsx +0 -0
  152. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/chat/page.tsx +0 -0
  153. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/dashboard/page.tsx +0 -0
  154. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/layout.tsx +0 -0
  155. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/(dashboard)/profile/page.tsx +0 -0
  156. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +0 -0
  157. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +0 -0
  158. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +0 -0
  159. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +0 -0
  160. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +0 -0
  161. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +0 -0
  162. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +0 -0
  163. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +0 -0
  164. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +0 -0
  165. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +0 -0
  166. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/auth/callback/page.tsx +0 -0
  167. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +0 -0
  168. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +0 -0
  169. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/page.tsx +0 -0
  170. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +0 -0
  171. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +0 -0
  172. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +0 -0
  173. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +0 -0
  174. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +0 -0
  175. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +0 -0
  176. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +0 -0
  177. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +0 -0
  178. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +0 -0
  179. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +0 -0
  180. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +0 -0
  181. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +0 -0
  182. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +0 -0
  183. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +0 -0
  184. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +0 -0
  185. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +0 -0
  186. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +0 -0
  187. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +0 -0
  188. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +0 -0
  189. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +0 -0
  190. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +0 -0
  191. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +0 -0
  192. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +0 -0
  193. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +0 -0
  194. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +0 -0
  195. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +0 -0
  196. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +0 -0
  197. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +0 -0
  198. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +0 -0
  199. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +0 -0
  200. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +0 -0
  201. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +0 -0
  202. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +0 -0
  203. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +0 -0
  204. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +0 -0
  205. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +0 -0
  206. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +0 -0
  207. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +0 -0
  208. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +0 -0
  209. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +0 -0
  210. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +0 -0
  211. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +0 -0
  212. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +0 -0
  213. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +0 -0
  214. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +0 -0
  215. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +0 -0
  216. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +0 -0
  217. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +0 -0
  218. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +0 -0
  219. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +0 -0
  220. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +0 -0
  221. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +0 -0
  222. {fastapi_fullstack-0.1.2 → fastapi_fullstack-0.1.3}/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-fullstack
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Interactive FastAPI project generator with Logfire 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
@@ -51,6 +51,7 @@ Description-Content-Type: text/markdown
51
51
  <p align="center">
52
52
  <a href="#-why-this-template">Why This Template</a> •
53
53
  <a href="#-features">Features</a> •
54
+ <a href="#-demo">Demo</a> •
54
55
  <a href="#-quick-start">Quick Start</a> •
55
56
  <a href="#-architecture">Architecture</a> •
56
57
  <a href="#-ai-agent">AI Agent</a> •
@@ -117,6 +118,25 @@ This template gives you all of that out of the box, with **20+ configurable inte
117
118
 
118
119
  ---
119
120
 
121
+ ## 🎬 Demo
122
+
123
+ <p align="center">
124
+ <img src="assets/app_start.gif" alt="FastAPI Fullstack Generator Demo" width="800">
125
+ </p>
126
+
127
+ ### Screenshots
128
+
129
+ <p align="center">
130
+ <img src="assets/docs_2.png" alt="API Documentation" width="700"><br><br>
131
+ <img src="assets/admin.png" alt="Admin Panel" width="700"><br><br>
132
+ <img src="assets/chat_view_light.png" alt="Chat Interface - Light Mode" width="700"><br><br>
133
+ <img src="assets/chat_view_dark.png" alt="Chat Interface - Dark Mode" width="700"><br><br>
134
+ <img src="assets/login.png" alt="Login Page" width="700"><br><br>
135
+ <img src="assets/register.png" alt="Register Page" width="700">
136
+ </p>
137
+
138
+ ---
139
+
120
140
  ## 🏗️ Architecture
121
141
 
122
142
  ```mermaid
@@ -219,6 +239,11 @@ cd backend
219
239
  uv sync
220
240
  cp .env.example .env
221
241
  alembic upgrade head
242
+
243
+ # Create admin user
244
+ uv run my_ai_app user create --email admin@example.com --password secret123 --superuser
245
+
246
+ # Start server
222
247
  uv run uvicorn app.main:app --reload
223
248
 
224
249
  # Frontend (new terminal)
@@ -227,9 +252,12 @@ bun install
227
252
  bun dev
228
253
  ```
229
254
 
255
+ > **Note:** The admin user is required to access the SQLAdmin panel at `/admin`. Use the `--superuser` flag to grant full admin privileges.
256
+
230
257
  **Access:**
231
258
  - API: http://localhost:8000
232
259
  - Docs: http://localhost:8000/docs
260
+ - Admin Panel: http://localhost:8000/admin
233
261
  - Frontend: http://localhost:3000
234
262
 
235
263
  ---
@@ -16,6 +16,7 @@
16
16
  <p align="center">
17
17
  <a href="#-why-this-template">Why This Template</a> •
18
18
  <a href="#-features">Features</a> •
19
+ <a href="#-demo">Demo</a> •
19
20
  <a href="#-quick-start">Quick Start</a> •
20
21
  <a href="#-architecture">Architecture</a> •
21
22
  <a href="#-ai-agent">AI Agent</a> •
@@ -82,6 +83,25 @@ This template gives you all of that out of the box, with **20+ configurable inte
82
83
 
83
84
  ---
84
85
 
86
+ ## 🎬 Demo
87
+
88
+ <p align="center">
89
+ <img src="assets/app_start.gif" alt="FastAPI Fullstack Generator Demo" width="800">
90
+ </p>
91
+
92
+ ### Screenshots
93
+
94
+ <p align="center">
95
+ <img src="assets/docs_2.png" alt="API Documentation" width="700"><br><br>
96
+ <img src="assets/admin.png" alt="Admin Panel" width="700"><br><br>
97
+ <img src="assets/chat_view_light.png" alt="Chat Interface - Light Mode" width="700"><br><br>
98
+ <img src="assets/chat_view_dark.png" alt="Chat Interface - Dark Mode" width="700"><br><br>
99
+ <img src="assets/login.png" alt="Login Page" width="700"><br><br>
100
+ <img src="assets/register.png" alt="Register Page" width="700">
101
+ </p>
102
+
103
+ ---
104
+
85
105
  ## 🏗️ Architecture
86
106
 
87
107
  ```mermaid
@@ -184,6 +204,11 @@ cd backend
184
204
  uv sync
185
205
  cp .env.example .env
186
206
  alembic upgrade head
207
+
208
+ # Create admin user
209
+ uv run my_ai_app user create --email admin@example.com --password secret123 --superuser
210
+
211
+ # Start server
187
212
  uv run uvicorn app.main:app --reload
188
213
 
189
214
  # Frontend (new terminal)
@@ -192,9 +217,12 @@ bun install
192
217
  bun dev
193
218
  ```
194
219
 
220
+ > **Note:** The admin user is required to access the SQLAdmin panel at `/admin`. Use the `--superuser` flag to grant full admin privileges.
221
+
195
222
  **Access:**
196
223
  - API: http://localhost:8000
197
224
  - Docs: http://localhost:8000/docs
225
+ - Admin Panel: http://localhost:8000/admin
198
226
  - Frontend: http://localhost:3000
199
227
 
200
228
  ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastapi-fullstack"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "Interactive FastAPI project generator with Logfire observability"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -9,6 +9,7 @@ import sys
9
9
  # Get cookiecutter variables
10
10
  use_frontend = "{{ cookiecutter.use_frontend }}" == "True"
11
11
  generate_env = "{{ cookiecutter.generate_env }}" == "True"
12
+ enable_i18n = "{{ cookiecutter.enable_i18n }}" == "True"
12
13
 
13
14
  # Remove frontend folder if not using frontend
14
15
  if not use_frontend:
@@ -17,6 +18,13 @@ if not use_frontend:
17
18
  shutil.rmtree(frontend_dir)
18
19
  print("Removed frontend/ directory (frontend not enabled)")
19
20
 
21
+ # Remove middleware.ts if i18n is not enabled (Next.js requires middleware to export a function)
22
+ if use_frontend and not enable_i18n:
23
+ middleware_file = os.path.join(os.getcwd(), "frontend", "src", "middleware.ts")
24
+ if os.path.exists(middleware_file):
25
+ os.remove(middleware_file)
26
+ print("Removed middleware.ts (i18n not enabled)")
27
+
20
28
  # Remove .env files if generate_env is false
21
29
  if not generate_env:
22
30
  backend_env = os.path.join(os.getcwd(), "backend", ".env")
@@ -4,7 +4,12 @@
4
4
  install:
5
5
  uv sync --directory backend --dev
6
6
  {%- if cookiecutter.enable_precommit %}
7
- uv run --directory backend pre-commit install
7
+ @if git rev-parse --git-dir > /dev/null 2>&1; then \
8
+ uv run --directory backend pre-commit install; \
9
+ else \
10
+ echo "⚠️ Not a git repository - skipping pre-commit install"; \
11
+ echo " Run 'git init && make install' to set up pre-commit hooks"; \
12
+ fi
8
13
  {%- endif %}
9
14
  @echo ""
10
15
  @echo "✅ Installation complete!"
@@ -0,0 +1,356 @@
1
+ {%- if cookiecutter.enable_admin_panel and cookiecutter.use_postgresql %}
2
+ """SQLAdmin configuration."""
3
+
4
+ from typing import ClassVar
5
+
6
+ from sqlalchemy import create_engine
7
+ from sqladmin import Admin, ModelView
8
+ {%- if cookiecutter.admin_require_auth %}
9
+ from sqladmin.authentication import AuthenticationBackend
10
+ from starlette.requests import Request
11
+ {%- endif %}
12
+
13
+ from app.core.config import settings
14
+ {%- if cookiecutter.admin_require_auth %}
15
+ from app.core.security import verify_password
16
+ {%- endif %}
17
+ from app.db.models.user import User
18
+ {%- if cookiecutter.enable_session_management %}
19
+ from app.db.models.session import Session
20
+ {%- endif %}
21
+ {%- if cookiecutter.include_example_crud %}
22
+ from app.db.models.item import Item
23
+ {%- endif %}
24
+ {%- if cookiecutter.enable_conversation_persistence %}
25
+ from app.db.models.conversation import Conversation, Message, ToolCall
26
+ {%- endif %}
27
+ {%- if cookiecutter.enable_webhooks %}
28
+ from app.db.models.webhook import Webhook, WebhookDelivery
29
+ {%- endif %}
30
+
31
+ # SQLAdmin requires a synchronous engine
32
+ sync_engine = create_engine(settings.DATABASE_URL_SYNC, echo=settings.DEBUG)
33
+
34
+ {%- if cookiecutter.admin_require_auth %}
35
+
36
+
37
+ class AdminAuth(AuthenticationBackend):
38
+ """Admin panel authentication backend.
39
+
40
+ Requires superuser credentials to access the admin panel.
41
+ """
42
+
43
+ async def login(self, request: Request) -> bool:
44
+ """Validate admin login credentials."""
45
+ form = await request.form()
46
+ email = form.get("username")
47
+ password = form.get("password")
48
+
49
+ if not email or not password:
50
+ return False
51
+
52
+ # Get user from database
53
+ from sqlalchemy.orm import Session as DBSession
54
+
55
+ with DBSession(sync_engine) as session:
56
+ user = session.query(User).filter(User.email == email).first()
57
+
58
+ if (
59
+ user
60
+ and verify_password(str(password), user.hashed_password)
61
+ and user.is_superuser
62
+ ):
63
+ # Store user info in session
64
+ request.session["admin_user_id"] = str(user.id)
65
+ request.session["admin_email"] = user.email
66
+ return True
67
+
68
+ return False
69
+
70
+ async def logout(self, request: Request) -> bool:
71
+ """Clear admin session."""
72
+ request.session.clear()
73
+ return True
74
+
75
+ async def authenticate(self, request: Request) -> bool:
76
+ """Check if user is authenticated."""
77
+ admin_user_id = request.session.get("admin_user_id")
78
+ if not admin_user_id:
79
+ return False
80
+
81
+ # Verify user still exists and is superuser
82
+ from sqlalchemy.orm import Session as DBSession
83
+
84
+ with DBSession(sync_engine) as session:
85
+ user = session.query(User).filter(User.id == admin_user_id).first()
86
+ if user and user.is_superuser and user.is_active:
87
+ return True
88
+
89
+ # User no longer valid, clear session
90
+ request.session.clear()
91
+ return False
92
+ {%- endif %}
93
+
94
+
95
+ # === User Management ===
96
+
97
+
98
+ class UserAdmin(ModelView, model=User): # type: ignore[call-arg]
99
+ """User admin view."""
100
+
101
+ name = "User"
102
+ name_plural = "Users"
103
+ icon = "fa-solid fa-user"
104
+
105
+ column_list: ClassVar = [
106
+ User.id,
107
+ User.email,
108
+ User.full_name,
109
+ User.is_active,
110
+ User.is_superuser,
111
+ User.role,
112
+ User.created_at,
113
+ ]
114
+ column_searchable_list: ClassVar = [User.email, User.full_name]
115
+ column_sortable_list: ClassVar = [User.id, User.email, User.is_active, User.created_at]
116
+ form_excluded_columns: ClassVar = [User.hashed_password, User.created_at, User.updated_at]
117
+ can_create: ClassVar = True
118
+ can_edit: ClassVar = True
119
+ can_delete: ClassVar = True
120
+ can_view_details: ClassVar = True
121
+
122
+ {%- if cookiecutter.enable_session_management %}
123
+
124
+
125
+ class SessionAdmin(ModelView, model=Session): # type: ignore[call-arg]
126
+ """Session admin view."""
127
+
128
+ name = "Session"
129
+ name_plural = "Sessions"
130
+ icon = "fa-solid fa-key"
131
+
132
+ column_list: ClassVar = [
133
+ Session.id,
134
+ Session.user_id,
135
+ Session.device_name,
136
+ Session.device_type,
137
+ Session.ip_address,
138
+ Session.is_active,
139
+ Session.created_at,
140
+ Session.last_used_at,
141
+ ]
142
+ column_searchable_list: ClassVar = [Session.device_name, Session.ip_address]
143
+ column_sortable_list: ClassVar = [Session.id, Session.created_at, Session.last_used_at]
144
+ form_excluded_columns: ClassVar = [Session.refresh_token_hash]
145
+ can_create: ClassVar = False # Sessions are created via login
146
+ can_edit: ClassVar = True
147
+ can_delete: ClassVar = True
148
+ can_view_details: ClassVar = True
149
+ {%- endif %}
150
+
151
+ {%- if cookiecutter.include_example_crud %}
152
+
153
+
154
+ # === Items (Example CRUD) ===
155
+
156
+
157
+ class ItemAdmin(ModelView, model=Item): # type: ignore[call-arg]
158
+ """Item admin view."""
159
+
160
+ name = "Item"
161
+ name_plural = "Items"
162
+ icon = "fa-solid fa-box"
163
+
164
+ column_list: ClassVar = [
165
+ Item.id,
166
+ Item.title,
167
+ Item.is_active,
168
+ Item.created_at,
169
+ ]
170
+ column_searchable_list: ClassVar = [Item.title, Item.description]
171
+ column_sortable_list: ClassVar = [Item.id, Item.title, Item.created_at]
172
+ can_create: ClassVar = True
173
+ can_edit: ClassVar = True
174
+ can_delete: ClassVar = True
175
+ can_view_details: ClassVar = True
176
+ {%- endif %}
177
+
178
+ {%- if cookiecutter.enable_conversation_persistence %}
179
+
180
+
181
+ # === AI Conversations ===
182
+
183
+
184
+ class ConversationAdmin(ModelView, model=Conversation): # type: ignore[call-arg]
185
+ """Conversation admin view."""
186
+
187
+ name = "Conversation"
188
+ name_plural = "Conversations"
189
+ icon = "fa-solid fa-comments"
190
+
191
+ column_list: ClassVar = [
192
+ Conversation.id,
193
+ Conversation.user_id,
194
+ Conversation.title,
195
+ Conversation.is_archived,
196
+ Conversation.created_at,
197
+ ]
198
+ column_searchable_list: ClassVar = [Conversation.title]
199
+ column_sortable_list: ClassVar = [Conversation.id, Conversation.created_at]
200
+ can_create: ClassVar = True
201
+ can_edit: ClassVar = True
202
+ can_delete: ClassVar = True
203
+ can_view_details: ClassVar = True
204
+
205
+
206
+ class MessageAdmin(ModelView, model=Message): # type: ignore[call-arg]
207
+ """Message admin view."""
208
+
209
+ name = "Message"
210
+ name_plural = "Messages"
211
+ icon = "fa-solid fa-message"
212
+
213
+ column_list: ClassVar = [
214
+ Message.id,
215
+ Message.conversation_id,
216
+ Message.role,
217
+ Message.model_name,
218
+ Message.tokens_used,
219
+ Message.created_at,
220
+ ]
221
+ column_searchable_list: ClassVar = [Message.content, Message.role]
222
+ column_sortable_list: ClassVar = [Message.id, Message.role, Message.created_at]
223
+ can_create: ClassVar = True
224
+ can_edit: ClassVar = True
225
+ can_delete: ClassVar = True
226
+ can_view_details: ClassVar = True
227
+
228
+
229
+ class ToolCallAdmin(ModelView, model=ToolCall): # type: ignore[call-arg]
230
+ """ToolCall admin view."""
231
+
232
+ name = "Tool Call"
233
+ name_plural = "Tool Calls"
234
+ icon = "fa-solid fa-wrench"
235
+
236
+ column_list: ClassVar = [
237
+ ToolCall.id,
238
+ ToolCall.message_id,
239
+ ToolCall.tool_name,
240
+ ToolCall.status,
241
+ ToolCall.duration_ms,
242
+ ToolCall.started_at,
243
+ ]
244
+ column_searchable_list: ClassVar = [ToolCall.tool_name, ToolCall.tool_call_id]
245
+ column_sortable_list: ClassVar = [ToolCall.id, ToolCall.tool_name, ToolCall.started_at]
246
+ can_create: ClassVar = False # Tool calls are created by the agent
247
+ can_edit: ClassVar = True
248
+ can_delete: ClassVar = True
249
+ can_view_details: ClassVar = True
250
+ {%- endif %}
251
+
252
+ {%- if cookiecutter.enable_webhooks %}
253
+
254
+
255
+ # === Webhooks ===
256
+
257
+
258
+ class WebhookAdmin(ModelView, model=Webhook): # type: ignore[call-arg]
259
+ """Webhook admin view."""
260
+
261
+ name = "Webhook"
262
+ name_plural = "Webhooks"
263
+ icon = "fa-solid fa-link"
264
+
265
+ column_list: ClassVar = [
266
+ Webhook.id,
267
+ Webhook.name,
268
+ Webhook.url,
269
+ Webhook.is_active,
270
+ Webhook.created_at,
271
+ ]
272
+ column_searchable_list: ClassVar = [Webhook.name, Webhook.url]
273
+ column_sortable_list: ClassVar = [Webhook.id, Webhook.name, Webhook.is_active, Webhook.created_at]
274
+ form_excluded_columns: ClassVar = [Webhook.secret] # Hide secret in forms
275
+ can_create: ClassVar = True
276
+ can_edit: ClassVar = True
277
+ can_delete: ClassVar = True
278
+ can_view_details: ClassVar = True
279
+
280
+
281
+ class WebhookDeliveryAdmin(ModelView, model=WebhookDelivery): # type: ignore[call-arg]
282
+ """WebhookDelivery admin view."""
283
+
284
+ name = "Webhook Delivery"
285
+ name_plural = "Webhook Deliveries"
286
+ icon = "fa-solid fa-paper-plane"
287
+
288
+ column_list: ClassVar = [
289
+ WebhookDelivery.id,
290
+ WebhookDelivery.webhook_id,
291
+ WebhookDelivery.event_type,
292
+ WebhookDelivery.response_status,
293
+ WebhookDelivery.success,
294
+ WebhookDelivery.attempt_count,
295
+ WebhookDelivery.created_at,
296
+ ]
297
+ column_searchable_list: ClassVar = [WebhookDelivery.event_type]
298
+ column_sortable_list: ClassVar = [
299
+ WebhookDelivery.id,
300
+ WebhookDelivery.event_type,
301
+ WebhookDelivery.success,
302
+ WebhookDelivery.created_at,
303
+ ]
304
+ can_create: ClassVar = False # Deliveries are created by webhook dispatch
305
+ can_edit: ClassVar = False
306
+ can_delete: ClassVar = True
307
+ can_view_details: ClassVar = True
308
+ {%- endif %}
309
+
310
+
311
+ def setup_admin(app):
312
+ """Setup SQLAdmin for the FastAPI app."""
313
+ {%- if cookiecutter.admin_require_auth %}
314
+ authentication_backend = AdminAuth(secret_key=settings.SECRET_KEY)
315
+ admin = Admin(
316
+ app,
317
+ sync_engine,
318
+ title="{{ cookiecutter.project_name }} Admin",
319
+ authentication_backend=authentication_backend,
320
+ )
321
+ {%- else %}
322
+ admin = Admin(
323
+ app,
324
+ sync_engine,
325
+ title="{{ cookiecutter.project_name }} Admin",
326
+ )
327
+ {%- endif %}
328
+
329
+ # User management
330
+ admin.add_view(UserAdmin)
331
+ {%- if cookiecutter.enable_session_management %}
332
+ admin.add_view(SessionAdmin)
333
+ {%- endif %}
334
+
335
+ {%- if cookiecutter.include_example_crud %}
336
+ # Items
337
+ admin.add_view(ItemAdmin)
338
+ {%- endif %}
339
+
340
+ {%- if cookiecutter.enable_conversation_persistence %}
341
+ # AI Conversations
342
+ admin.add_view(ConversationAdmin)
343
+ admin.add_view(MessageAdmin)
344
+ admin.add_view(ToolCallAdmin)
345
+ {%- endif %}
346
+
347
+ {%- if cookiecutter.enable_webhooks %}
348
+ # Webhooks
349
+ admin.add_view(WebhookAdmin)
350
+ admin.add_view(WebhookDeliveryAdmin)
351
+ {%- endif %}
352
+
353
+ return admin
354
+ {%- else %}
355
+ """Admin panel - not configured."""
356
+ {%- endif %}