Commit graph

210 commits

Author SHA1 Message Date
Jon Seager
3f83d74e20
feat(cafes): add CLI commands, web views, and templates
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.
2026-02-03 14:53:00 +00:00
Jon Seager
1781bff48d
feat(cafes): add route handlers and wire into application state
Add cafe route handlers (CRUD API + web pages with Datastar fragment
support). Register cafe_repo in AppState and mount API and web routes.
2026-02-03 14:52:51 +00:00
Jon Seager
677b77d70d
feat(cafes): add SQL repository, HTTP client, and backup support
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.
2026-02-03 14:52:44 +00:00
Jon Seager
c6ad6a02c7
feat(cafes): add migration and domain layer for cafe entity
Add cafes table with name, slug, city, country, latitude, longitude,
website, and notes fields. Define domain types (Cafe, NewCafe, UpdateCafe),
CafeId typed wrapper, CafeRepository trait, and CafeSortKey enum.
2026-02-03 14:52:37 +00:00
Jon Seager
f1e8984ffa
refactor(roasts): extract helpers to remove too_many_lines suppression
- 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
2026-02-03 14:09:53 +00:00
Jon Seager
09a629db9a
feat(brews): pre-populate Add Brew form with last recorded brew values
- 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
2026-02-03 14:01:41 +00:00
Jon Seager
fa0cccade0
docs(claude): update CLAUDE.md to match current codebase
- 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
2026-02-03 13:50:47 +00:00
Jon Seager
546e105b10
fix(templates): prefix Datastar signals with underscore to mark as local
Datastar sends all non-underscore signals with every backend request.
UI-only signals (showForm, navOpen, isSubmitting, form ref, brew
parameters) were being serialized into pagination/search/sort URLs,
creating bloated requests. Prefix them with _ so Datastar's default
filterSignals excludes them from requests.
2026-02-03 13:37:50 +00:00
Jon Seager
16dd72b624
fix(timeline): restore sticky month headers and jump-to-top button
Remove wrapper div around month headings so the h2 is a direct child
of the timeline container. position: sticky was broken because the
heading's containing block (the wrapper) was only as tall as the
heading itself, giving it no room to stick.

Also update MutationObserver to detect headings added as direct
children via node.matches() in addition to node.querySelector().
2026-02-03 13:29:46 +00:00
Jon Seager
145ddb4765
fix(timeline): centre line behind cards on mobile for full-width layout
- Move timeline line to centre on mobile instead of left gutter
- Remove left padding from cards to maximise horizontal space
- Reposition dots to top-centre of each card border on mobile
- Make card background fully opaque so line doesn't show through
- Desktop alternating layout unchanged
2026-02-03 13:21:55 +00:00
Jon Seager
3475c91273
fix(brews): prevent New Brew form from overflowing on mobile
- Add width: 100% and min-width: 0 to .input-field so selects/inputs
  fill their container instead of expanding to fit content
