Commit graph

472 commits

Author SHA1 Message Date
Jon Seager
9cc0b30cca
refactor(routes): move API handlers to routes/api/ subdirectory
Move entity CRUD modules (roasters, roasts, bags, brews, gear, cafes,
cups), pure API modules (tokens, backup, scan), macros, and webauthn
to routes/api/. Remove page handlers from api/webauthn.rs. Update
import paths (super::support:: to crate::, scan's TastingNotesInput
reference to super::roasts::). Widen pub(super) to
pub(in crate::application::routes) on page loaders and data structs
for cross-subdirectory access.
2026-02-05 19:04:21 +00:00
Jon Seager
0e620dcb2a
docs: update README and CLAUDE.md for improved logging
- Add RUST_LOG_FORMAT environment variable to README server config table
- Add logging & tracing section to CLAUDE.md covering error logging rules,
  CRUD operation logging, and security event logging practices
2026-02-05 18:52:26 +00:00
Jon Seager
fe4cb4ffbb
feat(logging): add CRUD operation and timeline error logging
- Add info! logging for entity create/update/delete across all route handlers
- Add entity deleted logging in define_delete_handler! macro
- Log timeline insert errors instead of silently discarding them
2026-02-05 18:14:00 +00:00
Jon Seager
4ab00dd630
refactor(logging): log errors and security events in auth routes
- Log all map_err(|_| StatusCode) patterns in webauthn, tokens, and account handlers
- Log fire-and-forget errors: registration token mark_used, passkey credential
  counter update, passkey update_last_used
- Add security event logging: token create/revoke, passkey delete, login/logout,
  CLI token creation via passkey auth
- Log session delete failures and auth check errors
2026-02-05 18:13:47 +00:00
Jon Seager
5ee89549a3
refactor(logging): log errors in auth and payload parsing
- Log bearer token lookup and user lookup failures in AuthenticatedUser extractor
- Log session lookup and user lookup failures in session-based authentication
- Log fire-and-forget token update_last_used errors
- Log JSON and form payload parse failures in FlexiblePayload
2026-02-05 18:13:34 +00:00
Jon Seager
06384265d3
refactor(logging): switch to env-based log format with HTTP tracing
- Replace tracing-bunyan-formatter with tracing-subscriber's built-in fmt layer
- Default to compact human-readable format, JSON opt-in via RUST_LOG_FORMAT=json
- Add tower-http TraceLayer for automatic HTTP request/response logging
- Remove tracing-bunyan-formatter and tracing-log dependencies
2026-02-05 18:13:19 +00:00
Jon Seager
fb7bc423b3
docs: update CLAUDE.md for restructured templates and static assets
Update all path references to reflect new directory structure.
Clarify committing convention to "never try to commit unless
explicitly prompted".
2026-02-05 17:48:37 +00:00
Jon Seager
56109f3afe
refactor: reorganize templates into pages/, partials/lists/, and forms/
Move 9 page templates to templates/pages/, nav to partials/,
7 list partials + table.html to partials/lists/. Extract duplicated
scan result form (~85 lines) from home.html and add.html into
partials/forms/scan_result_form.html. Update all Askama template
paths, include/import directives.
2026-02-05 17:48:18 +00:00
Jon Seager
4e917cee75
refactor: move static assets out of templates/ into static/
Move CSS, JS, favicon files to static/ directory to separate
compiled-in assets from Askama templates. Update all include paths,
build.rs, flake.nix, and Tailwind @source directives.
2026-02-05 17:47:32 +00:00
Jon Seager
4a54834424
refactor(ui): extract reusable tab bar component
- Create shared tab_bar.html partial with desktop + mobile layouts
- Add CSS component classes (.tab, .tab-active, .tab-mobile variants)
- Replace divergent implementations in data.html and add.html
- Rename DataTab to Tab for shared use across templates
- Improve readability: darker inactive text, more spacing, hover states
2026-02-05 17:23:50 +00:00
Jon Seager
70cbb76c3e
docs: update CLAUDE.md CSS section for build.rs integration
Replace the manual dev workflow instructions with documentation of
the automatic build.rs Tailwind pipeline added in 33c27ed.
2026-02-05 17:20:37 +00:00
Jon Seager
d2a3ee190b
docs: update CLAUDE.md with theme, component, and partial docs
Document CSS architecture (design tokens, dark mode, pills),
web components (brew-photo-capture, searchable-select), template
partial extraction patterns, and updated static asset serving.
2026-02-05 17:06:18 +00:00
Jon Seager
fb67f0659c
feat(ui): redesign with theme tokens, dark mode, and reusable components
Overhaul the web UI with CSS custom property-based theming and
dark mode support. Extract reusable template partials (location
search, scan input) and web components (photo-capture,
searchable-select). Add version and commit info to page footer.

