Skip to content

Commit 7c8c4f6

Browse files
committed
first commit
1 parent 59f9e50 commit 7c8c4f6

39 files changed

+1321
-1
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.sh text eol=lf
2+
*.py text eol=lf
3+
*.env text eol=lf
4+
*.yml text eol=lf

.github/workflows/ci-cd-main.yml

Whitespace-only changes.

.github/workflows/ci-develop.yml

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
name: CI – Develop Branch
2+
3+
4+
# Triggers
5+
# --------
6+
# • pull_request → quick job (lint + type-check + unit tests)
7+
# • push → full job (quick job + DB migrations + integration tests +
8+
# Docker build & smoke test)
9+
10+
on:
11+
pull_request:
12+
branches: [develop]
13+
push:
14+
branches: [develop]
15+
16+
17+
# Job 1 ─ Quick validation (executed only on pull_request events)
18+
# --------------------------------------------------------------------------- #
19+
# Runs fast checks that give reviewers immediate feedback. No external
20+
# services or Docker are used to keep runtime under one minute.
21+
22+
jobs:
23+
quick:
24+
if: github.event_name == 'pull_request'
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
# Checkout repository
29+
- uses: actions/checkout@v3
30+
31+
# Install Python 3.12
32+
- uses: actions/setup-python@v4
33+
with:
34+
python-version: "3.12"
35+
36+
# Restore Poetry cache for faster installs
37+
- uses: actions/cache@v3
38+
with:
39+
path: ~/.cache/pypoetry
40+
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
41+
42+
# Install project + development dependencies
43+
- name: Install dependencies
44+
run: |
45+
curl -sSL https://install.python-poetry.org | python3 -
46+
poetry config virtualenvs.create false
47+
poetry install --with dev --no-interaction
48+
49+
# Code quality gates
50+
- name: Run Ruff (lint & formatting check)
51+
run: poetry run ruff check src tests
52+
53+
- name: Run MyPy (type-check)
54+
run: poetry run mypy src tests
55+
56+
# Unit-tests only (exclude integration markers)
57+
- name: Run unit tests
58+
run: poetry run pytest -m "not integration" --disable-warnings
59+
60+
61+
62+
# Job 2 ─ Full validation (executed only on push events)
63+
# --------------------------------------------------------------------------- #
64+
# Includes everything from the quick job plus:
65+
# • PostgreSQL service container
66+
# • Alembic migrations
67+
# • Integration tests
68+
# • Multi-stage Docker build and health-check
69+
70+
full:
71+
if: |
72+
github.event_name == 'push' &&
73+
github.ref == 'refs/heads/develop'
74+
runs-on: ubuntu-latest
75+
76+
services:
77+
postgres:
78+
image: postgres:17
79+
env:
80+
POSTGRES_USER: ${{ secrets.DB_USER }}
81+
POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }}
82+
POSTGRES_DB: ${{ secrets.DB_NAME }}
83+
ports: ["5432:5432"]
84+
options: >-
85+
--health-cmd "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"
86+
--health-interval 10s
87+
--health-timeout 5s
88+
--health-retries 5
89+
90+
steps:
91+
- uses: actions/checkout@v3
92+
- uses: actions/setup-python@v4
93+
with: { python-version: '3.12' }
94+
- uses: actions/cache@v3
95+
with:
96+
path: ~/.cache/pypoetry
97+
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
98+
99+
- name: Install dependencies
100+
run: |
101+
curl -sSL https://install.python-poetry.org | python3 -
102+
poetry config virtualenvs.create false
103+
poetry install --with dev --no-interaction
104+
105+
- name: Run Ruff
106+
run: poetry run ruff check src tests
107+
108+
- name: Run mypy
109+
run: poetry run mypy src
110+
111+
- name: Apply Alembic migrations
112+
env:
113+
ENVIRONMENT: test
114+
DB_URL: postgresql+psycopg://${{ secrets.DB_USER }}:${{ secrets.DB_PASSWORD }}@localhost:5432/${{ secrets.DB_NAME }}
115+
run: poetry run alembic upgrade head
116+
117+
- name: Run all tests
118+
env:
119+
ENVIRONMENT: test
120+
DB_URL: postgresql+asyncpg://${{ secrets.DB_USER }}:${{ secrets.DB_PASSWORD }}@localhost:5432/${{ secrets.DB_NAME }}
121+
run: |
122+
poetry run pytest \
123+
--cov=src --cov-report=term \
124+
--disable-warnings
125+
126+
- name: Build Docker image
127+
run: docker build --progress=plain -t backend:ci .
128+
129+
- name: Smoke test container
130+
run: |
131+
# partiamo con --network host così il container condivide la rete del runner
132+
docker run -d \
133+
--name backend_ci \
134+
--network host \
135+
-e ENVIRONMENT=test \
136+
-e DB_URL=postgresql+asyncpg://${{ secrets.DB_USER }}:${{ secrets.DB_PASSWORD }}@localhost:5432/${{ secrets.DB_NAME }} \
137+
backend:ci \
138+
uvicorn app.main:app --host 0.0.0.0 --port 8000
139+
140+
for i in {1..10}; do
141+
if curl --silent --fail http://localhost:8000/health; then
142+
echo "✔ Health OK"; break
143+
else
144+
echo "Waiting…"; sleep 3
145+
fi
146+
done
147+
148+
docker stop backend_ci

