Commit graph

554 commits

Author SHA1 Message Date
Jon Seager
78cc66972d
refactor: extract static_asset! macro for static file handlers
Replace 16 near-identical async functions with a macro that generates
static-asset handlers with embedded content and one-week cache headers.
2026-02-13 13:03:14 +00:00
Ubuntu
7e0b910008
fix: validate CLI callback URLs to localhost-only
Reject non-localhost CLI callback URLs in the WebAuthn auth start
endpoint to prevent token exfiltration to external servers.
2026-02-13 13:01:12 +00:00
Jon Seager
24d9d75145
feat: add home screen icons for iOS and Android 2026-02-13 11:41:16 +00:00
Jon Seager
21696a02f0
chore: update gitignore 2026-02-13 11:27:02 +00:00
Jon Seager
2e41c28429
fix: apply EXIF orientation to uploaded photos
iPhone photos were displayed rotated because EXIF orientation metadata
was not being applied. Fix both the client-side canvas conversion
(use createImageBitmap which respects EXIF) and the server-side image
processing (read and apply EXIF orientation before resizing).
2026-02-12 18:07:52 +00:00
Jon Seager
98053a8679
docs: add note about Claude usage in README 2026-02-12 15:55:57 +00:00
Jon Seager
f1548d7e7a
build: fail-fast pre-commit hooks for faster iteration 2026-02-12 15:30:57 +00:00
Jon Seager
67f218495f
feat: add cancel buttons to all add forms
Match the edit form pattern by adding a Cancel button (history.back())
below each Save button in the sticky submit bar.
2026-02-11 10:24:28 +00:00
Jon Seager
720ebcbad3
feat: add sticky submit buttons to all edit forms on mobile
Add sticky-submit class to the shared edit_form_actions() macro and
pb-16 bottom padding to all seven edit form templates, matching the
add form pattern for a consistent mobile experience.
2026-02-11 10:20:30 +00:00
Jon Seager
1eb5647b76
feat: add sticky submit button to all mobile add forms
Apply the existing sticky-submit pattern (fixed bottom bar on mobile,
inline on desktop) to roaster, roast, bag, gear, cafe, and cup add
forms, matching the brew form behavior.
2026-02-11 10:15:40 +00:00
Jon Seager
1f21dc27af
fix: prevent iOS auto-zoom on input focus
Bump .input-field font-size to 1rem (16px) on mobile so iOS Safari
does not auto-zoom the viewport when focusing text inputs, number
inputs, or searchable selects.
2026-02-11 10:11:02 +00:00
Jon Seager
55addb200c
fix: prevent double-tap zoom on mobile stepper buttons
Add touch-action: manipulation to .btn-adjust so rapid taps on +/-
buttons no longer trigger the browser's double-tap-to-zoom gesture.
2026-02-11 10:07:58 +00:00
Jon Seager
049e9d68a8
fix: mobile fixed nav bar and detail page polish
- Make nav bar fixed on mobile with safe-area-inset-top support for
  notched devices (10% reduction) and 1rem minimum for non-notched
- Adjust timeline sticky month headings to sit flush below the fixed
  nav with matching top/bottom padding
- Update IntersectionObserver rootMargin to account for fixed nav height
  so stuck-state accent border triggers correctly
- Increase main content top padding on mobile for balanced spacing on
  detail pages
- Add remaining field to bag edit form with +/- stepper buttons
- Make admin page passkey/token forms responsive with icon-only mobile
  delete/revoke buttons
- Make detail page action buttons stack vertically on mobile with equal
  width
2026-02-11 09:53:43 +00:00
Jon Seager
705144bcf7
fix: make detail page action buttons responsive on mobile 2026-02-11 09:05:58 +00:00
Jon Seager
76445f49ae
fix: improve admin page forms for mobile
Stack passkey and token input forms vertically on mobile with full-width
fields and buttons. Collapse Delete/Revoke buttons to icon-only squares
on mobile, expanding to show text labels on larger screens.
2026-02-11 08:59:52 +00:00
Jon Seager
3a32d9725a
feat: add remaining amount field to bag edit form 2026-02-11 08:53:56 +00:00
Jon Seager
4190fc2620
feat: log payload fields in trace spans by redacting image data
Add ImageData newtype that wraps Option<String> with a custom Debug impl
showing Some(<image>)/None instead of raw base64. Replace image fields on
all 14 submission structs and remove payload from tracing skip lists so
textual/numeric fields appear in spans.
2026-02-11 08:37:03 +00:00
Jon Seager
56a1637d63
style: use accented color for links on timeline 2026-02-10 20:35:42 +00:00
Jon Seager
a38e9aae5b
fix: use shortened dates in expanded timeline cards 2026-02-10 20:33:24 +00:00
Jon Seager
7ec422f7ce
style: short month names on expanded timeline cards 2026-02-10 20:32:13 +00:00
Jon Seager
2cd579a574
refactor: deduplicate update handlers and edit templates
Add HasChanges trait with impl_has_changes! macro, validate_update()
and update_response() helpers to reduce boilerplate across all 7 entity
update handlers. Extract edit form actions (error, spinner, buttons)
into a shared Askama macro. Also adds missing no-changes validation
to the bag update handler.
2026-02-10 20:04:24 +00:00
Jon Seager
8ced58039b
fix: add x icon to cancel button and saving spinner to edit forms
Replace both buttons with a centered "Saving..." spinner when the
form is submitting. Add x_mark icon to the cancel button for clarity.
2026-02-10 19:43:10 +00:00
Jon Seager
0434b127e0
test: add E2E chromedriver tests for edit forms
Cover text fields, numeric fields, +/- adjuster buttons, searchable
selects, image upload/replace/remove, deferred image save, and the
cancel button across roaster, gear, cafe, brew, and cup entities.