- Replace hardcoded amber palette with semantic theme tokens
- Add dark mode with localStorage persistence and system preference detection
- Extract <brew-photo-capture> and <searchable-select> web components
- Extract location_search and scan_input Askama macros
- Add sun/moon, timeline, database, map icons
- Display version and git commit in footer
- Improve timeline coordinate rounding and map link formatting
- Add roast_name, roaster_name, remaining to BagOptionView
2026-02-05 17:03:09 +00:00
Jon Seager
6d12b71482
refactor(cups): remove rating field
Drop the rating column from cups. This removes the field from the
domain model, repository, API routes (including the PUT/update
endpoint), CLI, and all related tests.
2026-02-05 17:02:42 +00:00
Jon Seager
33c27ed0d0
build: add Tailwind CSS v4 build pipeline with theme tokens
Replace the checked-in styles.css with a build-time Tailwind CSS
pipeline. input.css defines CSS custom properties for light/dark
themes, mapped to Tailwind utilities via @theme. build.rs runs
the Tailwind CLI to generate styles.css at compile time.
2026-02-05 17:02:13 +00:00
Jon Seager
6398adc853
docs: strengthen JavaScript style conventions in CLAUDE.md
Expand the one-line JS style guideline into explicit rules with
examples, covering arrow functions, const/let, template literals,
and the inline onclick handler pattern. Prevents future code from
being written with function declarations or var.
2026-02-05 12:48:19 +00:00
Jon Seager
4fc81dd0c5
style(templates): modernize JS to arrow functions and const/let
Convert all remaining function declarations, var usage, and string
concatenation across base, add, checkin, and data templates.
2026-02-05 12:45:52 +00:00
Jon Seager
5acbddd65b
refactor(account): simplify passkey/token JS and modernize syntax
Replace DOMContentLoaded event-listener block with global arrow
functions and inline onclick handlers. Convert string concatenation
to template literals throughout.
2026-02-05 12:43:03 +00:00
Jon Seager
de3e1d4bcb
fix(nix): add openssl build inputs for webauthn-rs
webauthn-rs-core unconditionally depends on openssl for X.509 and
signature verification. Add pkg-config and openssl to the nix build
so the package builds in the sandbox.
2026-02-05 12:34:57 +00:00
Jon Seager
149921dc31
refactor(account): simplify backup/restore with native download link
Replace the blob URL download JS with a Content-Disposition header on
the export endpoint and a plain <a> tag. Consolidate restore JS from
event listeners into a single global function.
2026-02-05 12:27:17 +00:00
Jon Seager
9eb9a9a56c
feat(account): display OpenRouter usage on account page
Show cumulative cost, API call count, and total tokens in card
layout when the user has AI usage data.
2026-02-05 12:09:43 +00:00
Jon Seager
0a93df845f
feat(ai): record usage after each OpenRouter extraction
Wire AiUsageRepository into AppState and add a fire-and-forget
record_ai_usage helper. All extraction route handlers now capture
the usage tuple and record it in the background.
2026-02-05 12:09:36 +00:00
Jon Seager
6271b0e5e5
feat(ai): capture usage data from OpenRouter API responses
Add Usage struct to parse prompt_tokens, completion_tokens,
total_tokens, and cost from every OpenRouter response. Extraction
functions now return (result, Option<Usage>) tuples. New ai_usage
table stores per-call records with a repository trait and SQL
implementation.
2026-02-05 12:08:48 +00:00
Jon Seager
69b039b02d
feat(account): add backup download and restore UI
Add a Data section to the account page with buttons to download
a JSON backup and restore from a previously exported backup file.
2026-02-05 11:51:36 +00:00
Jon Seager
6a0d94739b
feat(auth): allow naming the initial passkey during registration
- Add "Passkey Name" field to the registration form
- Pass passkey_name through start/finish WebAuthn ceremony
- Use user-provided name instead of hardcoded "default"
2026-02-05 11:24:52 +00:00
Jon Seager
16a4704fcf
feat(account): add account page with passkey and token management
- Add /account page with passkey list, token list, and sign-out
- Replace nav login/logout buttons with user icon linking to /account or /login
- Add passkey management: add new passkeys (WebAuthn ceremony), delete with confirmation
- Add token management: create, copy one-time value, revoke with confirmation
- Add user/key/clipboard icon macros
- Add PasskeyCredentialRepository::get() for ownership verification
- Add WebAuthn passkey/start and passkey/finish endpoints for adding passkeys
2026-02-05 11:24:43 +00:00
Jon Seager
25705ea0c0
fix(ui): update empty state messages based on auth status
Show a simple "No X added yet" for unauthenticated visitors.
Authenticated users see a prompt to click the Add button.
2026-02-05 11:14:39 +00:00
Jon Seager
e6d9f861e6
style(tables): normalize text styling to match brews table
Replace bold amber (font-semibold text-amber-800) with medium stone
(font-medium text-stone-800) across roaster, roast, cafe, and cup
list templates to match the brews table convention.
2026-02-05 11:11:44 +00:00
Jon Seager
c6b98f81c9
docs: update documentation for passkey auth
- Replace BREWLOG_ADMIN_USERNAME/PASSWORD with BREWLOG_RP_ID/RP_ORIGIN
- Document first-user bootstrap via one-time registration URL
- Document CLI browser handoff flow for token creation
- Update bootstrap script for new token creation process
- Change default URL references from 127.0.0.1 to localhost
2026-02-05 11:00:25 +00:00
Jon Seager
4bc64dd12f
test(auth): update tests for passkey migration
- Replace password-based token creation with direct DB inserts in CLI helpers
- Use INSERT OR IGNORE for concurrent test thread safety on shared user
- Update server test helpers with passkey/registration_token repos and WebAuthn state
- Remove password-based auth tests, keep bearer token validation tests
- Set BREWLOG_RP_ID, RP_ORIGIN, OPENROUTER_API_KEY, FOURSQUARE_API_KEY in test env
- Use localhost instead of 127.0.0.1 for WebAuthn RP ID compatibility
2026-02-05 11:00:20 +00:00
Jon Seager
03e03d87d9
feat(auth): replace password auth with WebAuthn passkeys
Replace username/password authentication with FIDO2/WebAuthn passkey-based
auth using webauthn-rs. Sessions and bearer tokens are unchanged — only the
way they are created changes.