.gitignore

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
*.egg-info/
23+
.installed.cfg
24+
*.egg
25+
*.whl
26+
pip-wheel-metadata/
27+
28+
# Virtual environments
29+
.venv/
30+
venv/
31+
ENV/
32+
env/
33+
34+
# Poetry-specific
35+
.cache/pypoetry/
36+
poetry.lock # <– tienilo in repo se vuoi bloccare le versioni; altrimenti aggiungilo
37+
38+
# Installer logs
39+
pip-log.txt
40+
pip-delete-this-directory.txt
41+
42+
# Unit test / coverage reports
43+
htmlcov/
44+
.tox/
45+
.coverage
46+
.coverage.*
47+
.junit.*
48+
nose2-junit.xml
49+
coverage.xml
50+
.cache/
51+
.pytest_cache/
52+
53+
# MyPy
54+
.mypy_cache/
55+
.dmypy.json
56+
57+
# Ruff
58+
.ruff_cache
59+
60+
# Environment variables
61+
.env
62+
.env.* # escludi .env.local, .env.production, etc.
63+
!.env.example # ma tieni il template
64+
65+
# IDEs and editors
66+
.vscode/
67+
.idea/
68+
*.sublime-project
69+
*.sublime-workspace
70+
71+
# OS generated
72+
.DS_Store
73+
Thumbs.db
74+
75+
# Logs
76+
*.log
77+
78+
# Other
79+
*.sqlite3

