Project layout
app/
├── main.py FastAPI routes, session middleware, CSRF check
├── auth.py accounts, identities, passwords, sessions, invites
├── oauth.py OAuth2/OIDC client and the provider registry
├── mailer.py optional SMTP, used only for reset links
├── backup.py verified database snapshots and rotation
├── integrity.py full-file hashing and drift detection
├── media.py every image URL, and the page cache behind the reader
├── convert.py ComicInfo write-back and container conversion
├── cli.py command-line account recovery
├── config.py environment configuration
├── db.py SQLite schema and migrations
├── archives.py CBZ/CBR/CB7/CBT/PDF/EPUB reading
├── metadata.py ComicInfo.xml and filename parsing
├── covers.py cover extraction and thumbnails
├── scanner.py filesystem walking and per-user browse permissions
├── importer.py import pipeline and background job runner
├── comicvine.py Comic Vine client, cache and matching
├── matching.py source-independent series and issue matching rules
├── providers/ metadata sources behind one interface (Comic Vine, Metron)
├── skins.py colour palettes: validation, contrast checking, storage
├── diskusage.py free space per device, for import/upload locations
├── library.py search, filters, facets, edits — all user-scoped
├── templates/ Jinja2 pages
└── static/ one stylesheet, one script
CLAUDE.md decisions and their reasoning, and what is next
docs/
├── architecture.md what it would take to scale this, and what to decide now
└── skins.md the skin authoring contract
tests/
├── run.py runs every suite
├── _support.py shared bootstrap and assertions
├── make_samples.py generates the sample collection
└── schema_v1.sql the pre-multi-user schema, for the migration test
vendor/ comiccore/ebookcore, vendored -- see vendor/README.md