|
| 1 | +# Python Template Server - AI Agent Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +FastAPI-based template server providing reusable infrastructure for building secure HTTPS applications. |
| 6 | +Implements authentication, rate limiting, security headers, and observability foundations via a base `TemplateServer` class. |
| 7 | +Developers extend `TemplateServer` to create application-specific servers (see `ExampleServer` in `main.py`). |
| 8 | + |
| 9 | +## Architecture & Key Components |
| 10 | + |
| 11 | +### Application Factory Pattern |
| 12 | + |
| 13 | +- Entry: `main.py:run()` → instantiates `ExampleServer` (subclass of `TemplateServer`) → calls `.run()` |
| 14 | +- `TemplateServer.__init__()` sets up middleware, rate limiting, metrics, and calls `setup_routes()` |
| 15 | +- **Critical**: Middleware order matters - request logging → security headers → rate limiting |
| 16 | +- **Extensibility**: Subclasses implement `setup_routes()` to add custom endpoints and `validate_config()` for config validation |
| 17 | + |
| 18 | +### Configuration System |
| 19 | + |
| 20 | +- `config.json` loaded via `TemplateServer.load_config()` method |
| 21 | +- Validated using Pydantic models in `models.py` (TemplateServerConfig hierarchy) |
| 22 | +- Subclasses override `validate_config()` to provide custom config models |
| 23 | +- Logging configured automatically on `logging_setup.py` import with rotating file handler |
| 24 | +- Environment variables stored in `.env` (API_TOKEN_HASH only, never commit) |
| 25 | + |
| 26 | +### Authentication Architecture |
| 27 | + |
| 28 | +- **Token Generation**: `uv run generate-new-token` creates secure token + SHA-256 hash |
| 29 | +- **Hash Storage**: Only hash stored in `.env` (API_TOKEN_HASH), raw token shown once |
| 30 | +- **Token Loading**: `load_hashed_token()` loads hash from .env on server startup, stored in `TemplateServer.hashed_token` |
| 31 | +- **Verification Flow**: Request → `_verify_api_key()` dependency → `verify_token()` → hash comparison |
| 32 | +- **Metrics**: Success/failure counters with labeled reasons (missing/invalid/error) |
| 33 | +- **Health Endpoint**: `/api/health` does NOT require authentication, reports unhealthy if token not configured |
| 34 | +- Header: `X-API-Key` (defined in `constants.API_KEY_HEADER_NAME`) |
| 35 | + |
| 36 | +### Rate Limiting |
| 37 | + |
| 38 | +- Uses `slowapi` with configurable storage (in-memory/Redis/Memcached) |
| 39 | +- Applied via `_limit_route()` wrapper when `config.rate_limit.enabled=true` |
| 40 | +- Custom exception handler increments `rate_limit_exceeded_counter` per endpoint |
| 41 | +- Format: `"100/minute"` (supports /second, /minute, /hour) |
| 42 | + |
| 43 | +### Observability Stack |
| 44 | + |
| 45 | +- **Prometheus**: `/metrics` endpoint always exposed (no auth), custom auth/rate-limit metrics |
| 46 | +- **Grafana**: Pre-configured dashboards in `grafana/dashboards/*.json` |
| 47 | +- **Logging**: Dual output (console + rotating file), 10MB per file, 5 backups in `logs/` |
| 48 | +- **Request Tracking**: `RequestLoggingMiddleware` logs all requests with client IP |
| 49 | + |
| 50 | +## Developer Workflows |
| 51 | + |
| 52 | +### Essential Commands |
| 53 | + |
| 54 | +```powershell |
| 55 | +# Setup (first time) |
| 56 | +uv sync # Install dependencies |
| 57 | +uv run generate-certificate # Create self-signed SSL certs (certs/ dir) |
| 58 | +uv run generate-new-token # Generate API key, save hash to .env |
| 59 | +
|
| 60 | +# Development |
| 61 | +uv run python-template-server # Start server (https://localhost:443/api) |
| 62 | +uv run -m pytest # Run tests with coverage |
| 63 | +uv run -m mypy . # Type checking |
| 64 | +uv run -m ruff check . # Linting |
| 65 | +
|
| 66 | +# Docker Development |
| 67 | +docker compose up --build -d # Build + start all services |
| 68 | +docker compose logs -f python-template-server # View logs |
| 69 | +docker compose down # Stop and remove containers |
| 70 | +``` |
| 71 | + |
| 72 | +### Testing Patterns |
| 73 | + |
| 74 | +- **Fixtures**: All tests use `conftest.py` fixtures, auto-mock `pyhere.here()` to tmp_path |
| 75 | +- **Config Mocking**: Use fixtures for consistent test config |
| 76 | +- **Integration Tests**: Test via FastAPI TestClient with auth headers |
| 77 | +- **Coverage Target**: 99% (currently achieved) |
| 78 | +- **Pattern**: Unit tests per module (test\_\*.py) + integration tests (test_template_server.py) |
| 79 | + |
| 80 | +### Docker Multi-Stage Build |
| 81 | + |
| 82 | +- **Stage 1 (builder)**: Uses `uv` to build wheel, copies `configuration/` directory and other required files |
| 83 | +- **Stage 2 (runtime)**: Installs wheel, copies runtime files (.here, configs, LICENSE, README.md) from wheel to /app |
| 84 | +- **Startup Script**: `/app/start.sh` generates token/certs if missing, starts server |
| 85 | +- **Config Selection**: Uses `config.json` for all environments |
| 86 | +- **Build Args**: `PORT=443` (exposes port) |
| 87 | +- **Health Check**: Curls `/api/health` with unverified SSL context (no auth required) |
| 88 | +- **User**: Switches to non-root user `templateserver` (UID 1000) |
| 89 | + |
| 90 | +## Project-Specific Conventions |
| 91 | + |
| 92 | +### Code Organization |
| 93 | + |
| 94 | +- **Handlers**: Separate modules for auth (`authentication_handler.py`), certs (`certificate_handler.py`) |
| 95 | +- **Middleware**: Dedicated package `middleware/` with base classes extending `BaseHTTPMiddleware` |
| 96 | +- **Constants**: All magic strings/numbers in `constants.py` (ports, file names, log config) |
| 97 | +- **Models**: Pydantic models for config + API responses, use `@property` for derived values |
| 98 | + |
| 99 | +### Security Patterns |
| 100 | + |
| 101 | +- **Never log secrets**: Print tokens via `print()`, not `logger` (see `generate_new_token()`) |
| 102 | +- **Path validation**: Use Pydantic validators, Path objects for cert paths |
| 103 | +- **Security headers**: HSTS, CSP, X-Frame-Options via `SecurityHeadersMiddleware` |
| 104 | +- **Cert generation**: RSA-4096, SHA-256, 365-day validity, SANs for localhost |
| 105 | + |
| 106 | +### API Design |
| 107 | + |
| 108 | +- **Prefix**: All routes under `/api` (API_PREFIX constant) |
| 109 | +- **Authentication**: Applied via `dependencies=[Security(self._verify_api_key)]` in route registration |
| 110 | +- **Unauthenticated Endpoints**: `/health` and `/metrics` do not require authentication |
| 111 | +- **Response Models**: All endpoints return `BaseResponse` subclasses with code/message/timestamp |
| 112 | +- **Health Status**: `/health` includes `status` field (HEALTHY/DEGRADED/UNHEALTHY), reports unhealthy if no token configured |
| 113 | + |
| 114 | +### Logging Format |
| 115 | + |
| 116 | +- Format: `[DD/MM/YYYY | HH:MM:SS] (LEVEL) module: message` |
| 117 | +- Client IPs logged in requests: `"Request: GET /api/health from 192.168.1.1"` |
| 118 | +- Auth failures: `"Invalid API key attempt!"` |
| 119 | + |
| 120 | +## Development Constraints |
| 121 | + |
| 122 | +### What's NOT Implemented Yet |
| 123 | + |
| 124 | +- Custom domain-specific endpoints (template provides base functionality only) |
| 125 | +- Database/metadata storage (users implement as needed in subclasses) |
| 126 | +- CORS configuration (can be added by subclasses) |
| 127 | +- API key rotation/expiry |
| 128 | +- Multi-user auth (JWT/OAuth2) |
| 129 | + |
| 130 | +### Testing Requirements |
| 131 | + |
| 132 | +- Mock `pyhere.here()` for all file path tests (see `conftest.py`) |
| 133 | +- Use fixtures for TemplateServer/ExampleServer instantiation |
| 134 | +- Test async endpoints with `@pytest.mark.asyncio` |
| 135 | +- Mock `uvicorn.run` when testing server `.run()` methods |
| 136 | + |
| 137 | +### CI/CD Validation |
| 138 | + |
| 139 | +All PRs must pass: |
| 140 | + |
| 141 | +**CI Workflow:** |
| 142 | + |
| 143 | +1. `validate-pyproject` - pyproject.toml schema validation |
| 144 | +2. `ruff` - linting (120 char line length, strict rules in pyproject.toml) |
| 145 | +3. `mypy` - 100% type coverage (strict mode) |
| 146 | +4. `pytest` - 99% code coverage, HTML report uploaded |
| 147 | +5. `version-check` - pyproject.toml vs uv.lock version consistency |
| 148 | + |
| 149 | +**Docker Workflow:** |
| 150 | + |
| 151 | +1. `docker-development` - Build and test dev image with docker compose |
| 152 | +2. `docker-production` - Build and test prod image with ENV=prod, PORT=443 |
| 153 | + |
| 154 | +## Quick Reference |
| 155 | + |
| 156 | +### Key Files |
| 157 | + |
| 158 | +- `template_server.py` - Base TemplateServer class with middleware/metrics/auth setup |
| 159 | +- `main.py` - ExampleServer implementation showing how to extend TemplateServer |
| 160 | +- `authentication_handler.py` - Token generation, hashing, verification |
| 161 | +- `logging_setup.py` - Logging configuration (executed on import) |
| 162 | +- `models.py` - All Pydantic models (config + responses) |
| 163 | +- `constants.py` - Project constants, logging config |
| 164 | +- `docker-compose.yml` - FastAPI + Prometheus + Grafana stack |
| 165 | + |
| 166 | +### Environment Variables |
| 167 | + |
| 168 | +- `API_TOKEN_HASH` - SHA-256 hash of API token (only var required) |
| 169 | + |
| 170 | +### Configuration Files |
| 171 | + |
| 172 | +- `configuration/config.json` - Configuration (used for all environments) |
| 173 | +- `.env` - API token hash (auto-created by generate-new-token) |
| 174 | +- **Docker**: Startup script uses config.json for all environments |
0 commit comments