Add wait_for_url_not_contains helper to correctly detect post-submit
redirects when the edit page URL shares a prefix with the detail page.
2026-02-10 19:43:06 +00:00
Jon Seager
4ee8cf7964
fix: polish edit forms and detail pages
- Skip payload in tracing::instrument to avoid logging base64 image data
- Add blob: to CSP img-src for image preview support
- Add deferred_upload_with_preview macro for edit form image previews
  with Replace/Remove buttons and proper DOM cleanup on replacement
- Fix datastar-fetch finished handler (evt.detail.response is undefined
  for redirect scripts)
- Display brew time in M:SS format on edit form
- Add full-width Save Changes button with check icon and Cancel button
  to all edit forms
- Fix country flag emoji spacing on cafe and cup detail pages
- Add "View on Map" Google Maps link to cafe and cup detail pages
2026-02-10 19:43:03 +00:00
Jon Seager
9650735057
fix: wire edit forms for Datastar submission and recompute bag remaining
Add {contentType: 'form'} to all edit template @put() calls so form
inputs are submitted by name rather than as Datastar signals. Replace
the brew edit quick notes text input with toggle pill buttons. Recompute
bag remaining when amount is updated to account for brew deductions.
Add CLI tests for brew and cup update commands.
2026-02-10 19:43:00 +00:00
Jon Seager
cb28a6f8bb
fix: wire edit forms for Datastar form submission and add CLI tests
Add {contentType: 'form'} to all edit template @put() calls so form
inputs are submitted by name rather than as Datastar signals. Replace
the quick notes text input on the brew edit page with toggle pill
buttons matching the add form. Add CLI tests for brew and cup update
commands.
2026-02-10 19:42:58 +00:00
Jon Seager
5f99ca0953
feat: add CLI update commands for brews and cups
Add UpdateBrewCommand and UpdateCupCommand to the CLI with all
updatable fields. Add corresponding update() methods to BrewsClient
and CupsClient.
2026-02-10 19:42:55 +00:00
Jon Seager
931859938a
test: add integration and E2E tests for edit functionality
Add form-based PUT update tests via define_form_update_tests macro for all
7 entities. Add hand-written datastar update tests for roasters, roasts,
cafes, brews, and cups. Add brew/cup update API tests (CRUD + auth).
Add put_form, put_form_datastar, create_default_brew, create_default_cup
test helpers.
2026-02-10 19:42:52 +00:00
Jon Seager
1a1b28559c
feat: add edit page route handlers, template structs, and edit templates
Add edit page handlers for all 7 entities (roaster, roast, bag, brew,
cafe, cup, gear) with authentication, data pre-loading, and image URL
resolution. Register edit routes in app router. Add corresponding
template structs and HTML templates with pre-populated forms.
2026-02-10 19:42:49 +00:00
Jon Seager
94088f1f4b
feat: add edit button to all detail pages
Add edit_button and edit_delete_buttons macros to detail_cards.html.
All 7 entity detail pages now show an Edit button next to Delete when
authenticated. Each detail template struct receives a pre-computed
edit_url from the route handler.
2026-02-10 19:42:47 +00:00
Jon Seager
1c029f52f4
feat: add update endpoints for brews and cups
Add UpdateBrewSubmission and UpdateCupSubmission types with image
support. Register PUT handlers on /brews/{id} and /cups/{id} with
three-way response pattern (Datastar/form/JSON).
2026-02-10 19:42:45 +00:00
Jon Seager
bc449e520e
feat: upgrade update handlers to FlexiblePayload with three-way response
All five existing update handlers (roaster, roast, cafe, gear, bag) now
accept FlexiblePayload with UpdateSubmission types that separate image
data from domain structs. Each returns Datastar redirect scripts, form
redirects, or JSON depending on request type. Image save support added
to all update paths.
2026-02-10 19:42:43 +00:00
Jon Seager
77cb61f91b
feat: add UpdateBrew, UpdateCup structs and expand UpdateBag
Add domain update structs for brew and cup entities, add update()
methods to their repository traits and SQL implementations, and
expand UpdateBag with roast_id, roast_date, and amount fields.
2026-02-10 19:42:39 +00:00
Jon Seager
fbf5a288c1
feat: support HEIF/HEIC image uploads via client-side Canvas conversion
Convert all image files to JPEG on the client before uploading, allowing
iPhone HEIF/HEIC photos to work without server-side libheif dependency.
2026-02-10 17:56:48 +00:00
Jon Seager
bb4aa103fb
fix: add success logging for deferred image saves
Log at info level when a deferred image is successfully saved, matching
the project convention that every create/update operation logs with
entity context.
2026-02-10 17:50:46 +00:00
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
3675a2cdc6
fix: add decompression bomb protection and MIME type validation
Set image decoder limits (10000x10000 max dimensions, 256MB max alloc)
to prevent crafted images from causing OOM via decompression bombs.
Validate data URL MIME types against an allowlist (jpeg/png/webp)
before decoding, rejecting non-image content types early.
2026-02-10 17:50:38 +00:00
Jon Seager
082b582cb3
fix: move image processing off async runtime with spawn_blocking
CPU-intensive image operations (decode, Lanczos3 resize, JPEG encode)
were running directly on the async worker thread, blocking all other
requests for 100-500ms per upload. Wrap in spawn_blocking in both
upload_image() and save_deferred_image().
2026-02-10 17:50:34 +00:00
Jon Seager
cf56ac28f7
test: add integration and e2e tests for image API
Cover all image entry points: upload, get, thumbnail, delete, auth
guards, validation, datastar responses, deferred image saves via
roaster create, checkin (cafe/cup), and scan flows including the
matched-roast guard that prevents overwriting existing images.
2026-02-10 17:50:30 +00:00
Jon Seager
7bacd30854
feat: improve image loading states on detail pages
Replace "Uploading..." text with animated spinner when uploading via
thumbnail, and show placeholder icon while image loads from server.
2026-02-10 17:50:27 +00:00
Jon Seager
b28234b52f
feat: include entity images in backup, restore, and reset
Images were not included in the backup/restore system, so a backup
would lose all uploaded images and a reset would orphan them.

