Struktura projektu, venv i zależności

Powtarzalna struktura projektu sprawia, że każdy serwis ZEUS wygląda tak samo i nowa osoba odnajduje się w nim w pięć minut. Do tego dochodzi izolacja środowiska i deterministyczne zależności.

Struktura katalogów

Backendowe serwisy ZEUS trzymamy w układzie warstwowym:

service-inventory/
├── app/
│   ├── __init__.py
│   ├── main.py            # tworzenie aplikacji FastAPI
│   ├── api/               # routery (warstwa HTTP)
│   ├── core/              # config, security, ustawienia
│   ├── models/            # modele SQLAlchemy
│   ├── schemas/           # modele Pydantic (DTO)
│   ├── services/          # logika domenowa
│   ├── workers/           # zadania ARQ
│   └── db/                # sesja, migracje
├── tests/
├── pyproject.toml
└── README.md

Standard ProfessNet: routery nie zawierają logiki domenowej. Endpoint waliduje wejście (Pydantic), woła services/ i zwraca wynik. Logika żyje w services/, dostęp do bazy w models/ + db/.

Wirtualne środowisko (venv)

Każdy serwis ma własne, izolowane środowisko. Nigdy nie instalujemy paczek globalnie.

python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Zależności w pyproject.toml

Zależności deklarujemy w pyproject.toml, nie w gołym requirements.txt. Rozdzielamy zależności produkcyjne od deweloperskich.

[project]
name = "service-inventory"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115",
    "sqlalchemy[asyncio]>=2.0",
    "arq>=0.26",
    "pydantic>=2.7",
]

[project.optional-dependencies]
dev = ["pytest", "pytest-asyncio", "mypy", "ruff", "black"]

Przypinanie wersji (lock)

Dla deterministycznych buildów generujemy plik lock. W ProfessNet używamy uv (szybki resolver) albo pip-tools:

uv lock                 # tworzy uv.lock
uv sync                 # instaluje dokładnie to, co w locku

Standard ProfessNet: zakres wersji (>=) deklarujemy w pyproject.toml, a dokładne wersje przypinamy w pliku lock, który commitujemy do repo. CI i produkcja instalują z locka — to gwarantuje powtarzalność.

Zmienne środowiskowe

Konfiguracji nie zaszywamy w kodzie. Czytamy ją przez Pydantic Settings:

from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    database_url: str
    redis_url: str

    class Config:
        env_file = ".env"

Plik .env jest w .gitignore — w repo trzymamy tylko .env.example.

PlikCommitujemy?
pyproject.tomltak
uv.lock / requirements.txttak
.env.exampletak
.envnie (sekrety)
.venv/nie

Jednolita struktura + izolowane venv + lock = serwis, który buduje się tak samo na laptopie, w CI i na produkcji. To fundament, na którym budujemy FastAPI.