routes/ → Thin HTTP. Parse request, call controller/service, return response.
controllers/ → Business logic orchestration (quest_controller, reasoning_controller).
services/ → Domain logic, AI calls, Docker execution, exports.
repositories/ → SQLAlchemy queries. One repo per model.
models/ → db.py (ORM) + schemas.py (Pydantic). Both must stay in sync.
prompts/ → All LLM prompt templates. NEVER inline prompts elsewhere.
utils/ → json_utils (resilient AI parse), encoding (base64 decode).
- Python 3.12, Ruff linter (E/F/I rules, E501 ignored), 120-char line limit
- Loguru logging everywhere —
from app.logging_config import get_logger; logger = get_logger(__name__) - No custom exceptions — all errors raised as
HTTPException(status_code, detail) - DI hub:
app/dependencies.py— allDepends()providers (repos, services, controllers) - Config:
app/config.py— all env vars viaos.getenv()with defaults. Never read env vars elsewhere.
- SQLite (default
sqlite:///./deepml.db), SQLAlchemy ORM - 6 models:
User,Problem,Submission,Quest,QuestProgress,ProblemSolution - Alembic migrations in
alembic/. Base schema created bycreate_all(), Alembic tracks incremental changes. setup_models.py— DB seeder script (459 lines). Seeds problems from JSON infrontend/public/data/.
routes/auth.py:get_current_user()dependency extracts Bearer token →decode_token()→ user_id or 401services/auth_service.py:create_access_token()/decode_token()(python-jose),hash_password()/verify_password()(bcrypt)repositories/auth_repository.py:get_by_email(),get_by_username(),get_by_id()- JWT payload:
{"sub": user_id, "exp": expiry}. HS256 algorithm. Default 24h expiry.
- Routes:
HTTPException(4xx)for validation/not-found - Controllers:
HTTPException(5xx)for business logic failures - Services:
ValueErrorfor config errors (missing API key, unknown provider) - Executor: Returns error dicts
{"status": "error", "error": "..."}— no exceptions - Global handlers in
main.py: catchStarletteHTTPException+ unhandledException→ structured JSON
slowapi in app/rate_limit.py. IP-based key extraction. Applied on /api/execute and /api/quest/execute. Default: 10/minute (configurable via SANDBOX_RATE_LIMIT).
pytest+ in-memory SQLite. All external calls mocked.conftest.py: function-scoped DB, TestClient, mock AI provider, test user fixture, auth token fixturetest_prompts.py(57+ tests): structural validation — return types, interpolation, negative constraintstest_prompt_consolidation.py(7 tests): AST parsing ensures no inline prompts in services/routes- Run:
pytest --cov=appfor coverage
| File | Purpose |
|---|---|
main.py |
Entry point. load_dotenv() FIRST, then CORS, exception handlers, lifespan, router mount |
app/config.py |
All env vars. Security warning if JWT_SECRET is default |
app/dependencies.py |
Central DI provider for all repos/services/controllers |
app/database.py |
Engine + get_db() session dependency |
app/rate_limit.py |
slowapi limiter instance + key function |
docker-compose.yml |
Backend + sandbox-builder services |
sandbox/Dockerfile |
Python 3.11-slim + numpy/scipy/pandas/sklearn/torch/matplotlib |