# Architecture ## Layers - `molodetz/main.py`: FastAPI object (`/swagger`, `/openapi.json`), lifespan (init lock, `init_db`, bootstrap, services with service lock), static mounts (uploads, versioned `/static/v/`, fallback), middleware in template order, exception handlers, routers. - `molodetz/config.py`: the only place for `load_dotenv`, paths, env bindings with prefix `MOLODETZ_`, `APP_VERSION` via `tomllib`, `BOOT_ID`, `STATIC_VERSION`. - `molodetz/database/`: synchronous `dataset` handle (SQLAlchemy NullPool, WAL PRAGMAs), per-table modules, soft delete with registries, `init_db` with indexes and `ANALYZE`. No async driver and no threadpool around database calls: the synchronous layer is called directly from async handlers (section 7.1). Only CPU and file work (PBKDF2, archive building, DNS) goes through `asyncio.to_thread`. - `molodetz/routers/`: one module per surface. Every HTML route returns JSON on `Accept: application/json` through `responses.respond` and a Pydantic output schema from `schemas/`. `routers/legacy.py` answers the old Dutch paths with 301 (308 for POST), hidden from the schema. - `molodetz/templating.py`: the only `Jinja2Templates`. Globals `static_url`, `local_dt`, `avatar_url`, `render_content` and more. - `molodetz/rendering.py`: server-side markdown (mistune, escaping on), emoji, URL allowlist, dash normalisation. Published content is always rendered on the server. - `molodetz/stealth.py`: the only factory for outbound HTTP clients (httpx with curl_cffi transport, `net_guard` SSRF protection). `link_check.py` uses it for the repo link check on join requests. - `molodetz/services/`: background services (presence, housekeeping, backup) under a `ServiceManager`, visible and controllable at `/admin/services`. - `molodetz/gallery.py`: flyers and memes from `static/media/`, Pillow thumbnails (webp) as blobs under `data/uploads`, perceptual hash (imagehash) against duplicates. - `molodetz/cli/`: argparse CLI `molodetz`. - `molodetz/static/js/`: ES6 modules without a bundler. `Application.js` loads `components/index.js` (custom elements in light DOM) and puts singletons on `window.app`. Vendor: marked, DOMPurify, highlight.js as ES modules in `static/vendor/`. - `molodetz/static/css/`: handwritten, tokens in `variables.css`, breakpoints exactly 360/480/768/1024. ## Auth Session cookie (HttpOnly, SameSite=Lax, Secure behind TLS), rows in `sessions`. Also `X-API-KEY`, `Authorization: Bearer ` and Basic for scripts. Passwords with passlib PBKDF2-SHA256. No JWT, no OAuth. The first user is the administrator from `.env`; there is no public registration. ## Data flows - Writing: administrator -> `/admin/posts` -> `content.create_post` / `edit_post` -> SQLite -> server render on read (lru cache on text). - Joining: visitor -> `POST /join` (honeypot, rate limit) -> `join_requests` -> notification to administrators -> `/admin/joins`. - Gallery: startup -> `sync_gallery` -> `media` table + thumbnails -> `/flyers`, `/memes` with lightbox. - Language: startup -> `bootstrap.migrate_to_english` (once, guarded by setting `content_language`) -> seeded posts, topics, tagline, maintenance message, notifications and admin bio translated in place. Old post slugs resolve through their uid tail and redirect with 301.