- Add "Search by city" toggle as alternative to GPS location
- Replace saved cafes button list with select dropdown
- Show editable review form when selecting a Foursquare result
- Guard all datastar-fetch handlers with in-progress signals
- Fix step indicator spacing (mt-4 on steps 2 and 3)
- Document data-bind (not data-model) for two-way signal binding
- Document signal naming: kebab-case in HTML, camelCase in JS/JSON
- Document render_signals_json for application/json signal patches
- Document datastar-fetch event bubbling and per-form guard pattern
- Document extraction template pattern with inline FileReader JS
- Remove outdated extract.js documentation and element ID conventions
- Update static assets section (no separate JS files)
- Add POST /api/v1/check-in endpoint with CheckInSubmission
- nearby_cafes returns HTML fragment for Datastar, JSON for API
- Add NearbyCafeView and NearbyCafesFragment for server-rendered results
- Rewrite checkin.html: replace checkin.js with Datastar signals,
@post for submission, @get for nearby search, inline geolocation JS
- Cafe filtering uses data-show with signal-based search
Extraction endpoints now accept FlexiblePayload (form or JSON) and
return application/json signal patches for Datastar requests. Templates
use data-bind for two-way signal binding and data-on:datastar-fetch
with per-form guards to prevent event bubbling between forms.
- extract_roaster, extract_roast_info, extract_bag_scan return signals
- submit_scan extended with optional image/prompt for combined extract+save
- match_roaster_id fuzzy-matches extracted roaster name to existing IDs
- Templates use data-bind:_signal-name (not data-model) for form binding
- Each datastar-fetch handler guards with its own in-progress signal
- 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.