Skip to content

Commit e13c048

Browse files
authored
Merge pull request #1 from IDTS-LAB/development
Development
2 parents 3b72794 + 1ad4431 commit e13c048

91 files changed

Lines changed: 5264 additions & 211 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.git
2+
.github
3+
.mypy_cache
4+
.pytest_cache
5+
.ruff_cache
6+
.venv
7+
__pycache__
8+
*.py[cod]
9+
*.pyo
10+
*.pyd
11+
*.sqlite
12+
*.db
13+
.env
14+
.env.*
15+
!.env.example
16+
Dockerfile
17+
docker-compose*.yml
18+
docs
19+
tests
20+
README.md

.env.example

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,47 @@
11
APP_NAME=Todo Modulith API
22
APP_ENV=production
33

4-
DATABASE_URL=postgresql+asyncpg://postgres:postgres@127.0.0.1:5432/todo_db
4+
POSTGRES_USER=postgres
5+
POSTGRES_PASSWORD=
6+
POSTGRES_DB=todo_db
7+
REDIS_PASSWORD=
58

6-
REDIS_URL=redis://:password@127.0.0.1:6379/0
9+
DATABASE_URL=
10+
DATABASE_POOL_SIZE=20
11+
DATABASE_MAX_OVERFLOW=10
12+
DATABASE_POOL_TIMEOUT=30
13+
DATABASE_POOL_RECYCLE=3600
714

8-
SECRET_KEY=your-super-secret-production-key-here
15+
REDIS_URL=
16+
17+
SECRET_KEY=
18+
19+
MAX_REQUEST_SIZE_MB=5242880 #5mb
920

1021
ALGORITHM=HS256
22+
JWT_ISSUER=todo-modulith-api
23+
JWT_AUDIENCE=todo-modulith-client
1124
ACCESS_TOKEN_EXPIRE_MINUTES=30
1225
REFRESH_TOKEN_EXPIRE_MINUTES=10080
1326

14-
RATE_LIMIT="100/minute"
27+
RATE_LIMIT="100/minute"
28+
29+
CORS_ALLOW_ORIGINS=http://localhost:3000
30+
CORS_ALLOW_METHODS=*
31+
CORS_ALLOW_HEADERS=*
32+
33+
SECURITY_CONTENT_SECURITY_POLICY=default-src 'self'; frame-ancestors 'none'
34+
35+
IDEMPOTENCY_TTL_SECONDS=86400
36+
37+
ACCOUNT_LOCKOUT_MAX_ATTEMPTS=5
38+
ACCOUNT_LOCKOUT_WINDOW_MINUTES=15
39+
ACCOUNT_LOCKOUT_DURATION_MINUTES=15
40+
41+
LOG_FORMAT=json
42+
43+
SEED_ADMIN_EMAIL=
44+
SEED_ADMIN_PASSWORD=
45+
SEED_ADMIN_USERNAME=admin
46+
SEED_ADMIN_FULLNAME=System Administrator
47+
SEED_DEVELOPMENT_USERS_PASSWORD=

.github/workflows/ci.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
tags:
9+
- "v*.*.*"
10+
11+
permissions:
12+
contents: read
13+
packages: write
14+
15+
env:
16+
IMAGE_NAME: ghcr.io/${{ github.repository }}
17+
PYTHON_VERSION: "3.14"
18+
POETRY_VERSION: "2.4.1"
19+
20+
jobs:
21+
verify:
22+
name: Test and lint
23+
runs-on: ubuntu-latest
24+
25+
steps:
26+
- name: Check out repository
27+
uses: actions/checkout@v4
28+
29+
- name: Set up Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: ${{ env.PYTHON_VERSION }}
33+
34+
- name: Install Poetry
35+
run: pipx install poetry==${{ env.POETRY_VERSION }}
36+
37+
- name: Configure Poetry cache
38+
uses: actions/cache@v4
39+
with:
40+
path: ~/.cache/pypoetry
41+
key: poetry-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
42+
restore-keys: |
43+
poetry-${{ runner.os }}-${{ env.PYTHON_VERSION }}-
44+
45+
- name: Install dependencies
46+
run: poetry install --with dev --no-interaction --no-ansi --no-root
47+
48+
- name: Run lint
49+
run: poetry run ruff check src tests scripts
50+
51+
- name: Run tests
52+
run: poetry run pytest -q
53+
54+
docker:
55+
name: Build and publish image
56+
runs-on: ubuntu-latest
57+
needs: verify
58+
59+
steps:
60+
- name: Check out repository
61+
uses: actions/checkout@v4
62+
63+
- name: Set up Docker Buildx
64+
uses: docker/setup-buildx-action@v3
65+
66+
- name: Log in to GHCR
67+
if: github.event_name == 'push'
68+
uses: docker/login-action@v3
69+
with:
70+
registry: ghcr.io
71+
username: ${{ github.actor }}
72+
password: ${{ secrets.GITHUB_TOKEN }}
73+
74+
- name: Extract Docker metadata
75+
id: meta
76+
uses: docker/metadata-action@v5
77+
with:
78+
images: ${{ env.IMAGE_NAME }}
79+
tags: |
80+
type=ref,event=branch
81+
type=ref,event=tag
82+
type=sha,prefix=sha-
83+
84+
- name: Build image
85+
uses: docker/build-push-action@v6
86+
with:
87+
context: .
88+
target: runtime
89+
push: ${{ github.event_name == 'push' }}
90+
tags: ${{ steps.meta.outputs.tags }}
91+
labels: ${{ steps.meta.outputs.labels }}
92+
cache-from: type=gha
93+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,50 @@
1-
FROM python:3.11-slim
1+
FROM python:3.14-slim AS builder
2+
3+
ENV POETRY_VERSION=2.4.1 \
4+
POETRY_NO_INTERACTION=1 \
5+
POETRY_VIRTUALENVS_CREATE=1 \
6+
POETRY_VIRTUALENVS_IN_PROJECT=1 \
7+
PYTHONDONTWRITEBYTECODE=1 \
8+
PYTHONUNBUFFERED=1
29