- Add overflow-hidden to the brews form as a safety net
2026-02-03 13:14:12 +00:00
Jon Seager
35e8460219
fix(brews): lay out action icons horizontally and merge temp into recipe
Wrap the brew-again form and delete button in an inline-flex container
to match the horizontal layout used in other tables. Fold water
temperature into the Recipe column as desktop subtext alongside the
ratio, reducing the table from 7 to 6 columns and eliminating the
horizontal scrollbar. Document the Actions column pattern in CLAUDE.md.
2026-02-03 13:08:07 +00:00
Jon Seager
2d27228059
refactor(tables): standardise Added column as first column across all tables
Move the Added/Date column to first position in brew, gear, and bag
list templates and apply consistent text-xs font-medium text-stone-600
styling. Document the pattern in CLAUDE.md.
2026-02-03 13:03:43 +00:00
Jon Seager
57a6736b9a
docs: add table, search, and pagination patterns to CLAUDE.md 2026-02-03 13:00:01 +00:00
Jon Seager
087ff00177
fix(mobile): better layout for brews table 2026-02-03 12:58:37 +00:00
Jon Seager
d3a473466a
docs: add commit signing and authorship conventions to CLAUDE.md 2026-02-03 12:53:13 +00:00
Jon Seager
8fe88c8ff6
fix(mobile): hide infinite scroll sentinel on desktop
The sentinel div (h-4) added extra space below the pagination bar
on pages with a next page, making the pagination bar appear taller
than on the last page. Since infinite scroll only runs on mobile,
hide the sentinel on desktop with md:hidden.
2026-02-03 12:52:23 +00:00
Jon Seager
8213543ed3
feat(roasters): consolidate table columns and restyle actions
- Combine Country/City into Location column with city as desktop subtext
- Add City as separate mobile-only field for card layout
- Move homepage icon into Actions column alongside delete button
- Remove bordered style from homepage icon to match other action icons
2026-02-03 12:52:14 +00:00
Jon Seager
39598c1709
fix(search): keep search bar visible when search returns no results
- Change empty state condition to also check navigator.has_search()
- Show "No X match your search" message inside the table container
- Applied to roast, roaster, and gear list templates
2026-02-03 12:52:06 +00:00
Jon Seager
1fa88d054c
feat(roasts): consolidate table columns and add tasting notes search
- Combine Roast/Roaster into single column with roaster as subtext on desktop
- Combine Origin/Producer into single column with producer as subtext on desktop
- Add Roaster and Producer as separate mobile-only fields for card layout
- Replace tasting notes pill badges with comma-separated list
- Rename "Notes" column to "Tasting Notes" with right-aligned mobile text
- Include tasting_notes in repository search filter columns
2026-02-03 12:51:59 +00:00
Jon Seager
39bad42f9c
feat(mobile): add infinite scroll and hide pagination on mobile
Add IntersectionObserver-based infinite scroll for mobile viewports
that fetches next pages as the user scrolls. Uses MutationObserver
to re-attach after DOM replacements. Hide pagination controls on
screens narrower than 768px.
2026-02-03 12:51:52 +00:00
Jon Seager
8e92385c56
feat(search): add search input and reposition pagination in templates
Add search_header macro with Datastar-driven live search and debounced
input. Move pagination controls from above to below tables. Add
pagination-controls class for mobile hiding. Add infinite scroll
sentinel divs and data attributes to all list partials.
2026-02-03 12:51:42 +00:00
Jon Seager
2edf102b41
feat(search): add search to ListQuery, ListNavigator, and route handlers
Add q parameter to ListQuery with into_request_and_search(). Extend
ListNavigator with search state, search_value(), has_search(), path(),
and search_query_base() for template URL generation. Thread search
through all route handlers and update backup tests.
2026-02-03 12:51:34 +00:00
Jon Seager
1e151123a0
feat(search): implement search filtering in repository SQL queries
Wire SearchFilter into each repository's list method with entity-specific
searchable columns: roasters (name, country, city), roasts (name, roaster,
origin, producer), bags (roaster, roast), brews (roast, roaster),
gear (make, model). Timeline passes None.
2026-02-03 12:51:26 +00:00
Jon Seager
f616958e3c
feat(search): add search parameter to repository traits
Add `search: Option<&str>` to list methods on RoasterRepository,
RoastRepository, BagRepository, GearRepository, and BrewRepository.
Default trait methods pass None for backwards compatibility.
2026-02-03 12:51:19 +00:00
Jon Seager
18d39d13ef
feat(search): add SearchFilter and DatabaseDriver to pagination infrastructure
Add SearchFilter struct for LIKE-based search with dynamic column
matching. Add DatabaseDriver type alias to support QueryBuilder
generics across SQLite and Postgres feature flags.
2026-02-03 12:51:08 +00:00
Jon Seager
ff8f0c781e
fix(web): better alignment on mobile for table views 2026-02-03 12:51:01 +00:00
Jon Seager
32c0935124
fix(nav): add responsive hamburger menu for mobile
- Hide horizontal nav links below md breakpoint
- Add hamburger/close toggle button using Datastar signals
- Show vertical dropdown menu on mobile with stacked nav links
2026-02-03 12:50:52 +00:00
Jon Seager
2ac61345ec
feat(backup): add CLI backup and restore commands
- Add BackupData struct and BackupService with raw SQL export/import
- Restore uses raw inserts to bypass brew deductions and timeline creation
- Restore requires an empty database, inserts in FK dependency order
- Add comprehensive e2e test verifying full round-trip fidelity
2026-02-03 12:50:41 +00:00
Jon Seager
cb1cdc5c5b
test(brews): add filter paper coverage to brew API tests
- Add test for creating a brew with filter paper
- Add test verifying filter_paper_name is None when omitted
- Update enriched data test to assert on filter_paper_name
- Add filter_paper category to test helper
2026-02-03 12:50:33 +00:00
Jon Seager
4c7e5346a8
feat(bootstrap): add filter paper gear and brew references
- Add Hario V60 Tabbed 02, Sibarist FAST Specialty 02, and Fellow
  Stagg XF Filters as sample filter paper gear
