diff --git a/.gitignore b/.gitignore index 4f00b33..2de0525 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ logs/ input/ output/ allure-results/ -.coverage \ No newline at end of file +.coverage +graphify-out/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 389b054..5b80f96 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,6 +20,13 @@ workers. Python >=3.13,<4.0, Poetry for dependency management. - `secure` flag on refresh_token cookie is driven by `env_settings.PROD_MODE` (bool) — `False` locally/tests so cookies work over plain HTTP, `True` in prod. +- **CORS**: `CORSMiddleware` in `main.py` with `allow_origins=[env_settings. + FRONT_URL]` and `allow_credentials=True` (needed for the httpOnly + `refresh_token` cookie — with credentials, `["*"]` is rejected by browsers). + `FRONT_URL` is a required `Env` field with no default, so the backend fails + to start without it in `configs/.env` (e.g. `http://localhost:5173`). It is + added last, after the logging middlewares, so it wraps them and CORS + headers also appear on error responses (401/429). ## Redis (`src/cache/`) @@ -27,12 +34,15 @@ workers. Python >=3.13,<4.0, Poetry for dependency management. `redis.Redis` directly (inherits all commands, no manual wrapping needed). - Three uses: permissions is-cache was considered and rejected (no real DB savings — `get_user_by_id` already eager-loads everything via `selectin` - in one call); rate limiting on login (`RateLimit.rate_limit(ip)` — - `INCR` + `EXPIRE` on first attempt, blocks >5/60s); access-token revoke - blacklist (see above). -- Rate limit is only triggered inside `except HTTPException` on `/protected/token` - — i.e. only on failed logins, not successful ones (otherwise legitimate - repeated logins would trip it). + in one call); rate limiting (`RateLimit.rate_limit(ip, action, limit=5, + window=60)` — `INCR` + `EXPIRE ... NX` on first attempt, key + `rate_limit:{action}:{ip}`, so each action has its own counter); access-token + revoke blacklist (see above). +- Two rate-limited actions: `"login"` (5/60s) and `"reset"` (3/600s). + The login limit is only triggered inside `except HTTPException` on + `/protected/token` — i.e. only on failed logins, not successful ones + (otherwise legitimate repeated logins would trip it). `/protected/reset` + counts every call. ## RabbitMQ (`src/messaging/`) @@ -89,11 +99,26 @@ workers. Python >=3.13,<4.0, Poetry for dependency management. `src/service/email/templates/`), inline CSS (email clients don't support `