Commit graph

7 commits

Author SHA1 Message Date
Jon Seager
dfd9814fa5
fix: add concurrency semaphore for image processing
Limit concurrent image processing tasks to 4 via a tokio::Semaphore on
AppState. Acquired before spawn_blocking in both upload_image() and
save_deferred_image() to prevent CPU/memory exhaustion from concurrent
image uploads.
2026-02-10 17:50:42 +00:00
Jon Seager
4b3f03f5d3
feat: add entity image support with display on detail pages
Add image infrastructure, API, and detail page integration:

- EntityImage domain model with ImageRepository trait
- SQLite storage for images and thumbnails as BLOBs
- Image processing with data URL decoding and thumbnail generation
- REST API: upload, get, delete, thumbnail at /{entity_type}/{id}/image
- resolve_image_url helper for image fallback chains
- image-upload web component for direct upload on detail pages
- Image display with vignette overlay and lightbox viewer
- Template macros: image_thumbnail, readonly_image, lightbox_script
- All 7 detail pages updated with image thumbnails
- Brew images fall back to roast; cup images fall back to cafe then roast
- Delete handler macro extended with optional image cleanup
2026-02-10 17:50:13 +00:00
Jon Seager
000f20eab7
feat(server): auto-enable insecure cookies for localhost defaults
Default BREWLOG_RP_ID to "localhost" and BREWLOG_RP_ORIGIN to
"http://localhost:3000". When these localhost defaults are active,
insecure cookies are enabled automatically so local dev works without
setting BREWLOG_INSECURE_COOKIES. A warning is logged at startup when
insecure cookies are active.

The insecure_cookies flag is now threaded through AppState instead of
reading the env var at cookie-set time.
2026-02-09 17:23:09 +00:00
Jon Seager
97c00f2e33
feat(stats): add pre-computed stats cache with background recomputation
- Add CachedStats domain types (roast summary, consumption, brewing)
- Extend StatsRepository with summary queries and cache get/store
- Add StatsInvalidator + background task with 2s debounce
- Add invalidate() calls to all entity create/update/delete handlers
- Add POST /api/v1/stats/recompute endpoint for manual refresh
- Add stats_cache migration and include in database reset
- Add GeoStats::from_counts() and Serialize/Deserialize derives
- Add 6 integration tests for stats API
- Document Stats Cache pattern in CLAUDE.md
2026-02-08 15:20:01 +00:00
Jon Seager
7f99ffc993
feat(stats): add geographic stats page with choropleth world map
- New /stats page with Roasters, Roasts, Cups, and Cafes tabs
- Interactive choropleth world map (SVG) colored by country counts
- Clickable country chips that highlight individual countries on the map
- Horizontal chip scroller with chevron navigation on desktop
- Datastar-powered tab switching without page reload
- Domain layer: country name → ISO code mapping, flag emoji generation
- StatsRepository trait with four aggregate SQL queries
- <world-map> and <chip-scroll> custom elements for Datastar compatibility
2026-02-08 11:03:15 +00:00
Jon Seager
ca43ad1d00
fix: set HTTP client timeout and remove pagination double-fetch
- Set a 30-second default timeout on the shared reqwest client so
  future call sites can't hang indefinitely.
- Use ensure_page_within() to clamp the page before querying instead
  of fetching, detecting an empty result, and re-fetching.
2026-02-06 18:19:37 +00:00
Jon Seager
4909d24a60
refactor(server): extract AppState into dedicated state module
Move AppState, AppStateConfig, and from_database() out of server.rs
into state.rs so server.rs only contains startup and shutdown logic.
2026-02-06 13:47:59 +00:00