fastapi-fullstack 0.1.11__tar.gz → 0.1.13__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.
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/PKG-INFO +4 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/README.md +3 -1
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/fastapi_gen/config.py +87 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/fastapi_gen/generator.py +34 -14
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/fastapi_gen/prompts.py +130 -32
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/pyproject.toml +10 -1
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/VARIABLES.md +4 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/cookiecutter.json +1 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/hooks/post_gen_project.py +55 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/CLAUDE.md +1 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/admin.py +1 -1
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +10 -0
- fastapi_fullstack-0.1.13/template/{{cookiecutter.project_slug}}/backend/app/agents/crewai_assistant.py +563 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/langchain_assistant.py +4 -3
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +461 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +3 -7
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +2 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +7 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +12 -7
- fastapi_fullstack-0.1.13/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +14 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +10 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +1 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/main.py +8 -2
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +6 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +4 -4
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +9 -9
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +6 -6
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +7 -7
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +9 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +2 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +6 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +39 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/.env.example +5 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +22 -4
- fastapi_fullstack-0.1.13/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +38 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +164 -17
- fastapi_fullstack-0.1.13/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +313 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +1 -1
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +16 -1
- fastapi_fullstack-0.1.11/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +0 -7
- fastapi_fullstack-0.1.11/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +0 -18
- fastapi_fullstack-0.1.11/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +0 -165
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/.gitignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/LICENSE +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/fastapi_gen/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/fastapi_gen/cli.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/.env.prod.example +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/.gitignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/.gitlab-ci.yml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/AGENTS.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/Makefile +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/README.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/.dockerignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/.env.example +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/Dockerfile +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/alembic.ini +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/langgraph_assistant.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/prompts.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/arq_app.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_metrics.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_admin.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docker-compose.yml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docs/adding_features.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docs/architecture.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docs/patterns.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/docs/testing.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/.dockerignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/.gitignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/README.md +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/package.json +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/layout.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/login/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/register/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/chat/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/dashboard/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/layout.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/profile/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/auth/callback/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/layout.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/page.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/copy-button.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/local-conversation-sidebar.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/markdown-content.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/sheet.tsx +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-sidebar-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/local-chat-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/sidebar-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/configmap.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/deployment.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/ingress.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/kustomization.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/namespace.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/secret.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/kubernetes/service.yaml +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/template/{{cookiecutter.project_slug}}/nginx/nginx.conf +0 -0
- {fastapi_fullstack-0.1.11 → fastapi_fullstack-0.1.13}/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.
|
|
3
|
+
Version: 0.1.13
|
|
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
|
|
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
|
|
169
|
+
# Create initial migration (REQUIRED first time)
|
|
168
170
|
make db-migrate
|
|
169
171
|
# Enter message: "Initial migration"
|
|
170
172
|
|
|
@@ -90,6 +90,7 @@ class AIFrameworkType(str, Enum):
|
|
|
90
90
|
PYDANTIC_AI = "pydantic_ai"
|
|
91
91
|
LANGCHAIN = "langchain"
|
|
92
92
|
LANGGRAPH = "langgraph"
|
|
93
|
+
CREWAI = "crewai"
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
class LLMProviderType(str, Enum):
|
|
@@ -178,7 +179,7 @@ class ProjectConfig(BaseModel):
|
|
|
178
179
|
admin_require_auth: bool = True
|
|
179
180
|
enable_websockets: bool = False
|
|
180
181
|
enable_file_storage: bool = False
|
|
181
|
-
enable_ai_agent: bool =
|
|
182
|
+
enable_ai_agent: bool = True
|
|
182
183
|
ai_framework: AIFrameworkType = AIFrameworkType.PYDANTIC_AI
|
|
183
184
|
llm_provider: LLMProviderType = LLMProviderType.OPENAI
|
|
184
185
|
enable_conversation_persistence: bool = False
|
|
@@ -207,7 +208,7 @@ class ProjectConfig(BaseModel):
|
|
|
207
208
|
python_version: str = "3.12"
|
|
208
209
|
|
|
209
210
|
# Frontend
|
|
210
|
-
frontend: FrontendType = FrontendType.
|
|
211
|
+
frontend: FrontendType = FrontendType.NEXTJS
|
|
211
212
|
frontend_port: int = 3000
|
|
212
213
|
|
|
213
214
|
# Backend
|
|
@@ -270,12 +271,95 @@ class ProjectConfig(BaseModel):
|
|
|
270
271
|
and self.llm_provider == LLMProviderType.OPENROUTER
|
|
271
272
|
):
|
|
272
273
|
raise ValueError("OpenRouter is not supported with LangGraph")
|
|
274
|
+
if (
|
|
275
|
+
self.enable_ai_agent
|
|
276
|
+
and self.ai_framework == AIFrameworkType.CREWAI
|
|
277
|
+
and self.llm_provider == LLMProviderType.OPENROUTER
|
|
278
|
+
):
|
|
279
|
+
raise ValueError("OpenRouter is not supported with CrewAI")
|
|
273
280
|
if (
|
|
274
281
|
self.enable_rate_limiting
|
|
275
282
|
and self.rate_limit_storage == RateLimitStorageType.REDIS
|
|
276
283
|
and not self.enable_redis
|
|
277
284
|
):
|
|
278
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
|
+
|
|
279
363
|
return self
|
|
280
364
|
|
|
281
365
|
def to_cookiecutter_context(self) -> dict[str, Any]:
|
|
@@ -353,6 +437,7 @@ class ProjectConfig(BaseModel):
|
|
|
353
437
|
"use_pydantic_ai": self.ai_framework == AIFrameworkType.PYDANTIC_AI,
|
|
354
438
|
"use_langchain": self.ai_framework == AIFrameworkType.LANGCHAIN,
|
|
355
439
|
"use_langgraph": self.ai_framework == AIFrameworkType.LANGGRAPH,
|
|
440
|
+
"use_crewai": self.ai_framework == AIFrameworkType.CREWAI,
|
|
356
441
|
"llm_provider": self.llm_provider.value,
|
|
357
442
|
"use_openai": self.llm_provider == LLMProviderType.OPENAI,
|
|
358
443
|
"use_anthropic": self.llm_provider == LLMProviderType.ANTHROPIC,
|
|
@@ -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
|
|
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
|
|
27
|
-
"make db-migrate
|
|
28
|
-
"make db-upgrade
|
|
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
|
|
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
|
|
38
|
-
"make db-migrate
|
|
39
|
-
"make db-upgrade
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
188
|
-
|
|
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
|
|
160
|
+
"SQLAlchemy — full control, supports admin panel",
|
|
161
161
|
value=OrmType.SQLALCHEMY,
|
|
162
162
|
),
|
|
163
163
|
questionary.Choice(
|
|
164
|
-
"SQLModel
|
|
164
|
+
"SQLModel — less boilerplate, no admin panel support",
|
|
165
165
|
value=OrmType.SQLMODEL,
|
|
166
166
|
),
|
|
167
167
|
]
|
|
@@ -289,36 +289,120 @@ def prompt_background_tasks() -> BackgroundTaskType:
|
|
|
289
289
|
)
|
|
290
290
|
|
|
291
291
|
|
|
292
|
-
def prompt_integrations(
|
|
293
|
-
|
|
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("AI Agent (PydanticAI/LangChain)", value="ai_agent"),
|
|
314
|
-
questionary.Choice("Webhooks (outbound events)", value="webhooks"),
|
|
315
|
-
questionary.Choice("Example CRUD (Item model)", value="example_crud", checked=True),
|
|
316
|
-
questionary.Choice("CORS middleware", value="cors", checked=True),
|
|
317
|
-
questionary.Choice("orjson (faster JSON)", value="orjson", checked=True),
|
|
318
|
-
],
|
|
397
|
+
choices=choices,
|
|
319
398
|
).ask()
|
|
320
399
|
)
|
|
321
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
|
+
|
|
322
406
|
return {
|
|
323
407
|
"enable_redis": "redis" in features,
|
|
324
408
|
"enable_caching": "caching" in features,
|
|
@@ -485,8 +569,8 @@ def prompt_frontend() -> FrontendType:
|
|
|
485
569
|
console.print()
|
|
486
570
|
|
|
487
571
|
choices = [
|
|
488
|
-
questionary.Choice("None (API only)", value=FrontendType.NONE),
|
|
489
572
|
questionary.Choice("Next.js 15 (App Router, TypeScript, Bun)", value=FrontendType.NEXTJS),
|
|
573
|
+
questionary.Choice("None (API only)", value=FrontendType.NONE),
|
|
490
574
|
]
|
|
491
575
|
|
|
492
576
|
return cast(
|
|
@@ -531,6 +615,7 @@ def prompt_ai_framework() -> AIFrameworkType:
|
|
|
531
615
|
questionary.Choice("PydanticAI (recommended)", value=AIFrameworkType.PYDANTIC_AI),
|
|
532
616
|
questionary.Choice("LangChain", value=AIFrameworkType.LANGCHAIN),
|
|
533
617
|
questionary.Choice("LangGraph (ReAct agent)", value=AIFrameworkType.LANGGRAPH),
|
|
618
|
+
questionary.Choice("CrewAI (multi-agent crews)", value=AIFrameworkType.CREWAI),
|
|
534
619
|
]
|
|
535
620
|
|
|
536
621
|
return cast(
|
|
@@ -550,7 +635,7 @@ def prompt_llm_provider(ai_framework: AIFrameworkType) -> LLMProviderType:
|
|
|
550
635
|
|
|
551
636
|
Args:
|
|
552
637
|
ai_framework: The selected AI framework. OpenRouter is only
|
|
553
|
-
available for PydanticAI (not LangChain or
|
|
638
|
+
available for PydanticAI (not LangChain, LangGraph, or CrewAI).
|
|
554
639
|
"""
|
|
555
640
|
console.print()
|
|
556
641
|
console.print("[bold cyan]LLM Provider[/]")
|
|
@@ -561,7 +646,7 @@ def prompt_llm_provider(ai_framework: AIFrameworkType) -> LLMProviderType:
|
|
|
561
646
|
questionary.Choice("Anthropic (claude-sonnet-4-5)", value=LLMProviderType.ANTHROPIC),
|
|
562
647
|
]
|
|
563
648
|
|
|
564
|
-
# OpenRouter only available for PydanticAI (not LangChain or
|
|
649
|
+
# OpenRouter only available for PydanticAI (not LangChain, LangGraph, or CrewAI)
|
|
565
650
|
if ai_framework == AIFrameworkType.PYDANTIC_AI:
|
|
566
651
|
choices.append(
|
|
567
652
|
questionary.Choice("OpenRouter (multi-provider)", value=LLMProviderType.OPENROUTER)
|
|
@@ -579,18 +664,31 @@ def prompt_llm_provider(ai_framework: AIFrameworkType) -> LLMProviderType:
|
|
|
579
664
|
)
|
|
580
665
|
|
|
581
666
|
|
|
582
|
-
def prompt_websocket_auth() -> WebSocketAuthType:
|
|
583
|
-
"""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
|
+
"""
|
|
584
674
|
console.print()
|
|
585
675
|
console.print("[bold cyan]AI Agent WebSocket Authentication[/]")
|
|
586
676
|
console.print()
|
|
587
677
|
|
|
588
678
|
choices = [
|
|
589
679
|
questionary.Choice("None (public access)", value=WebSocketAuthType.NONE),
|
|
590
|
-
questionary.Choice("JWT token required", value=WebSocketAuthType.JWT),
|
|
591
|
-
questionary.Choice("API Key required (query param)", value=WebSocketAuthType.API_KEY),
|
|
592
680
|
]
|
|
593
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
|
+
|
|
594
692
|
return cast(
|
|
595
693
|
WebSocketAuthType,
|
|
596
694
|
_check_cancelled(
|
|
@@ -741,8 +839,8 @@ def run_interactive_prompts() -> ProjectConfig:
|
|
|
741
839
|
# Background tasks
|
|
742
840
|
background_tasks = prompt_background_tasks()
|
|
743
841
|
|
|
744
|
-
# Integrations
|
|
745
|
-
integrations = prompt_integrations()
|
|
842
|
+
# Integrations (pass context for dynamic option filtering)
|
|
843
|
+
integrations = prompt_integrations(database=database, orm_type=orm_type)
|
|
746
844
|
|
|
747
845
|
# Dev tools
|
|
748
846
|
dev_tools = prompt_dev_tools()
|
|
@@ -777,7 +875,7 @@ def run_interactive_prompts() -> ProjectConfig:
|
|
|
777
875
|
if integrations.get("enable_ai_agent"):
|
|
778
876
|
ai_framework = prompt_ai_framework()
|
|
779
877
|
llm_provider = prompt_llm_provider(ai_framework)
|
|
780
|
-
websocket_auth = prompt_websocket_auth()
|
|
878
|
+
websocket_auth = prompt_websocket_auth(auth=auth)
|
|
781
879
|
# Only offer persistence if database is enabled
|
|
782
880
|
if database != DatabaseType.NONE:
|
|
783
881
|
enable_conversation_persistence = _check_cancelled(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-fullstack"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.13"
|
|
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"
|
|
@@ -149,6 +149,9 @@ testpaths = ["tests"]
|
|
|
149
149
|
python_files = ["test_*.py"]
|
|
150
150
|
python_functions = ["test_*"]
|
|
151
151
|
addopts = "-v --tb=short"
|
|
152
|
+
markers = [
|
|
153
|
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
154
|
+
]
|
|
152
155
|
|
|
153
156
|
[tool.coverage.run]
|
|
154
157
|
source = ["fastapi_gen"]
|
|
@@ -162,3 +165,9 @@ exclude_lines = [
|
|
|
162
165
|
"if TYPE_CHECKING:",
|
|
163
166
|
"raise NotImplementedError",
|
|
164
167
|
]
|
|
168
|
+
|
|
169
|
+
[dependency-groups]
|
|
170
|
+
dev = [
|
|
171
|
+
"mypy>=1.19.1",
|
|
172
|
+
"pytest-cov>=7.0.0",
|
|
173
|
+
]
|
|
@@ -187,10 +187,11 @@ These variables are set automatically by the generator.
|
|
|
187
187
|
| Variable | Type | Default | Description | Dependencies |
|
|
188
188
|
|----------|------|---------|-------------|--------------|
|
|
189
189
|
| `enable_ai_agent` | bool | `false` | Enable AI agent functionality | - |
|
|
190
|
-
| `ai_framework` | enum | `"pydantic_ai"` | AI framework. Values: `pydantic_ai`, `langchain`, `langgraph` | Requires `enable_ai_agent` |
|
|
190
|
+
| `ai_framework` | enum | `"pydantic_ai"` | AI framework. Values: `pydantic_ai`, `langchain`, `langgraph`, `crewai` | Requires `enable_ai_agent` |
|
|
191
191
|
| `use_pydantic_ai` | bool | `true` | PydanticAI is selected | Computed from `ai_framework` |
|
|
192
192
|
| `use_langchain` | bool | `false` | LangChain is selected | Computed from `ai_framework` |
|
|
193
193
|
| `use_langgraph` | bool | `false` | LangGraph (ReAct agent) is selected | Computed from `ai_framework` |
|
|
194
|
+
| `use_crewai` | bool | `false` | CrewAI (multi-agent crews) is selected | Computed from `ai_framework` |
|
|
194
195
|
| `llm_provider` | enum | `"openai"` | LLM provider. Values: `openai`, `anthropic`, `openrouter` | Requires `enable_ai_agent` |
|
|
195
196
|
| `use_openai` | bool | `true` | OpenAI is selected | Computed from `llm_provider` |
|
|
196
197
|
| `use_anthropic` | bool | `false` | Anthropic is selected | Computed from `llm_provider` |
|
|
@@ -200,7 +201,8 @@ These variables are set automatically by the generator.
|
|
|
200
201
|
**Notes:**
|
|
201
202
|
- PydanticAI uses `iter()` for full event streaming over WebSocket
|
|
202
203
|
- LangGraph implements a ReAct (Reasoning + Acting) agent pattern with graph-based architecture
|
|
203
|
-
-
|
|
204
|
+
- CrewAI enables multi-agent teams that collaborate on complex tasks
|
|
205
|
+
- OpenRouter with LangChain, LangGraph, or CrewAI is not supported
|
|
204
206
|
|
|
205
207
|
---
|
|
206
208
|
|
|
@@ -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:
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_pydantic_ai %}, PydanticAI{%- endif %}
|
|
14
14
|
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_langchain %}, LangChain{%- endif %}
|
|
15
15
|
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_langgraph %}, LangGraph{%- endif %}
|
|
16
|
+
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_crewai %}, CrewAI{%- endif %}
|
|
16
17
|
{%- if cookiecutter.use_celery %}, Celery{%- endif %}
|
|
17
18
|
{%- if cookiecutter.use_taskiq %}, Taskiq{%- endif %}
|
|
18
19
|
{%- if cookiecutter.use_frontend %}, Next.js 15{%- endif %}
|