fastapi-fullstack 0.1.7__py3-none-any.whl → 0.1.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_fullstack-0.1.7.dist-info → fastapi_fullstack-0.1.15.dist-info}/METADATA +9 -2
- {fastapi_fullstack-0.1.7.dist-info → fastapi_fullstack-0.1.15.dist-info}/RECORD +71 -55
- fastapi_gen/__init__.py +6 -1
- fastapi_gen/cli.py +9 -0
- fastapi_gen/config.py +154 -2
- fastapi_gen/generator.py +34 -14
- fastapi_gen/prompts.py +172 -31
- fastapi_gen/template/VARIABLES.md +33 -4
- fastapi_gen/template/cookiecutter.json +10 -0
- fastapi_gen/template/hooks/post_gen_project.py +87 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/.env.prod.example +9 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/.gitlab-ci.yml +178 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/CLAUDE.md +3 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/README.md +334 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.env.example +32 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +10 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py +1 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +31 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/crewai_assistant.py +563 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/deepagents_assistant.py +526 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/langchain_assistant.py +4 -3
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/langgraph_assistant.py +371 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +1472 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +3 -7
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +2 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +7 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +44 -7
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +7 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +42 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +262 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +76 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +118 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +158 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +185 -3
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py +29 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +6 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +4 -4
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +9 -9
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +6 -6
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +7 -7
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +1 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/arq_app.py +165 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +10 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +40 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_metrics.py +53 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +2 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +6 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +100 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.yml +39 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.env.example +5 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +28 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +1 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +22 -4
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +23 -3
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-approval-dialog.tsx +138 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +242 -18
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +242 -17
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +1 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +57 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/configmap.yaml +63 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/deployment.yaml +242 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/ingress.yaml +44 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/kustomization.yaml +28 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/namespace.yaml +12 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/secret.yaml +59 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/service.yaml +23 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/nginx/nginx.conf +225 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/nginx/ssl/.gitkeep +18 -0
- {fastapi_fullstack-0.1.7.dist-info → fastapi_fullstack-0.1.15.dist-info}/WHEEL +0 -0
- {fastapi_fullstack-0.1.7.dist-info → fastapi_fullstack-0.1.15.dist-info}/entry_points.txt +0 -0
- {fastapi_fullstack-0.1.7.dist-info → fastapi_fullstack-0.1.15.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
{%- if cookiecutter.use_gitlab_ci %}
|
|
2
|
+
# GitLab CI/CD Pipeline for {{ cookiecutter.project_name }}
|
|
3
|
+
|
|
4
|
+
stages:
|
|
5
|
+
- lint
|
|
6
|
+
- test
|
|
7
|
+
- security
|
|
8
|
+
{%- if cookiecutter.enable_docker %}
|
|
9
|
+
- build
|
|
10
|
+
{%- endif %}
|
|
11
|
+
|
|
12
|
+
variables:
|
|
13
|
+
PYTHON_VERSION: "{{ cookiecutter.python_version }}"
|
|
14
|
+
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
|
15
|
+
UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
|
|
16
|
+
|
|
17
|
+
# Cache configuration
|
|
18
|
+
.cache_config: &cache_config
|
|
19
|
+
cache:
|
|
20
|
+
key: "$CI_COMMIT_REF_SLUG"
|
|
21
|
+
paths:
|
|
22
|
+
- .cache/pip
|
|
23
|
+
- .cache/uv
|
|
24
|
+
- backend/.venv
|
|
25
|
+
|
|
26
|
+
# Base Python job template
|
|
27
|
+
.python_base:
|
|
28
|
+
image: python:${PYTHON_VERSION}-slim
|
|
29
|
+
before_script:
|
|
30
|
+
- pip install uv
|
|
31
|
+
- cd backend
|
|
32
|
+
- uv sync --dev
|
|
33
|
+
<<: *cache_config
|
|
34
|
+
|
|
35
|
+
# =============================================================================
|
|
36
|
+
# Lint Stage
|
|
37
|
+
# =============================================================================
|
|
38
|
+
|
|
39
|
+
ruff-check:
|
|
40
|
+
stage: lint
|
|
41
|
+
extends: .python_base
|
|
42
|
+
script:
|
|
43
|
+
- uv run ruff check app tests cli
|
|
44
|
+
rules:
|
|
45
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
46
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
47
|
+
|
|
48
|
+
ruff-format:
|
|
49
|
+
stage: lint
|
|
50
|
+
extends: .python_base
|
|
51
|
+
script:
|
|
52
|
+
- uv run ruff format app tests cli --check
|
|
53
|
+
rules:
|
|
54
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
55
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
56
|
+
|
|
57
|
+
mypy:
|
|
58
|
+
stage: lint
|
|
59
|
+
extends: .python_base
|
|
60
|
+
script:
|
|
61
|
+
- uv run mypy app
|
|
62
|
+
rules:
|
|
63
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
64
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
65
|
+
|
|
66
|
+
# =============================================================================
|
|
67
|
+
# Test Stage
|
|
68
|
+
# =============================================================================
|
|
69
|
+
|
|
70
|
+
test:
|
|
71
|
+
stage: test
|
|
72
|
+
image: python:${PYTHON_VERSION}-slim
|
|
73
|
+
{%- if cookiecutter.use_postgresql or cookiecutter.enable_redis %}
|
|
74
|
+
services:
|
|
75
|
+
{%- if cookiecutter.use_postgresql %}
|
|
76
|
+
- name: postgres:16-alpine
|
|
77
|
+
alias: postgres
|
|
78
|
+
variables:
|
|
79
|
+
POSTGRES_USER: postgres
|
|
80
|
+
POSTGRES_PASSWORD: postgres
|
|
81
|
+
POSTGRES_DB: test_db
|
|
82
|
+
{%- endif %}
|
|
83
|
+
{%- if cookiecutter.enable_redis %}
|
|
84
|
+
- name: redis:7-alpine
|
|
85
|
+
alias: redis
|
|
86
|
+
{%- endif %}
|
|
87
|
+
{%- endif %}
|
|
88
|
+
variables:
|
|
89
|
+
{%- if cookiecutter.use_postgresql %}
|
|
90
|
+
POSTGRES_HOST: postgres
|
|
91
|
+
POSTGRES_PORT: "5432"
|
|
92
|
+
POSTGRES_USER: postgres
|
|
93
|
+
POSTGRES_PASSWORD: postgres
|
|
94
|
+
POSTGRES_DB: test_db
|
|
95
|
+
{%- endif %}
|
|
96
|
+
{%- if cookiecutter.enable_redis %}
|
|
97
|
+
REDIS_HOST: redis
|
|
98
|
+
REDIS_PORT: "6379"
|
|
99
|
+
{%- endif %}
|
|
100
|
+
before_script:
|
|
101
|
+
- pip install uv
|
|
102
|
+
- cd backend
|
|
103
|
+
- uv sync --dev
|
|
104
|
+
script:
|
|
105
|
+
- uv run pytest tests/ -v --cov=app --cov-report=xml --cov-report=term-missing
|
|
106
|
+
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
|
|
107
|
+
artifacts:
|
|
108
|
+
reports:
|
|
109
|
+
coverage_report:
|
|
110
|
+
coverage_format: cobertura
|
|
111
|
+
path: backend/coverage.xml
|
|
112
|
+
expire_in: 1 week
|
|
113
|
+
<<: *cache_config
|
|
114
|
+
rules:
|
|
115
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
116
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# Security Stage
|
|
120
|
+
# =============================================================================
|
|
121
|
+
|
|
122
|
+
security-scan:
|
|
123
|
+
stage: security
|
|
124
|
+
extends: .python_base
|
|
125
|
+
script:
|
|
126
|
+
- uv pip install pip-audit
|
|
127
|
+
- uv run pip-audit --require-hashes=false --progress-spinner=off
|
|
128
|
+
allow_failure: true
|
|
129
|
+
rules:
|
|
130
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
131
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
132
|
+
|
|
133
|
+
{%- if cookiecutter.enable_docker %}
|
|
134
|
+
|
|
135
|
+
# =============================================================================
|
|
136
|
+
# Build Stage
|
|
137
|
+
# =============================================================================
|
|
138
|
+
|
|
139
|
+
docker-build:
|
|
140
|
+
stage: build
|
|
141
|
+
image: docker:24
|
|
142
|
+
services:
|
|
143
|
+
- docker:24-dind
|
|
144
|
+
variables:
|
|
145
|
+
DOCKER_TLS_CERTDIR: "/certs"
|
|
146
|
+
before_script:
|
|
147
|
+
- docker info
|
|
148
|
+
script:
|
|
149
|
+
- docker build -t {{ cookiecutter.project_slug }}:$CI_COMMIT_SHORT_SHA ./backend
|
|
150
|
+
- docker tag {{ cookiecutter.project_slug }}:$CI_COMMIT_SHORT_SHA {{ cookiecutter.project_slug }}:latest
|
|
151
|
+
rules:
|
|
152
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
153
|
+
|
|
154
|
+
# Optional: Push to GitLab Container Registry
|
|
155
|
+
# Uncomment and configure as needed
|
|
156
|
+
#
|
|
157
|
+
# docker-push:
|
|
158
|
+
# stage: build
|
|
159
|
+
# image: docker:24
|
|
160
|
+
# services:
|
|
161
|
+
# - docker:24-dind
|
|
162
|
+
# variables:
|
|
163
|
+
# DOCKER_TLS_CERTDIR: "/certs"
|
|
164
|
+
# before_script:
|
|
165
|
+
# - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
|
166
|
+
# script:
|
|
167
|
+
# - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA ./backend
|
|
168
|
+
# - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
|
169
|
+
# - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:latest
|
|
170
|
+
# - docker push $CI_REGISTRY_IMAGE:latest
|
|
171
|
+
# rules:
|
|
172
|
+
# - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
173
|
+
# needs:
|
|
174
|
+
# - docker-build
|
|
175
|
+
{%- endif %}
|
|
176
|
+
{%- else %}
|
|
177
|
+
# GitLab CI is disabled for this project
|
|
178
|
+
{%- endif %}
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
{%- if cookiecutter.enable_redis %}, Redis{%- endif %}
|
|
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
|
+
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_langgraph %}, LangGraph{%- endif %}
|
|
16
|
+
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_crewai %}, CrewAI{%- endif %}
|
|
17
|
+
{%- if cookiecutter.enable_ai_agent and cookiecutter.use_deepagents %}, DeepAgents{%- endif %}
|
|
15
18
|
{%- if cookiecutter.use_celery %}, Celery{%- endif %}
|
|
16
19
|
{%- if cookiecutter.use_taskiq %}, Taskiq{%- endif %}
|
|
17
20
|
{%- if cookiecutter.use_frontend %}, Next.js 15{%- endif %}
|
|
@@ -144,6 +144,11 @@ cd my_ai_app
|
|
|
144
144
|
make install
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
> **Windows Users:** The `make` command requires GNU Make which is not available by default on Windows.
|
|
148
|
+
> You can either install Make via [Chocolatey](https://chocolatey.org/) (`choco install make`),
|
|
149
|
+
> use WSL (Windows Subsystem for Linux), or use the raw commands from the
|
|
150
|
+
> [Manual Commands Reference](#-manual-commands-reference-windows--no-make) section below.
|
|
151
|
+
|
|
147
152
|
#### Step 2: Start the Database
|
|
148
153
|
{%- if cookiecutter.use_postgresql %}
|
|
149
154
|
|
|
@@ -575,6 +580,224 @@ with logfire.span("process_order", order_id=order.id):
|
|
|
575
580
|
|
|
576
581
|
For more details, see [Logfire Documentation](https://logfire.pydantic.dev/docs/integrations/).
|
|
577
582
|
|
|
583
|
+
{%- if cookiecutter.enable_prometheus %}
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## 📈 Prometheus Metrics
|
|
588
|
+
|
|
589
|
+
This project includes Prometheus metrics for monitoring and alerting.
|
|
590
|
+
|
|
591
|
+
### Accessing Metrics
|
|
592
|
+
|
|
593
|
+
Metrics are exposed at the `/metrics` endpoint:
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
curl http://localhost:{{ cookiecutter.backend_port }}/metrics
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Available Metrics
|
|
600
|
+
|
|
601
|
+
| Metric | Type | Description |
|
|
602
|
+
|--------|------|-------------|
|
|
603
|
+
| `http_requests_total` | Counter | Total HTTP requests by method, path, status |
|
|
604
|
+
| `http_request_duration_seconds` | Histogram | Request latency distribution |
|
|
605
|
+
| `http_requests_inprogress` | Gauge | Currently in-flight requests |
|
|
606
|
+
| `http_request_size_bytes` | Histogram | Request body size |
|
|
607
|
+
| `http_response_size_bytes` | Histogram | Response body size |
|
|
608
|
+
|
|
609
|
+
### Prometheus Configuration
|
|
610
|
+
|
|
611
|
+
Add to your `prometheus.yml`:
|
|
612
|
+
|
|
613
|
+
```yaml
|
|
614
|
+
scrape_configs:
|
|
615
|
+
- job_name: '{{ cookiecutter.project_slug }}'
|
|
616
|
+
static_configs:
|
|
617
|
+
- targets: ['localhost:{{ cookiecutter.backend_port }}']
|
|
618
|
+
metrics_path: /metrics
|
|
619
|
+
scrape_interval: 15s
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Docker Labels
|
|
623
|
+
|
|
624
|
+
When running with Docker, the service includes labels for Prometheus service discovery:
|
|
625
|
+
|
|
626
|
+
```yaml
|
|
627
|
+
labels:
|
|
628
|
+
- "prometheus.scrape=true"
|
|
629
|
+
- "prometheus.port={{ cookiecutter.backend_port }}"
|
|
630
|
+
- "prometheus.path=/metrics"
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Environment Variables
|
|
634
|
+
|
|
635
|
+
| Variable | Default | Description |
|
|
636
|
+
|----------|---------|-------------|
|
|
637
|
+
| `PROMETHEUS_METRICS_PATH` | `/metrics` | Endpoint path for metrics |
|
|
638
|
+
| `PROMETHEUS_INCLUDE_IN_SCHEMA` | `false` | Include in OpenAPI schema |
|
|
639
|
+
{%- endif %}
|
|
640
|
+
|
|
641
|
+
{%- if cookiecutter.use_arq %}
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## ⚡ Background Tasks (ARQ)
|
|
646
|
+
|
|
647
|
+
This project uses [ARQ](https://arq-docs.helpmanual.io/) (Async Redis Queue) for background task processing.
|
|
648
|
+
|
|
649
|
+
### Starting the Worker
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
# Using the CLI
|
|
653
|
+
cd backend
|
|
654
|
+
arq app.worker.arq_app.WorkerSettings
|
|
655
|
+
|
|
656
|
+
# Using Docker
|
|
657
|
+
docker-compose up -d arq_worker
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### Enqueueing Tasks
|
|
661
|
+
|
|
662
|
+
```python
|
|
663
|
+
from arq.connections import ArqRedis, create_pool
|
|
664
|
+
from app.core.config import settings
|
|
665
|
+
|
|
666
|
+
# Create a connection pool
|
|
667
|
+
redis = await create_pool(RedisSettings(
|
|
668
|
+
host=settings.ARQ_REDIS_HOST,
|
|
669
|
+
port=settings.ARQ_REDIS_PORT,
|
|
670
|
+
database=settings.ARQ_REDIS_DB,
|
|
671
|
+
))
|
|
672
|
+
|
|
673
|
+
# Enqueue a task
|
|
674
|
+
await redis.enqueue_job('example_task', 'Hello, World!')
|
|
675
|
+
|
|
676
|
+
# Enqueue with delay
|
|
677
|
+
from datetime import timedelta
|
|
678
|
+
await redis.enqueue_job('example_task', 'Delayed message', _defer_by=timedelta(minutes=5))
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Creating New Tasks
|
|
682
|
+
|
|
683
|
+
Add tasks to `app/worker/arq_app.py`:
|
|
684
|
+
|
|
685
|
+
```python
|
|
686
|
+
async def my_task(ctx: dict, arg1: str, arg2: int) -> dict:
|
|
687
|
+
"""My custom background task."""
|
|
688
|
+
# ctx contains: redis connection, job_id, job_try, etc.
|
|
689
|
+
result = await do_something(arg1, arg2)
|
|
690
|
+
return {"status": "completed", "result": result}
|
|
691
|
+
|
|
692
|
+
# Register in WorkerSettings.functions list
|
|
693
|
+
class WorkerSettings:
|
|
694
|
+
functions = [
|
|
695
|
+
example_task,
|
|
696
|
+
my_task, # Add your task here
|
|
697
|
+
]
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Scheduled Tasks (Cron)
|
|
701
|
+
|
|
702
|
+
```python
|
|
703
|
+
from arq import cron
|
|
704
|
+
|
|
705
|
+
class WorkerSettings:
|
|
706
|
+
cron_jobs = [
|
|
707
|
+
cron(my_scheduled_task, minute=0, hour=0), # Daily at midnight
|
|
708
|
+
cron(my_scheduled_task, minute={0, 30}), # Every 30 minutes
|
|
709
|
+
]
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### Environment Variables
|
|
713
|
+
|
|
714
|
+
| Variable | Default | Description |
|
|
715
|
+
|----------|---------|-------------|
|
|
716
|
+
| `ARQ_REDIS_HOST` | `localhost` | Redis host |
|
|
717
|
+
| `ARQ_REDIS_PORT` | `6379` | Redis port |
|
|
718
|
+
| `ARQ_REDIS_PASSWORD` | `None` | Redis password |
|
|
719
|
+
| `ARQ_REDIS_DB` | `2` | Redis database number |
|
|
720
|
+
{%- endif %}
|
|
721
|
+
|
|
722
|
+
{%- if cookiecutter.enable_kubernetes %}
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## ☸️ Kubernetes Deployment
|
|
727
|
+
|
|
728
|
+
This project includes Kubernetes manifests for production deployment.
|
|
729
|
+
|
|
730
|
+
### Quick Deploy
|
|
731
|
+
|
|
732
|
+
```bash
|
|
733
|
+
# Using kustomize (recommended)
|
|
734
|
+
kubectl apply -k kubernetes/
|
|
735
|
+
|
|
736
|
+
# Or apply individually
|
|
737
|
+
kubectl apply -f kubernetes/namespace.yaml
|
|
738
|
+
kubectl apply -f kubernetes/configmap.yaml
|
|
739
|
+
kubectl apply -f kubernetes/secret.yaml
|
|
740
|
+
kubectl apply -f kubernetes/deployment.yaml
|
|
741
|
+
kubectl apply -f kubernetes/service.yaml
|
|
742
|
+
kubectl apply -f kubernetes/ingress.yaml
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Manifest Files
|
|
746
|
+
|
|
747
|
+
| File | Description |
|
|
748
|
+
|------|-------------|
|
|
749
|
+
| `namespace.yaml` | Creates dedicated namespace |
|
|
750
|
+
| `configmap.yaml` | Non-sensitive configuration |
|
|
751
|
+
| `secret.yaml` | Sensitive data (passwords, API keys) |
|
|
752
|
+
| `deployment.yaml` | Backend + worker deployments |
|
|
753
|
+
| `service.yaml` | ClusterIP service for backend |
|
|
754
|
+
| `ingress.yaml` | External access with nginx ingress |
|
|
755
|
+
| `kustomization.yaml` | Kustomize configuration |
|
|
756
|
+
|
|
757
|
+
### Before Deploying
|
|
758
|
+
|
|
759
|
+
1. **Update secrets** in `kubernetes/secret.yaml`:
|
|
760
|
+
```bash
|
|
761
|
+
# Generate a secure SECRET_KEY
|
|
762
|
+
openssl rand -hex 32
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
2. **Configure ingress** in `kubernetes/ingress.yaml`:
|
|
766
|
+
- Replace `api.example.com` with your domain
|
|
767
|
+
- Uncomment TLS section for HTTPS
|
|
768
|
+
|
|
769
|
+
3. **Build and push Docker image**:
|
|
770
|
+
```bash
|
|
771
|
+
docker build -t your-registry/{{ cookiecutter.project_slug }}:latest ./backend
|
|
772
|
+
docker push your-registry/{{ cookiecutter.project_slug }}:latest
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
4. **Update image** in `kubernetes/kustomization.yaml`:
|
|
776
|
+
```yaml
|
|
777
|
+
images:
|
|
778
|
+
- name: {{ cookiecutter.project_slug }}
|
|
779
|
+
newName: your-registry/{{ cookiecutter.project_slug }}
|
|
780
|
+
newTag: latest
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Scaling
|
|
784
|
+
|
|
785
|
+
```bash
|
|
786
|
+
# Scale backend replicas
|
|
787
|
+
kubectl scale deployment {{ cookiecutter.project_slug }}-backend -n {{ cookiecutter.project_slug }} --replicas=3
|
|
788
|
+
|
|
789
|
+
# View pods
|
|
790
|
+
kubectl get pods -n {{ cookiecutter.project_slug }}
|
|
791
|
+
|
|
792
|
+
# View logs
|
|
793
|
+
kubectl logs -f deployment/{{ cookiecutter.project_slug }}-backend -n {{ cookiecutter.project_slug }}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Using with Helm (optional)
|
|
797
|
+
|
|
798
|
+
For more advanced deployments, consider creating a Helm chart based on these manifests.
|
|
799
|
+
{%- endif %}
|
|
800
|
+
|
|
578
801
|
---
|
|
579
802
|
|
|
580
803
|
## 🛠️ Django-style CLI
|
|
@@ -635,6 +858,117 @@ uv run {{ cookiecutter.project_slug }} cmd seed --dry-run
|
|
|
635
858
|
|
|
636
859
|
---
|
|
637
860
|
|
|
861
|
+
## 🖥️ Manual Commands Reference (Windows / No Make)
|
|
862
|
+
|
|
863
|
+
If you don't have `make` installed (common on Windows), use these commands directly.
|
|
864
|
+
All commands should be run from the project root directory.
|
|
865
|
+
|
|
866
|
+
### Setup & Development
|
|
867
|
+
|
|
868
|
+
| Task | Command |
|
|
869
|
+
|------|---------|
|
|
870
|
+
| Install dependencies | `uv sync --directory backend --dev` |
|
|
871
|
+
| Start dev server | `uv run --directory backend {{ cookiecutter.project_slug }} server run --reload` |
|
|
872
|
+
| Start prod server | `uv run --directory backend {{ cookiecutter.project_slug }} server run --host 0.0.0.0 --port {{ cookiecutter.backend_port }}` |
|
|
873
|
+
| Show routes | `uv run --directory backend {{ cookiecutter.project_slug }} server routes` |
|
|
874
|
+
|
|
875
|
+
### Code Quality
|
|
876
|
+
|
|
877
|
+
| Task | Command |
|
|
878
|
+
|------|---------|
|
|
879
|
+
| Format code | `uv run --directory backend ruff format app tests cli` |
|
|
880
|
+
| Fix lint issues | `uv run --directory backend ruff check app tests cli --fix` |
|
|
881
|
+
| Check linting | `uv run --directory backend ruff check app tests cli` |
|
|
882
|
+
| Type check | `uv run --directory backend mypy app` |
|
|
883
|
+
|
|
884
|
+
### Testing
|
|
885
|
+
|
|
886
|
+
| Task | Command |
|
|
887
|
+
|------|---------|
|
|
888
|
+
| Run tests | `uv run --directory backend pytest tests/ -v` |
|
|
889
|
+
| Run with coverage | `uv run --directory backend pytest tests/ -v --cov=app --cov-report=term-missing` |
|
|
890
|
+
|
|
891
|
+
{%- if cookiecutter.use_postgresql or cookiecutter.use_sqlite %}
|
|
892
|
+
|
|
893
|
+
### Database
|
|
894
|
+
|
|
895
|
+
| Task | Command |
|
|
896
|
+
|------|---------|
|
|
897
|
+
| Create migration | `uv run --directory backend {{ cookiecutter.project_slug }} db migrate -m "message"` |
|
|
898
|
+
| Apply migrations | `uv run --directory backend {{ cookiecutter.project_slug }} db upgrade` |
|
|
899
|
+
| Rollback migration | `uv run --directory backend {{ cookiecutter.project_slug }} db downgrade` |
|
|
900
|
+
| Show current | `uv run --directory backend {{ cookiecutter.project_slug }} db current` |
|
|
901
|
+
| Show history | `uv run --directory backend {{ cookiecutter.project_slug }} db history` |
|
|
902
|
+
{%- endif %}
|
|
903
|
+
|
|
904
|
+
{%- if cookiecutter.use_jwt %}
|
|
905
|
+
|
|
906
|
+
### Users
|
|
907
|
+
|
|
908
|
+
| Task | Command |
|
|
909
|
+
|------|---------|
|
|
910
|
+
| Create admin | `uv run --directory backend {{ cookiecutter.project_slug }} user create-admin` |
|
|
911
|
+
| Create user | `uv run --directory backend {{ cookiecutter.project_slug }} user create` |
|
|
912
|
+
| List users | `uv run --directory backend {{ cookiecutter.project_slug }} user list` |
|
|
913
|
+
{%- endif %}
|
|
914
|
+
|
|
915
|
+
{%- if cookiecutter.use_celery %}
|
|
916
|
+
|
|
917
|
+
### Celery
|
|
918
|
+
|
|
919
|
+
| Task | Command |
|
|
920
|
+
|------|---------|
|
|
921
|
+
| Start worker | `uv run --directory backend {{ cookiecutter.project_slug }} celery worker` |
|
|
922
|
+
| Start beat | `uv run --directory backend {{ cookiecutter.project_slug }} celery beat` |
|
|
923
|
+
| Start flower | `uv run --directory backend {{ cookiecutter.project_slug }} celery flower` |
|
|
924
|
+
{%- endif %}
|
|
925
|
+
|
|
926
|
+
{%- if cookiecutter.use_taskiq %}
|
|
927
|
+
|
|
928
|
+
### Taskiq
|
|
929
|
+
|
|
930
|
+
| Task | Command |
|
|
931
|
+
|------|---------|
|
|
932
|
+
| Start worker | `uv run --directory backend {{ cookiecutter.project_slug }} taskiq worker` |
|
|
933
|
+
| Start scheduler | `uv run --directory backend {{ cookiecutter.project_slug }} taskiq scheduler` |
|
|
934
|
+
{%- endif %}
|
|
935
|
+
|
|
936
|
+
{%- if cookiecutter.use_arq %}
|
|
937
|
+
|
|
938
|
+
### ARQ
|
|
939
|
+
|
|
940
|
+
| Task | Command |
|
|
941
|
+
|------|---------|
|
|
942
|
+
| Start worker | `arq app.worker.arq_app.WorkerSettings` (from backend/) |
|
|
943
|
+
{%- endif %}
|
|
944
|
+
|
|
945
|
+
{%- if cookiecutter.enable_docker %}
|
|
946
|
+
|
|
947
|
+
### Docker
|
|
948
|
+
|
|
949
|
+
| Task | Command |
|
|
950
|
+
|------|---------|
|
|
951
|
+
| Start all services | `docker-compose up -d` |
|
|
952
|
+
| Stop all services | `docker-compose down` |
|
|
953
|
+
| View logs | `docker-compose logs -f` |
|
|
954
|
+
| Build images | `docker-compose build` |
|
|
955
|
+
{%- if cookiecutter.use_postgresql %}
|
|
956
|
+
| Start PostgreSQL only | `docker-compose up -d db` |
|
|
957
|
+
{%- endif %}
|
|
958
|
+
{%- if cookiecutter.enable_redis %}
|
|
959
|
+
| Start Redis only | `docker-compose up -d redis` |
|
|
960
|
+
{%- endif %}
|
|
961
|
+
| Start production | `docker-compose -f docker-compose.prod.yml up -d` |
|
|
962
|
+
{%- endif %}
|
|
963
|
+
|
|
964
|
+
### Cleanup
|
|
965
|
+
|
|
966
|
+
| Task | Command (Unix) | Command (Windows PowerShell) |
|
|
967
|
+
|------|----------------|------------------------------|
|
|
968
|
+
| Clean cache | `find . -type d -name __pycache__ -exec rm -rf {} +` | `Get-ChildItem -Recurse -Directory -Filter __pycache__ \| Remove-Item -Recurse -Force` |
|
|
969
|
+
|
|
970
|
+
---
|
|
971
|
+
|
|
638
972
|
## 📁 Generated Project Structure
|
|
639
973
|
|
|
640
974
|
```
|
|
@@ -79,12 +79,28 @@ TASKIQ_BROKER_URL=redis://localhost:6379/1
|
|
|
79
79
|
TASKIQ_RESULT_BACKEND=redis://localhost:6379/1
|
|
80
80
|
{%- endif %}
|
|
81
81
|
|
|
82
|
+
{%- if cookiecutter.use_arq %}
|
|
83
|
+
|
|
84
|
+
# === ARQ (Async Redis Queue) ===
|
|
85
|
+
ARQ_REDIS_HOST=localhost
|
|
86
|
+
ARQ_REDIS_PORT=6379
|
|
87
|
+
# ARQ_REDIS_PASSWORD=
|
|
88
|
+
ARQ_REDIS_DB=2
|
|
89
|
+
{%- endif %}
|
|
90
|
+
|
|
82
91
|
{%- if cookiecutter.enable_sentry %}
|
|
83
92
|
|
|
84
93
|
# === Sentry ===
|
|
85
94
|
SENTRY_DSN=
|
|
86
95
|
{%- endif %}
|
|
87
96
|
|
|
97
|
+
{%- if cookiecutter.enable_prometheus %}
|
|
98
|
+
|
|
99
|
+
# === Prometheus ===
|
|
100
|
+
PROMETHEUS_METRICS_PATH=/metrics
|
|
101
|
+
PROMETHEUS_INCLUDE_IN_SCHEMA=false
|
|
102
|
+
{%- endif %}
|
|
103
|
+
|
|
88
104
|
{%- if cookiecutter.enable_file_storage %}
|
|
89
105
|
|
|
90
106
|
# === S3/MinIO Storage ===
|
|
@@ -120,6 +136,22 @@ LANGCHAIN_API_KEY=
|
|
|
120
136
|
LANGCHAIN_PROJECT={{ cookiecutter.project_slug }}
|
|
121
137
|
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
|
|
122
138
|
{%- endif %}
|
|
139
|
+
{%- if cookiecutter.use_deepagents %}
|
|
140
|
+
|
|
141
|
+
# === DeepAgents Configuration ===
|
|
142
|
+
# Skills paths (comma-separated, relative paths e.g. "/skills/user/,/skills/project/")
|
|
143
|
+
DEEPAGENTS_SKILLS_PATHS=
|
|
144
|
+
# Enable/disable built-in tools
|
|
145
|
+
DEEPAGENTS_ENABLE_FILESYSTEM=true
|
|
146
|
+
DEEPAGENTS_ENABLE_EXECUTE=false
|
|
147
|
+
DEEPAGENTS_ENABLE_TODOS=true
|
|
148
|
+
DEEPAGENTS_ENABLE_SUBAGENTS=true
|
|
149
|
+
# Human-in-the-loop: tools requiring approval (comma-separated, or "all")
|
|
150
|
+
# e.g. "write_file,edit_file,execute" or leave empty to disable HITL
|
|
151
|
+
DEEPAGENTS_INTERRUPT_TOOLS=
|
|
152
|
+
# Allowed decisions for interrupted tools (approve, edit, reject)
|
|
153
|
+
DEEPAGENTS_ALLOWED_DECISIONS=approve,edit,reject
|
|
154
|
+
{%- endif %}
|
|
123
155
|
{%- endif %}
|
|
124
156
|
|
|
125
157
|
{%- if cookiecutter.enable_cors %}
|
|
@@ -6,11 +6,16 @@ from logging.config import fileConfig
|
|
|
6
6
|
|
|
7
7
|
from alembic import context
|
|
8
8
|
from sqlalchemy import engine_from_config, pool
|
|
9
|
+
{%- if cookiecutter.use_sqlmodel %}
|
|
10
|
+
from sqlmodel import SQLModel
|
|
11
|
+
{%- endif %}
|
|
9
12
|
|
|
10
13
|
from app.core.config import settings
|
|
14
|
+
{%- if not cookiecutter.use_sqlmodel %}
|
|
11
15
|
from app.db.base import Base
|
|
16
|
+
{%- endif %}
|
|
12
17
|
|
|
13
|
-
# Import all models here to ensure they are registered with
|
|
18
|
+
# Import all models here to ensure they are registered with metadata
|
|
14
19
|
{%- if cookiecutter.use_jwt %}
|
|
15
20
|
from app.db.models.user import User # noqa: F401
|
|
16
21
|
{%- endif %}
|
|
@@ -20,7 +25,11 @@ config = context.config
|
|
|
20
25
|
if config.config_file_name is not None:
|
|
21
26
|
fileConfig(config.config_file_name)
|
|
22
27
|
|
|
28
|
+
{%- if cookiecutter.use_sqlmodel %}
|
|
29
|
+
target_metadata = SQLModel.metadata
|
|
30
|
+
{%- else %}
|
|
23
31
|
target_metadata = Base.metadata
|
|
32
|
+
{%- endif %}
|
|
24
33
|
|
|
25
34
|
|
|
26
35
|
def get_url() -> str:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{%- if cookiecutter.enable_admin_panel and cookiecutter.use_postgresql %}
|
|
1
|
+
{%- if cookiecutter.enable_admin_panel and (cookiecutter.use_postgresql or cookiecutter.use_sqlite) and cookiecutter.use_sqlalchemy %}
|
|
2
2
|
"""SQLAdmin configuration with automatic model discovery."""
|
|
3
3
|
|
|
4
4
|
from typing import Any, ClassVar
|
|
@@ -18,6 +18,37 @@ Tools are defined in the tools/ subdirectory.
|
|
|
18
18
|
from app.agents.langchain_assistant import AgentContext, AgentState, LangChainAssistant
|
|
19
19
|
|
|
20
20
|
__all__ = ["LangChainAssistant", "AgentContext", "AgentState"]
|
|
21
|
+
{%- elif cookiecutter.enable_ai_agent and cookiecutter.use_langgraph %}
|
|
22
|
+
"""AI Agents module using LangGraph.
|
|
23
|
+
|
|
24
|
+
This module contains a ReAct agent built with LangGraph.
|
|
25
|
+
Tools are defined in the tools/ subdirectory.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from app.agents.langgraph_assistant import AgentContext, AgentState, LangGraphAssistant
|
|
29
|
+
|
|
30
|
+
__all__ = ["LangGraphAssistant", "AgentContext", "AgentState"]
|
|
31
|
+
{%- elif cookiecutter.enable_ai_agent and cookiecutter.use_crewai %}
|
|
32
|
+
"""AI Agents module using CrewAI.
|
|
33
|
+
|
|
34
|
+
This module contains a multi-agent crew built with CrewAI.
|
|
35
|
+
Agents work together in a team to accomplish complex tasks.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from app.agents.crewai_assistant import CrewAIAssistant, CrewConfig, CrewContext
|
|
39
|
+
|
|
40
|
+
__all__ = ["CrewAIAssistant", "CrewConfig", "CrewContext"]
|
|
41
|
+
{%- elif cookiecutter.enable_ai_agent and cookiecutter.use_deepagents %}
|
|
42
|
+
"""AI Agents module using DeepAgents.
|
|
43
|
+
|
|
44
|
+
This module contains an agentic coding assistant built with DeepAgents.
|
|
45
|
+
DeepAgents provides built-in tools for filesystem operations, task management,
|
|
46
|
+
and code execution.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from app.agents.deepagents_assistant import AgentContext, AgentState, DeepAgentsAssistant
|
|
50
|
+
|
|
51
|
+
__all__ = ["DeepAgentsAssistant", "AgentContext", "AgentState"]
|
|
21
52
|
{%- else %}
|
|
22
53
|
"""AI Agents - not configured."""
|
|
23
54
|
{%- endif %}
|