- Reference filter papers in V60 and Stagg XF brews
2026-02-03 12:50:18 +00:00
Jon Seager
8b77eb90eb
feat(brews): add filter paper to routes, views, CLI, and templates
- Add filter paper dropdown to brew form and gear category form
- Add custom deserializer for optional GearId from HTML forms
- Load filter papers in brews_page handler
- Show filter paper as subtext under brewer in brew list
- Add filter paper to timeline event details and brew-again forms
- Add --filter-paper-id flag to CLI brew add command
2026-02-03 10:14:22 +00:00
Jon Seager
d636f6c246
feat(brews): support filter paper in repository and HTTP client
- Add filter_paper_id to SQL queries (SELECT, INSERT, LEFT JOIN)
- Add filter_paper_name via LEFT JOIN on gear table
- Update BrewRecord and BrewWithDetailsRecord structs
- Add filter_paper_id parameter to HTTP client create method
2026-02-03 10:14:00 +00:00
Jon Seager
0b967cbb14
feat(gear): add filter paper category and optional brew association
- Add migration to extend gear CHECK constraint with 'filter_paper'
  and add nullable filter_paper_id column to brews
- Add FilterPaper variant to GearCategory enum
- Add filter_paper_id to Brew, NewBrew, and BrewWithDetails
- Add filter_paper_id to TimelineBrewData
2026-02-03 10:13:35 +00:00
Jon Seager
4ed1544d66
fix(timeline): ensure cards always alternate sides across month boundaries
Per-month <ol> containers caused :nth-of-type to reset at each month,
putting the first card of consecutive months on the same side. Flatten
all items into a single container and use :nth-child(odd of .timeline-item)
for continuous left/right alternation across months and infinite scroll.
2026-02-03 09:51:48 +00:00
Jon Seager
80849f2bf5
refactor(brews): extract brew timeline event builder into helper
Move timeline event construction out of create_brew to keep the
handler under clippy's too_many_lines limit.
2026-02-03 08:56:29 +00:00
Jon Seager
949f65ac16
refactor(timeline): denormalize data and simplify frontend
Database:
- Add slug, roaster_slug, brew_data_json columns to timeline_events
- Migration backfills existing data from related tables
- Remove 9-way LEFT JOIN from list query, read directly from columns

Frontend:
- Use CSS :nth-of-type(odd/even) for alternating timeline layout
- Remove JavaScript class manipulation when appending month events
- Simplify infinite scroll month-merging logic

This eliminates query-time JOINs across 5 tables and ~20 lines of
client-side JavaScript for pattern maintenance.
2026-02-03 08:53:29 +00:00
Jon Seager
267ef2bf17
feat(timeline): remove sidebar nav, include sticky headers on scroll
- Simplify timeline layout to single-column without sidebar
- Update tests to explicitly pass page_size for pagination testing
- Include sticky headers and a neater alternating, side-by-side
  timeline design
