- Add home page at / with scan, last brew, open bags, activity, stats
- Add check-in page at /check-in with cafe search + roast scan + rating
- Use Datastar signals for check-in UI state (steps, rating, selection)
- Bridge async JS (geolocation, fetch) to Datastar via custom events
- Replace nav camera icon with house icon (always visible)
- Redirect /scan to / for backward compatibility
- Delete scan.html, add home.html, checkin.html, checkin.js
Move list partials outside the section element on bags, gear, and brews
pages so they become separate flex children of <main>, matching the
pattern used by roasters, roasts, cafes, and cups. Add mt-6 to each
partial's outer div for consistent spacing.
Standardise brew and gear list partials to match the canonical structure:
empty-state conditional with dashed amber border, <section> wrapper for
the table, and data-star-scope attribute on the outer div.
Update CLAUDE.md to document page template and list partial structure
requirements, preventing future drift.
When cup notes were removed, the blank lines left between --cafe-id
and --rating broke shell line continuations, causing --rating to be
interpreted as a command.
- Add migration 0016 to drop notes column from roasters table
- Remove notes from domain structs, repositories, views, CLI, routes
- Remove notes from AI extraction prompts and ExtractedRoaster struct
- Remove notes from scan page form and submission handler
- Update templates, bootstrap script, backup module, and tests
- Add migration 0014 to drop the notes column from cafes table
- Remove notes from domain structs, repository, view model, CLI, routes
- Remove notes textarea/column from web templates
- Update bootstrap script and all test files
- Fix CLI examples to use subcommand style (e.g. brewlog roaster add)
- Document all environment variables including .env file support
- Add sections for AI extraction, Foursquare nearby search, database
feature flags, and backup/restore
- Add ai/ and foursquare.rs to infrastructure layer in architecture diagram
- Add Foursquare Integration section covering SearchLocation enum, API
details, config, and wiremock testing pattern
- Note wiremock external API mocking in Conventions
- Add SearchLocation enum to support coordinates or named location
- Accept optional `near` query param as alternative to lat/lng
- Add city text input with checkbox toggle in cafes template
- Foursquare `near` param enables searching any city worldwide
- Replace osm.rs with foursquare.rs using Foursquare Places Search API
- Add isocountry crate for ISO 3166-1 country code to name conversion
- Override verbose country names (e.g. "United Kingdom" instead of
"United Kingdom of Great Britain and Northern Ireland")
- Add BREWLOG_FOURSQUARE_API_KEY env var for API authentication
- Update route handler, tests, and template to use Foursquare
- Modernise cafes template JS to ES6+ (const/let, arrow fns, template
literals)
Move duplicated photo capture, text extraction, and fetch/UI-toggle
logic from roasters, roasts, and scan templates into a shared
extract.js file served at /extract.js. Each page now provides only
its form-filling callback. Uses ES6+ syntax (const, let, arrow
functions, template literals).
Hide input controls and display a spinner with "Waiting for
response..." while LLM extraction requests are in-flight. Controls
are restored on completion or failure. Applied consistently across
scan, roaster, and roast forms.
Add /scan page that lets authenticated users photograph or describe a
coffee bag, extracts both roaster and roast data via a single AI call,
and creates both entities on submit. Existing roasters are matched by
slug to avoid duplicates. Camera icon added to nav bar.
Users can upload a photo of a coffee bag or type a text prompt to
auto-fill roaster/roast form fields via OpenRouter's chat completions
API. The feature is opt-in: hidden when BREWLOG_OPENROUTER_API_KEY is
not set.
- Add src/infrastructure/ai.rs with OpenRouter client, prompt
templates, JSON extraction from model responses, and unit tests
- Add extract-roaster and extract-roast API endpoints behind auth
- Add extraction UI (photo button + text input) to both form templates
- Add openrouter_api_key and openrouter_model to CLI args and AppState
- Enable reqwest gzip feature for compressed API responses
- Default model set to openrouter/free (auto-selects available models)
- Prompts instruct model to use web search for missing details
Add dotenvy::dotenv() call before CLI argument parsing so that
environment variables (e.g. API keys) can be set in a .env file
instead of the shell environment. Add .env to .gitignore.
- Move entity view models into views/{entity}.rs submodules
- Keep Paginated and ListNavigator in views/mod.rs as shared infrastructure
- Re-export all types from mod.rs to preserve existing import paths
- Add load_roaster_options, load_roast_options, load_cafe_options
helpers to support.rs, replacing duplicated inline loading in
roasts.rs, bags.rs, and cups.rs
- Add define_list_fragment_renderer! macro for the 5 structurally
identical render_*_list_fragment functions
- Fix gear.rs to return navigator from load_gear_page like all other
loaders instead of discarding and reconstructing it
Extract the detail-mapping loop from TimelineEventView::from_domain
into a private map_details helper method, bringing the function under
clippy's 100-line limit.
- Pair roasts with cafes visited, with tasting notes and ratings
- Timestamps align with cafe visit dates across the 6-month spread
- Include cup timeline event timestamp distribution
- Test CRUD operations: create, list, get, update, delete
- Test auth requirement, optional fields, enriched data
- Test validation: no changes returns 400, nonexistent returns 404
- Update test helpers with cup_repo wiring
- Add CupView, CafeOptionView, RoastOptionView view models
- Add CupsTemplate (full page) and CupListTemplate (fragment)
- Create cups.html with form and cup_list.html with responsive table
- Add Cups link to desktop and mobile navigation
- Add cup timeline event link and label support
- Add cup_repo to AppState and server startup
- Register API routes: GET/POST /cups, GET/PUT/DELETE /cups/:id
- Register web route: GET /cups with Datastar fragment support
- Rating validation (1-5) on create and update
- Implement CupRepository trait for SqlCupRepository
- Transactional insert creates cup and timeline event atomically
- Support filtering by cafe_id/roast_id, search across roast/roaster/cafe names
- Use QueryBuilder with push_update_field! macro for updates
- Add "Find nearby" button that requests browser geolocation
- Show search input with debounced type-ahead after locating user
- Render clickable results with name, location, and distance
- Auto-fill form fields (name, city, country, lat, lng, website)
when a result is selected
- Show loading spinner in search input during API requests
- Add OSM infrastructure module with Nominatim forward search, viewbox
location bias, and haversine distance calculation
- Add reqwest::Client to AppState for server-side HTTP requests
- Add GET /api/v1/nearby-cafes endpoint (authenticated) accepting
lat, lng, and text query parameters
- Check website, contact:website, url, contact:url, and brand:website
tags to maximise website coverage from OSM data
Position is already shown as a clickable detail row in the card body,
making the title icon redundant. Also removes the unused map_link field
from TimelineEventView.
Add cafe entries distributed over the last 6 months with timestamp
updates for both cafes and timeline events. Add .timeout to sqlite3
heredoc to handle database lock contention.
Add 14 server API tests, 6 CLI tests, 4 Datastar fragment tests,
1 timeline event test, and backup round-trip verification. Wire
cafe_repo into test helpers.
Add CLI subcommands (add, list, get, update, delete) with negative
number support for coordinates. Add CafeView with map URL generation,
Askama templates for list/detail pages, and nav link between Brews
and Gear.
Implement SqlCafeRepository with CRUD operations and timeline event
creation. Add CafesClient for CLI HTTP access. Wire cafes into backup
export/restore and empty-database verification.
- Add empty_to_none() to replace four repeated empty-string-to-None blocks
- Extract insert_timeline_event() from insert() to isolate timeline logic
- Remove #[allow(clippy::too_many_lines)] from RoastRepository impl
- Add BrewDefaultsView to carry last brew's values to the template
- Extract form data loading into load_brew_form_data() helper
- Use defaults for signal initialization and dropdown pre-selection
- Retain submitted values after form submission instead of resetting
- Fix stale fragment rendering example (into_request → into_request_and_search)
- Correct domain conversion convention to to_domain() and fold into Repository Pattern
- Add listing.rs and missing ID types to architecture tree
- Document define_enriched_get_handler! macro
- Add Route Module Structure pattern (load/page/fragment trio, build_page_view)
- Note submission types vs direct domain structs in FlexiblePayload