310
WORKDIR /app
411

5-
# Install Poetry
6-
RUN pip install poetry
12+
RUN apt-get update \
13+
&& apt-get install --no-install-recommends -y build-essential \
14+
&& pip install --no-cache-dir "poetry==${POETRY_VERSION}" \
15+
&& rm -rf /var/lib/apt/lists/*
16+
17+
COPY pyproject.toml poetry.lock ./
18+
19+
RUN poetry install --only main --no-root --no-ansi
720

8-
# Copy dependency files
9-
COPY pyproject.toml poetry.lock* ./
1021

11-
# Install dependencies without dev tools
12-
RUN poetry config virtualenvs.create false \
13-
&& poetry install --no-interaction --no-ansi --no-root
22+
FROM python:3.14-slim AS runtime
1423

15-
# Copy source code
24+
ENV APP_ENV=production \
25+
PATH="/app/.venv/bin:${PATH}" \
26+
PYTHONDONTWRITEBYTECODE=1 \
27+
PYTHONUNBUFFERED=1
28+
29+
WORKDIR /app
30+
31+
RUN groupadd --system app \
32+
&& useradd --system --gid app --home-dir /app --shell /usr/sbin/nologin app
33+
34+
COPY --from=builder /app/.venv /app/.venv
35+
COPY alembic.ini ./
36+
COPY alembic ./alembic
37+
COPY scripts ./scripts
1638
COPY src ./src
1739

18-
# Expose port
40+
RUN chmod +x /app/scripts/start.sh \
41+
&& chown -R app:app /app
42+
43+
USER app
44+
1945
EXPOSE 8000
2046

21-
# Run application
22-
COPY start.sh ./script/start.sh
23-
RUN chmod +x start.sh
47+
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
48+
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3).read()" || exit 1
2449

25-
CMD ["./script/start.sh"]
50+
CMD ["/app/scripts/start.sh"]

Makefile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ COMPOSE_FILE := docker-compose.yml
1010

1111
.DEFAULT_GOAL := help
1212

13-
.PHONY: help install run test lint import-check check migrate downgrade revision db-up db-down db-logs clean
13+
.PHONY: help install run test lint import-check security-scan check migrate seed downgrade revision db-up db-down db-logs clean
1414

1515
help:
1616
@echo "[make:help] Available commands:"
@@ -19,8 +19,10 @@ help:
1919
@echo " [make:test] Run pytest"
2020
@echo " [make:lint] Run Ruff checks"
2121
@echo " [make:import-check] Verify src.main imports"
22+
@echo " [make:security-scan] Run dependency vulnerability scan with pip-audit"
2223
@echo " [make:check] Run tests, lint, and import check"
2324
@echo " [make:migrate] Apply Alembic migrations"
25+
@echo " [make:seed] Seed baseline database records"
2426
@echo " [make:downgrade] Roll back one Alembic migration"
2527
@echo " [make:revision] Create an Alembic migration: make revision name=\"describe change\""
2628
@echo " [make:db-up] Start Docker Compose services"
@@ -42,19 +44,31 @@ test:
4244

4345
lint:
4446
@echo "[make:lint] Running Ruff checks"
45-
@$(RUFF) check src tests
47+
@$(RUFF) check src tests scripts
4648

4749
import-check:
4850
@echo "[make:import-check] Verifying src.main imports"
4951
@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) -c "import src.main; print('import ok')"
5052

53+
security-scan:
54+
@echo "[make:security-scan] Running dependency vulnerability scan"
55+
@if ! command -v pip-audit >/dev/null 2>&1; then \
56+
echo "[make:security-scan] pip-audit is not installed. Install it with: pip install pip-audit"; \
57+
exit 1; \
58+
fi
59+
@pip-audit
60+
5161
check: test lint import-check
5262
@echo "[make:check] All checks completed"
5363

5464
migrate:
5565
@echo "[make:migrate] Applying Alembic migrations"
5666
@$(ALEMBIC) upgrade head
5767

68+
seed:
69+
@echo "[make:seed] Running database seeders"
70+
@$(PYTHON) scripts/seed.py
71+
5872
downgrade:
5973
@echo "[make:downgrade] Rolling back one Alembic migration"
6074
@$(ALEMBIC) downgrade -1

0 commit comments

Comments
 (0)