2026-02-02 21:18:20 +00:00
Jon Seager
a0e2c2a1e9
feat(bootstrap): distribute sample data over 6 months
- Add sqlite3 commands to update timestamps after data creation
- Spread gear, roasters, bags, and brews logically from Aug 2025 to Jan 2026
- Ensure temporal consistency (entities created before being referenced)
- Update timeline_events to match entity creation times
2026-02-02 20:20:47 +00:00
Jon Seager
b12ad2bf6d
feat(timeline): add "brew again" button to timeline
- Add TimelineBrewData struct to domain layer to carry raw brew
  parameters needed for repeating a brew
- Extend timeline SQL query to LEFT JOIN with brews table and fetch
  brew data (bag_id, grinder_id, brewer_id, coffee_weight, etc.)
- Add brew_data field to TimelineEventView for template access
- Add is_authenticated to TimelineChunkTemplate for auth-aware chunks
- Add "brew again" button to timeline month partial, visible only for
  authenticated users on brew events
- Server returns reload script when brew is created from timeline page,
  using Datastar's fragment patching to append script to body
2026-02-02 20:14:51 +00:00
Jon Seager
bda59f1c2a
fix(brews): allow arbitrary values in numeric form fields
- Change step to "any" for coffee weight, grind setting, water volume,
  and temperature inputs to allow arbitrary decimal values
- Keep +/- button increments unchanged (0.5g weight, 0.5 grind, 10ml
  water, 0.5°C temp)
2026-02-02 19:59:51 +00:00
Jon Seager
9402d98bb6
fix(brews): improve table layout and add "brew again" feature
- Combine weight/water/ratio into single "Recipe" column
- Reorder columns: Coffee, Grind, Recipe, Temp, Brewer, Date, Actions
- Style actions column with icon buttons (consistent with roasts)
- Add "brew again" button to repeat a brew with same parameters
- Use data-model for form inputs (fixes Datastar binding error)
- Add raw values to BrewView for repeat brew functionality
2026-02-02 19:55:18 +00:00
Jon Seager
7e579cb2d1
fix(brews): improve form defaults and table layout
- Prepopulate form inputs with default values (15g, 6.0 grind, 250ml, 91°C)
- Combine weight/water/ratio into single "Recipe" column
- Reorder columns: Coffee, Grind, Recipe, Temp, Brewer, Date, Actions
- Use trash icon button for delete action (consistent with roasts table)
2026-02-02 19:42:50 +00:00
Jon Seager
8aa72b55eb
fix(brews): prepopulate form fields with default values
Add value attributes to numeric inputs so defaults are visible
when the form is opened.
2026-02-02 19:35:30 +00:00
Jon Seager
b3d697978c
test(brews): add server and CLI integration tests
- Test create, list, get, delete operations
- Test bag deduction and conflict on insufficient coffee
- Test CLI commands with defaults
- Add create_default_gear helper
2026-02-02 19:32:35 +00:00
Jon Seager
0eedf09c08
chore(brews): add sample brews to bootstrap script
- Add 8 sample brews with realistic ratios (1:15 to 1:17)
- Use various bags, grinders, and brewers
2026-02-02 19:32:11 +00:00
Jon Seager
c4357f2698
feat(brews): add web views and templates
- Add BrewView, BagOptionView, GearOptionView
- Add brews page with form and +/- adjustment buttons
- Add brew list partial with sortable columns
- Add Brews link to navigation
2026-02-02 19:31:46 +00:00
Jon Seager
35d64eaed2
feat(brews): add CLI commands
- Add brew add/list/get/delete subcommands
- Defaults: 15g coffee, 6.0 grind, 250ml water, 91°C temp
2026-02-02 19:31:14 +00:00
Jon Seager
6b7b7f9c6e
feat(brews): add application routes and server integration
- Add brew routes: page, create, list, get, delete
- Add timeline event creation when brews are logged
- Add brew_repo to AppState
- Add Conflict variant to AppError for 409 responses
2026-02-02 19:30:45 +00:00
Jon Seager
5f8de35404
feat(brews): add infrastructure layer
- Add SqlBrewRepository with transactional insert that deducts from bag
- Return Conflict error when insufficient coffee in bag
- Add BrewsClient for CLI HTTP operations
2026-02-02 19:30:14 +00:00