A question's stem image is two to four megabytes of scanned radiograph, and a
media grid is forty of those pulled at full size to draw forty postage stamps.
`?w=256` and `?w=640` now serve a WebP copy instead, made on the first ask and
kept beside the original under `thumbs/{width}/{key}` — same bucket, so nothing
new has to be configured for them to be backed up or thrown away.
Three rules, all about not making this a way to spend the server's afternoon.
Those two widths and no others: any other `?w=` is refused with a 400, because
an endpoint that resizes to whatever the query string asks for is a CPU sink
anybody can point at. Never enlarged: a 180px image asked for at 640 is served
as it is, since scaling up invents detail and charges bytes for it. And best
effort throughout — a PDF, an SVG, a truncated upload or a file that is not the
image its name claims all serve their original rather than failing, because a
preview must never take down the page that wanted it.
Authorisation is unchanged and still runs first: a thumbnail of a file you may
not read is a file you may not read. They stay `private, no-store` like
everything else here — they are behind authentication, so there is nothing for
a shared cache to do with them, and the win is the byte count.
EXIF rotation is read before anything measures the image. Every phone stores a
portrait photograph sideways with a flag; a thumbnail made without reading it
is a sideways thumbnail.
Pillow rather than sharp, which is Node. It is not pinned in requirements: the
pin invalidates the pip layer, and that layer no longer builds because
litellm==1.28.13 has been withdrawn from PyPI. Re-pinning litellm is a
deliberate upgrade of the AI layer, not something to slip into this. Noted in
the TODO.
Also: the article hover-card excerpt was printing `[[288|eczema]]` at readers.
The generic markdown-link rule does not know our own cross-reference syntax, so
it left the brackets and the id behind.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
|
||
|---|---|---|
| .. | ||
| quiz-revamp | ||
| adaptive-sessions.md | ||
| api-reference.md | ||
| architecture.md | ||
| deployment.md | ||
| frontend.md | ||
| migrations.md | ||
| quiz-revamp-plan.md | ||
| quiz-revamp-progress.md | ||
| README.md | ||
| services.md | ||
| study-recommendations.md | ||
| tied-conditions.md | ||
| TODO.md | ||
PedsHub Documentation
Deep technical documentation for the PedsHub pediatric learning platform.
Pages
| Document | Description |
|---|---|
| Architecture | System overview, database schema, multi-worker setup, vector search, auth, rate limiting, concurrent quiz protection |
| API Reference | Every endpoint: method, path, auth, request/response, notes |
| Services | Backend service layer: AI extraction, embedding, vector search, PDF processing, email, reminders |
| Frontend | React app structure, pages, components, state patterns, runtime config |
| Deployment | Docker setup, environment variables, HTTPS, rebuilding, monitoring, troubleshooting, scaling |
| Adaptive sessions | What the Adaptive toggle selects, where the code is, and what it deliberately ignores |
| Study recommendations | How focus areas are ranked and what readiness means |
Quick Links
- Main README: ../README.md
- Backend .env template: ../backend/.env.example
- Docker Compose: ../docker-compose.yml