30 lines
1.4 KiB
Markdown
30 lines
1.4 KiB
Markdown
# Project Memory
|
|
|
|
<!-- This file stores durable project learnings. Agents consult and update it during triage and execution. -->
|
|
|
|
## Architecture
|
|
|
|
<!-- Key architectural patterns, module boundaries, and design decisions -->
|
|
|
|
## Conventions
|
|
|
|
<!-- Project-specific coding standards, naming patterns, file organization -->
|
|
|
|
## Pitfalls
|
|
|
|
<!-- Known issues, common mistakes, and things to avoid -->
|
|
|
|
## Context
|
|
|
|
<!-- Important background information, dependency constraints, deployment notes -->
|
|
|
|
**Headquarter Backend Patterns (FN-004)**
|
|
|
|
- Use SQLAlchemy 2.0 async style with `mapped_column` + `Mapped[]` syntax
|
|
- For Alembic + asyncpg: rewrite `postgresql://` to `postgresql+asyncpg://` in both `app/db.py` and `alembic/env.py`
|
|
- For pytest + async SQLAlchemy testing: use `pytest-asyncio==0.21.2` (not 1.3.0) with `asyncio_mode = "auto"`, `NullPool`, and a session-scoped `event_loop` fixture to avoid event loop mismatches with asyncpg
|
|
- Test DB isolation: `begin_nested()` on a connection + `async_sessionmaker` bound to that connection; override `get_db_session` dependency
|
|
- Secret encryption: derive Fernet key from settings string via `SHA-256 + base64.urlsafe_b64encode`
|
|
- Auth dev bypass: only active when `settings.debug and settings.auth_dev_bypass`; creates/returns a fixed `authentik_sub="dev-user"`
|
|
- JWT production path: fetch OIDC discovery → get `jwks_uri` → fetch JWKS → match by `kid` → decode with `jwt.decode(..., algorithms=["RS256"])`
|