- Add webauthn-rs, uuid, open, url deps; remove argon2, rpassword
- Add passkey_credentials and registration_tokens tables (migrations 17-18)
- Add domain entities, typed IDs, and repository traits for passkeys/tokens
- Add SQL repository implementations for passkeys and registration tokens
- Add ChallengeStore for in-memory WebAuthn ceremony state
- Add WebAuthn route handlers (register/auth start+finish ceremonies)
- Add CLI browser handoff for token creation (opens browser, local callback)
- Replace login form with "Sign in with Passkey" button
- Add registration page for first-user bootstrap via one-time token
- Replace BREWLOG_ADMIN_USERNAME/PASSWORD with BREWLOG_RP_ID/RP_ORIGIN
- Change default BREWLOG_URL from 127.0.0.1 to localhost (WebAuthn requires it)
2026-02-05 11:00:07 +00:00
Jon Seager
8c521f0e05
feat(data): redesign mobile data page with card layout and tab selector
- Add collapsible mobile tab selector with chevron icons
- Integrate search bar into tab component (below tabs)
- Replace Datastar search handler with vanilla JS for reliability
- Add mobile card layout: card-title, card-date, card-actions classes
- Add three-dot action menu for mobile with details/summary pattern
- Hide duplicate search inside data-content via CSS
- Pass search_value to DataTemplate for input preservation
2026-02-04 22:22:18 +00:00
Jon Seager
dd08e84572
fix(data): fix search bar 400 error on data page
Split Query<DataQuery> (which used #[serde(flatten)]) into two
separate extractors, since serde_urlencoded doesn't support flatten
and coerces all flattened values to strings, breaking u32 parsing.
2026-02-04 20:57:26 +00:00
Jon Seager
2c045f9335
fix(templates): remove dead detail-page links from list tables
The detail page routes and templates were removed but list templates
still linked to them. Replace the <a> tags with plain text to avoid
navigating to non-existent pages.
2026-02-04 20:53:19 +00:00
Jon Seager
2eca0ae3c6
refactor(bags): replace dual-section bag list with single paginated table
Remove the open-bags card grid and closed-bags history table in favour
of a unified table showing all bags with status badges and actions.

- Simplify load_bag_page to single BagFilter::all() query
- Remove open_bags field from BagPageData and BagListTemplate
- Add Status column with Open/Closed badges and remaining weight
- Add Close and Delete action buttons per row
2026-02-04 20:53:12 +00:00
Jon Seager
4bdfc661f9
refactor: consolidate entity pages into unified /data and /add views
Replace per-entity pages (/roasters, /roasts, /bags, /brews, /gear,
/cafes, /cups) and detail pages with a single tabbed /data view and
a dedicated /add page for entity creation.

- Add /data route with tab-based navigation using Datastar
- Add /add route consolidating all create forms
- Remove per-entity page handlers and standalone templates
- Remove detail page routes, handlers, and templates
- Update ListNavigator to accept String paths for query-param URLs
- Update home page and timeline links to use new /data?type=X paths
- Update nav to reference /data instead of individual entity pages
2026-02-04 20:51:30 +00:00
Jon Seager
50a372015c
feat(backup): expose backup/restore via authenticated API endpoints
- Add GET /api/v1/backup and POST /api/v1/backup/restore endpoints
  behind AuthenticatedUser
- Add BackupService to AppState and BackupClient for HTTP access
- Update CLI backup/restore to use API instead of direct DB access
- Remove --database-url flag from backup and restore commands
- Increase body limit to 50MB for restore endpoint
- Add API and CLI tests for auth, export, restore, and round-trip
- Update README to document auth requirement and API endpoints
2026-02-04 19:38:49 +00:00
Jon Seager
e31f1c741e
docs(claude): add code simplicity rules to prevent complexity creep
Add "Keeping Code Flat and Simple" section with five rules:
- Extract large closures (>10 lines) into named functions
- DRY repeated blocks that differ only by a parameter
- Prefer match over chained if/else-if when branching on a value
- Extract shared predicates into named helpers
- Use generic helpers for repeated structural patterns
2026-02-04 19:25:45 +00:00
Jon Seager
47c89bd725
refactor: simplify overly nested and duplicated code across five modules
- Extract 35-line filter_map closure into parse_cafe() in foursquare.rs
- Unify triple-duplicated search branching in pagination.rs into
  fetch_records() and fetch_count() helpers
- DRY three identical gear-loading blocks in brews.rs via
  load_gear_options() helper
- Flatten nested if/else-if in timeline map_details() using match,
  extract shared is_blank() helper
- Deduplicate JSON decode pattern in backup.rs with decode_json_vec()
  and decode_json_opt() helpers
2026-02-04 19:25:35 +00:00
Jon Seager
939743a224
feat(home): add inline detail subtitles to timeline preview cards
Show contextual details inline with event titles on home page timeline
cards. Each event type picks relevant fields: brew shows roaster and
brewer, roast shows roaster and origin, cafe shows city and country,
cup shows roaster and cafe, others show first three detail values.
2026-02-04 19:14:30 +00:00
Jon Seager
cdf90d1ff3
feat(home): add relative dates to timeline and brew cards
- Add relative_date() helper to views module for humanized timestamps
- Show relative dates on home page timeline preview and brew cards
- Format: "Just now", "Xm ago", "Xh ago", "Yesterday", "Xd/Xw ago"
2026-02-04 19:03:05 +00:00
Jon Seager
ba7a38b16f
refactor(home): redesign stats section with icon pills and responsive layout
- Replace single bordered card with compact pill-style stat links
- Add Heroicons for each stat category (beaker, fire, building, bag, cup, location, wrench)
- Rename old bag icon to cup, add new shopping-bag icon for bags
- Use 2-column grid on mobile, centered flex wrap on desktop
- Add min-width on numbers to align labels consistently
2026-02-04 18:54:37 +00:00
Jon Seager
ef039da123
fix(home): prevent text wrapping in brew and bag card detail fields 2026-02-04 17:49:57 +00:00
Jon Seager
37cd595c93
fix(home): truncate long names in brew and bag cards
Add text truncation with ellipsis to roast and roaster names in the
recent brews and open bags cards to prevent layout inconsistency when
titles wrap.
2026-02-04 17:43:36 +00:00
Jon Seager
91a9900c24
feat(scan): optionally open a bag when scanning coffee
Add "Open a bag of this coffee" checkbox (default: checked) to the
scan form with a configurable amount field (default: 250g). When
enabled, creates a bag and timeline event alongside the roaster/roast.
2026-02-04 17:41:53 +00:00
Jon Seager
ec62a1fc7b
fix(scan): clear signals and reset form on repeated extractions
Clear all roaster/roast signals before each extraction request to
prevent stale values from persisting across consecutive scans. Also
reset the extract form on completion to clear the prompt input.
2026-02-04 17:41:46 +00:00
Jon Seager
249d9c2583
refactor(home): consolidate scan results form and improve save behavior
- Merge roaster and roast sections into single bordered box
- Move cancel and save buttons inside the form border
- Reset form and reload homepage after save instead of redirecting to /roasts
2026-02-04 17:29:26 +00:00
Jon Seager
327a820b52
fix(home): simplify scan bag input layout
- Use camera icon-only button instead of "Take Photo" text
- Align camera button and text input horizontally
- Remove Go button, form submits on Enter
2026-02-04 17:28:24 +00:00
Jon Seager
52084be7ed
refactor(nav): replace login and logout text with icons
- Add login and logout icon macros to shared icons partial
- Desktop nav uses icon-only with aria-label for both
- Mobile nav uses icon + text for both
2026-02-04 17:21:58 +00:00
Jon Seager
f3a4cc7075
feat(home): limit open bags to 3 most recently updated
- Add UpdatedAt variant to BagSortKey
- Sort home page bags by updated_at desc instead of roast_date
- Limit to 3 bags instead of showing all open bags
2026-02-04 17:19:26 +00:00