Commit graph

398 commits

Author SHA1 Message Date
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
Jon Seager
91bd3172ea
feat(brews): add domain layer and database migration
- Add BrewId typed wrapper
- Add Brew, BrewWithDetails, NewBrew, BrewFilter, BrewSortKey
- Add BrewRepository trait with transactional insert semantics
- Add brews table with foreign keys to bags and gear
- Update timeline_events constraint to include 'brew' entity type
2026-02-02 19:29:23 +00:00
Jon Seager
2bd008a8d7
chore(lint): enable clippy pedantic and restriction lints
- Add [lints.clippy] section to Cargo.toml with pedantic group
- Cherry-pick restriction lints: dbg_macro (deny), todo, unwrap_used, expect_used (warn)
- Allow noisy pedantic lints (missing_errors_doc, module_name_repetitions, etc.)
- Fix unnecessary Result wrappers in token and user repository to_domain functions
- Merge duplicate match arms in TimelineEventViewModel
- Add justified #[allow] attributes for startup code and tests
2026-02-02 17:55:16 +00:00
Jon Seager
500389583f
chore(deps): remove unused wiremock dev-dependency
The wiremock crate was declared in dev-dependencies but never
imported or used anywhere in the test code.
2026-02-02 17:43:13 +00:00
Jon Seager
583f249059
refactor(nix): migrate flake.nix to flake-parts
- Replace manual forAllSystems pattern with flake-parts.lib.mkFlake
- Use perSystem for packages and devShells definitions
- Pin rust-overlay's nixpkgs to follow main nixpkgs input
- No functional changes to package or dev shell
2026-02-02 17:39:38 +00:00
Jon Seager
c7ea7420ae
fix(tests): use CARGO_BIN_EXE for binary path in CLI tests
The CLI tests hardcoded target/debug/brewlog, but nix builds in
release mode. Use Cargo's CARGO_BIN_EXE_brewlog env var which
automatically points to the correct binary location.

This enables running tests during nix build (removes doCheck = false).
2026-02-02 17:37:04 +00:00
Jon Seager
6cd621e10a
refactor(deps): switch from openssl to rustls for TLS
- Add tls-rustls feature to sqlx
- Disable default features on reqwest to avoid native-tls
- Remove openssl from flake.nix build and dev dependencies

This simplifies the build by removing the native OpenSSL dependency,
using pure-Rust TLS implementation instead.
2026-02-02 17:23:42 +00:00
Jon Seager
00477bdbc0
feat(roast): add update command for consistency with other entities
- Add PUT /api/v1/roasts/:id route handler
- Add update() method to roasts HTTP client
- Add UpdateRoastCommand to CLI with optional fields
- Add CLI tests for roast update authentication and functionality

Brings roast entity in line with roaster, bag, and gear which all
support add/list/get/update/delete operations.
2026-02-02 17:09:32 +00:00
Jon Seager
0090c4ba43
refactor(cli): restructure commands from flat to nested subcommands
Change CLI structure from `brewlog {verb}-{entity}` to `brewlog {entity} {verb}`:
- brewlog add-roaster → brewlog roaster add
- brewlog list-bags → brewlog bag list
- brewlog create-token → brewlog token create
- etc.

Each entity module now owns its subcommand enum and dispatch logic,
simplifying main.rs and improving discoverability via `brewlog {entity} --help`.

- Add RoasterCommands, RoastCommands, BagCommands, GearCommands, TokenCommands enums
- Add run() dispatcher to each entity module
- Simplify top-level Commands enum to delegate to entity modules
- Update all CLI tests and bootstrap script
2026-02-02 17:02:46 +00:00
Jon Seager
4edc66f44a
chore(bootstrap): add sample gear (2 grinders, 3 brewers) 2026-02-02 16:48:27 +00:00
Jon Seager
2ed8772302
chore(bootstrap): finish 4 older bags in sample data
Mark 4 of the 12 sample bags as finished to provide more realistic
test data with both open and closed bags in the timeline.
2026-02-02 16:45:27 +00:00
Jon Seager
b3c13faacf
fix(api): make all roast and bag endpoints return enriched types
Previously, list endpoints returned enriched types (RoastWithRoaster,
BagWithRoast) with related entity names, while get/create/update
endpoints returned bare types without this information.

This change makes all endpoints consistent by returning enriched types:
- Added get_with_roaster and get_with_roast repository methods
- Created define_enriched_get_handler! macro for custom getter methods
- Updated create and update handlers to fetch enriched data after write
- Updated CLI client to expect enriched types
2026-02-02 16:43:31 +00:00
Jon Seager
bee94d2a2e
fix(api): flatten RoastWithRoaster JSON response for consistency
The list-roasts API was returning nested objects with a "roast" field,
which was inconsistent with other list APIs in the codebase. Added
serde's #[serde(flatten)] attribute to make the response flat while
maintaining the internal struct composition.
2026-02-02 16:32:56 +00:00