Dockerfile

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# ─────────────── Build stage ───────────────
2+
FROM python:3.12-slim AS builder
3+
4+
# Install system dependencies for psycopg and build tools
5+
RUN apt-get update \
6+
&& apt-get install -y --no-install-recommends gcc libpq-dev curl \
7+
&& rm -rf /var/lib/apt/lists/*
8+
9+
WORKDIR /opt/app
10+
11+
# Copy only pyproject.toml, poetry.lock, README so we leverage cache
12+
COPY pyproject.toml poetry.lock* README.md ./
13+
14+
# Install Poetry (into /root/.local/bin)
15+
RUN curl -sSL https://install.python-poetry.org | python3 -
16+
17+
# Symlink Poetry into /usr/local/bin so "poetry" is on PATH
18+
RUN ln -s /root/.local/bin/poetry /usr/local/bin/poetry
19+
20+
# Tell Poetry not to create its own venv
21+
RUN poetry config virtualenvs.create false
22+
23+
# Install only the prod deps (uvicorn, fastapi, sqlalchemy, psycopg...)
24+
RUN poetry install --no-root --without dev
25+
26+
# Now copy in your application code
27+
COPY src/ ./src
28+
29+
# ─────────── Runtime stage ───────────
30+
FROM python:3.12-slim AS runtime
31+
32+
WORKDIR /opt/app
33+
34+
# 1) Copy installed libraries
35+
COPY --from=builder /usr/local/lib/python3.12 /usr/local/lib/python3.12
36+
37+
# 2) Copy console scripts (uvicorn, alembic, etc.)
38+
COPY --from=builder /usr/local/bin /usr/local/bin
39+
40+
# 3) Copy application code
41+
COPY --from=builder /opt/app/src ./src
42+
43+
# 4) Non-root user
44+
RUN adduser --disabled-password --gecos '' appuser
45+
USER appuser
46+
47+
WORKDIR /opt/app/src
48+
49+
# 5) Default command
50+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

README.md

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,86 @@
1-
# FastSim-backend
1+
## 🚀 How to Start the Backend with Docker (Development)
2+
3+
To spin up the backend and its supporting services in development mode:
4+
5+
1. **Install & run Docker** on your machine.
6+
2. **Clone** the repository and `cd` into its root.
7+
3. Execute:
8+
9+
```bash
10+
bash ./scripts/init-docker-dev.sh
11+
```
12+
13+
This will launch:
14+
15+
* A **PostgreSQL** container
16+
* A **Backend** container that mounts your local `src/` folder with live-reload
17+
18+
---
19+
20+
## 🏗️ Development Architecture & Philosophy
21+
22+
We split responsibilities between Docker-managed services and local workflows:
23+
24+
### 🐳 Docker-Compose Dev
25+
26+
* **Containers** host external services (PostgreSQL) and run the FastAPI app.
27+
* Your **local `src/` directory** is mounted into the backend container for hot-reload.
28+
* **No tests, migrations, linting, or type checks** run inside these containers during development.
29+
30+
**Why?**
31+
32+
***Instant feedback** on code changes
33+
* 🛠️ **Full IDE support** (debugging, autocomplete, refactoring)
34+
* ⏱️ **Blistering speed**—no rebuilding images on every change
35+
36+
---
37+
38+
### 🧪 Local Quality & Testing Workflow
39+
40+
All code quality tools, migrations, and tests execute on your host machine:
41+
42+
| Task | Command | Notes |
43+
| --------------------- | ---------------------------------------- | ------------------------------------------------- |
44+
| **Lint & format** | `poetry run ruff check src tests` | Style and best-practice validations |
45+
| **Type checking** | `poetry run mypy src tests` | Static type enforcement |
46+
| **Unit tests** | `poetry run pytest -m "not integration"` | Fast, isolated tests—no DB required |
47+
| **Integration tests** | `poetry run pytest -m integration` | Real-DB tests against Docker’s PostgreSQL |
48+
| **DB migrations** | `poetry run alembic upgrade head` | Applies migrations to your local Docker-hosted DB |
49+
50+
> **Rationale:**
51+
> Running tests or Alembic migrations inside Docker images would force you to mount the full source tree, install dev dependencies in each build, and copy over configs—**slowing down** your feedback loop and **limiting** IDE features.
52+
53+
---
54+
55+
## ⚙️ CI/CD with GitHub Actions
56+
57+
We maintain two jobs on the `develop` branch:
58+
59+
### 🔍 Quick (on Pull Requests)
60+
61+
* Ruff & MyPy
62+
* Unit tests only
63+
* **No database** → < 1-minute feedback
64+
65+
### 🛠️ Full (on pushes to `develop`)
66+
67+
* All **Quick** checks
68+
* Start a **PostgreSQL** service container
69+
* Run **Alembic** migrations
70+
* Execute **unit + integration** tests
71+
* Build the **Docker** image
72+
* **Smoke-test** the `/health` endpoint
73+
74+
> **Guarantee:** Every commit in `develop` is style-checked, type-safe, DB-tested, and Docker-ready.
75+
76+
---
77+
78+
## 🧠 Summary
79+
80+
1. **Docker-Compose** for services & hot-reload of the app code
81+
2. **Local** execution of migrations, tests, and QA for speed and IDE integration
82+
3. **CI pipeline** split into quick PR checks and full develop-branch validation
83+
84+
This hybrid setup delivers **fast development** without sacrificing **production-grade safety** in CI.
85+
86+

0 commit comments

Comments
 (0)