Add BackupImage with base64-encoded binary data to BackupData,
export/restore/reset the entity_images table, and verify it in
the empty-database check. Backward-compatible with existing v2
backups via #[serde(default)].
2026-02-10 17:50:23 +00:00
Jon Seager
c3781de30c
feat: add image upload to create and check-in forms
Add deferred image upload support to entity creation flows:

- Roaster, roast, gear, cafe forms save images on create via
  save_deferred_image helper
- Brew form accepts optional image upload
- Check-in form accepts optional cup photo
- Scan flow preserves captured image for new roasts and skips
  overwriting existing roast images
- Homepage updated with image-upload component registration
- Delete handlers for brews and cups clean up associated images
2026-02-10 17:50:20 +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
3d61f71f1d
test(e2e): add homepage scan tests and fix stale element in checkin test
Add 3 homepage scan e2e tests covering all roaster/roast match
permutations (new+new, existing+new, existing+existing). Fix
StaleElementReference in checkin test by using JS clicks for
Datastar-managed DOM elements.
2026-02-10 11:36:16 +00:00
Jon Seager
264ef9c1fb
test: add e2e checkin test with new cafe and scanned roast
Cover the check-in flow where neither the cafe nor the roast exist
beforehand. The test searches for a cafe via location search (mocked
Foursquare), scans a coffee bag via text prompt (mocked OpenRouter),
and submits the check-in. Adds spawn_app_with_all_mocks helper.
2026-02-10 11:26:17 +00:00
Jon Seager
7c1fbb99b8
test: add e2e tests for data page, detail pages, bag close, and navigation
Cover tab switching, search, pagination, and sorting on the data list
page. Verify detail page rendering for roasters, roasts, bags, gear,
and cafes. Test the close-bag flow from the detail page. Check that
home, stats, and timeline pages load correctly with data.
2026-02-10 11:09:30 +00:00
Jon Seager
034630ade0
ci: add e2e browser test job to GitHub Actions 2026-02-10 10:45:12 +00:00
Jon Seager
104ebb410a
test: add e2e browser tests for core user flows
Roaster creation (basic + all fields), full brew chain through browser,
entity deletion with confirm dialog, AI extraction via text prompt with
mocked OpenRouter, and check-in wizard with saved cafe + existing roast.
2026-02-10 10:45:01 +00:00
Jon Seager
73976cbe51
feat(test): add e2e browser test helpers
BrowserSession wraps headless Chrome via thirtyfour. Auth helper injects
session cookies to bypass WebAuthn. Wait helpers handle Datastar's async
DOM updates (visibility, text, URL). Form helpers find visible elements
to avoid hidden duplicates on tabbed pages. Chromedriver is auto-spawned
on first use via a dedicated parked thread with PR_SET_PDEATHSIG so the
kernel kills it when the test binary exits.
2026-02-10 10:44:47 +00:00
Jon Seager
c2b252824d
feat(test): add e2e test infrastructure with thirtyfour
Add thirtyfour WebDriver client as dev-dependency, feature-gated behind
--features e2e so normal cargo test is unaffected. Add chromedriver and
chromium to the nix devShell.
2026-02-10 10:44:36 +00:00