Commit graph

389 commits

Author SHA1 Message Date
Jon Seager
05c33ed533
fix(timeline): register border color in Tailwind theme
The timeline line used `bg-border` but `--color-border` was missing from
the @theme block, so Tailwind never generated the utility class and the
line was invisible.
2026-02-05 21:44:03 +00:00
Jon Seager
f1cdf75eaf
refactor(templates): replace manual JS with Datastar patterns
- Convert data.html search from manual fetch+debounce to Datastar @get
- Replace filterList() on checkin page with <searchable-select> component
- Convert account.html form show/hide from classList to data-show signals
- Rename _scanWaiting/_scanError to _extracting/_extractError for consistency
- Delete unused render_signals_fragment() and escape_html_attr() from support.rs
- Document Datastar vs JS guidelines in CLAUDE.md
2026-02-05 21:42:14 +00:00
Jon Seager
ba71bb69c5
style: update design of recent brew card 2026-02-05 21:20:38 +00:00
Jon Seager
8777ceb25b
fix(brews): carry over quick notes when using "Brew Again"
- Add quick_notes_raw field to BrewView with comma-separated form values
- Include quick_notes hidden input in all three brew-again forms
  (homepage, brew list desktop, brew list mobile)
2026-02-05 21:18:11 +00:00
Jon Seager
6b1d6a3187
fix(ui): tone down token-created success banner in dark mode
Add dark: variants for the green success banner on the account page
so it doesn't appear overly bright against the dark background.
Also tidy .gitignore to catch all .db and .db-journal files.
2026-02-05 21:06:42 +00:00
Jon Seager
b5e91d9d0d
refactor(db): consolidate 21 migrations into 4 clean files
No production instances exist, so safe to rewrite from scratch.
Drops columns that were added then removed (notes, password_hash,
cup rating), standardises timestamp format and primary key style,
and creates all tables in their final form without incremental
ALTER TABLE churn.
2026-02-05 21:06:37 +00:00
Jon Seager
709adcdd3e
fix(ui): tokenize neutral text colors for dark mode contrast
Replace ~268 hardcoded text-stone-* classes with theme-aware token
utilities (text-text, text-text-secondary, text-text-muted) across all
templates and JS components. Adjust dark mode token values to meet
WCAG AA contrast ratios on dark surfaces.
2026-02-05 20:57:59 +00:00
Jon Seager
1377d43935
fix: resolve clippy warnings for dead field and struct prefix
- Remove unused passkey_name from RegisterStartRequest (only used in RegisterFinishRequest)
- Rename AiUsageView fields from total_calls/total_tokens/total_cost to calls/tokens/cost
2026-02-05 20:49:17 +00:00
Jon Seager
fbc2d66a84
refactor(home): move quick notes pills to card footer with icon-only brew again
- Move quick notes pills into border-t footer row, left-aligned
- Show "No Notes" muted pill when brew has no quick notes
- Replace text "Brew Again" button with compact refresh icon button
- Footer now always visible (pills + optional brew-again action)
2026-02-05 20:46:07 +00:00
Jon Seager
010b700595
feat(brews): add quick notes
Predefined toggleable tags for brews: Good, Too Fast, Too Slow,
Too Hot, Under Extracted, Over Extracted.

- Add quick_notes TEXT column storing JSON array
- Add QuickNote enum with label/form-value/positive helpers
- Update repository to encode/decode JSON, backup to export notes
- Add toggle pill UI on brew form with Datastar signals
- Show pills on home page cards (muted for Good, amber for others)
- Show comma-joined text in data table Notes column
- Add --quick-notes flag to CLI, update HTTP client
- Update bootstrap script with sample quick notes
2026-02-05 20:42:03 +00:00
Jon Seager
3bc6fae656
refactor(ui): improve data table detail rows and mobile cards
- Split created_at into created_date + created_time across all view models
- Add inline card-detail pattern for mobile action buttons
- Add desktop detail-row with ellipsis toggle for table actions
- Add pill-warning and pill-success CSS variants with dark mode
- Center mobile card-detail buttons, fix card-date vertical spacing
- Rename action labels: "View on Map" → "View Map", "Visit website/homepage" → "Homepage"
2026-02-05 20:40:38 +00:00
Jon Seager
35ea246ba2
test: add coverage for homepage, check-in, scan, and AI extraction
- 12 page smoke tests: homepage (empty/with data/stats), login,
  auth-gated redirects (check-in, add, account), authenticated page
  loads, logout, and scan redirect
- 5 check-in API tests: existing cafe, new cafe creation, auth,
  and validation
- 7 scan API tests: roaster+roast creation, slug-based reuse, bag
  creation with timeline event, auth, and field validation
- 9 AI extraction tests: all 3 extract endpoints with wiremock-mocked
  OpenRouter, both JSON and Datastar signal responses, auth and
  empty input validation
2026-02-05 19:19:05 +00:00
Jon Seager
a9d97d40bd
refactor(ai): make OpenRouter URL configurable for testability
Add url parameter to ai::extract_roaster(), extract_roast(), and
extract_bag_scan() instead of using a hardcoded constant. Wire through
AppState.openrouter_url (defaulting to the production URL), matching
the existing pattern used for foursquare_url.

Add test infrastructure: session creation helper, page_url() on
TestApp, and spawn_app_with_openrouter_mock() for wiremock-based
AI extraction testing.
2026-02-05 19:18:51 +00:00
Jon Seager
b4a885e990
refactor(routes): simplify visibility to pub(crate)
Replace verbose pub(in crate::application::routes) with pub(crate)
across all api/ modules and support.rs for readability.
2026-02-05 19:08:44 +00:00
Jon Seager
f25101eef4
refactor(routes): wire up api/app module structure
Create api/mod.rs with API router and webauthn router construction.
Create app/mod.rs with page router and static asset handlers. Rewrite
routes/mod.rs to combine api::router() + app::router(). Widen
support.rs load_*_options visibility to pub(in crate::application::routes).
2026-02-05 19:05:03 +00:00
Jon Seager
58b551afac
refactor(routes): split account, checkin, and webauthn into api/app
Split each mixed file along the api/page boundary:
- account.rs: page handler + view types to app/, API handlers to api/
- checkin.rs: checkin_page to app/, submit_checkin to api/
- webauthn.rs: register_page + cli_callback_page to app/
2026-02-05 19:04:52 +00:00
Jon Seager
bb8fff2630
refactor(routes): move page handlers to routes/app/ subdirectory
Move home, auth, data, add, and timeline page handlers to routes/app/.
Update import paths: super::is_authenticated to
crate::application::routes::is_authenticated, super::entity:: to
crate::application::routes::api::entity:: in data.rs and add.rs.
2026-02-05 19:04:36 +00:00
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