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.
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)
Add Gear entity to track brewing equipment (grinders and brewers) with complete domain layer implementation.
Database changes:
- migrations/0006_add_gear.sql: Create gear table with category CHECK constraint and indexes
- migrations/0007_update_timeline_for_gear.sql: Document 'gear' as valid timeline entity type
Domain layer:
- Add GearId typed ID wrapper
- Create domain/gear.rs with:
- GearCategory enum (Grinder/Brewer) with string conversion methods
- Gear entity with make, model, notes fields
- NewGear and UpdateGear DTOs
- GearFilter for category-based filtering
- GearSortKey with Make (default), Model, Category, CreatedAt options
- Add GearRepository trait to domain/repositories.rs with standard CRUD operations
- Register gear module in domain/mod.rs
This follows the same architectural pattern as the Bag entity.
Code Quality Improvements:
- Fix hex literal grouping in ID generator (0xB10C_1D -> 0x00B1_0C1D)
- Rename ListQuery::default() to default_query() to avoid confusion with Default trait
- Use div_ceil() instead of manual ceiling division
- Remove unnecessary borrows in auth token generation and hashing
- Simplify nested if statements in error handling
Documentation:
- Add comprehensive authentication section to README
- Document environment variables for server and CLI
- Add security best practices and considerations
- Document password hashing (Argon2id), token storage (SHA-256), and session management
- Include step-by-step authentication setup guide
- Add production deployment recommendations
All 70 tests pass (8 unit + 46 server + 16 CLI) ✅
Co-authored-by: jnsgruk <668505+jnsgruk@users.noreply.github.com>