diff --git a/README.md b/README.md index 7f055f0..ee42fc7 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ brewlog bag Manage bags of coffee brewlog gear Manage brewing gear (grinders, brewers, filter papers) brewlog brew Manage brews (add, list, get, delete — no update) brewlog cafe Manage cafes -brewlog cup Manage cups (tasting notes with ratings) +brewlog cup Manage cups (cafe visits with ratings) brewlog token Manage API tokens (create, list, revoke) brewlog backup Export all data to JSON on stdout brewlog restore --file F Restore data from a JSON backup into an empty database diff --git a/migrations/0015_remove_cup_notes.sql b/migrations/0015_remove_cup_notes.sql new file mode 100644 index 0000000..1ee068f --- /dev/null +++ b/migrations/0015_remove_cup_notes.sql @@ -0,0 +1 @@ +ALTER TABLE cups DROP COLUMN notes; diff --git a/scripts/bootstrap-db.sh b/scripts/bootstrap-db.sh index df92615..69f1ccc 100755 --- a/scripts/bootstrap-db.sh +++ b/scripts/bootstrap-db.sh @@ -515,129 +515,128 @@ fi ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Red Brick Espresso") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Monmouth Coffee") | .id')" \ - --notes "Rich and balanced; the house espresso blend is a crowd-pleaser." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Kamwangi") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Monmouth Coffee") | .id')" \ - --notes "Juicy Kenyan pour-over, bright blackcurrant notes." \ + --rating 5 # Prufrock Coffee (London) - 3 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Kochere") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Prufrock Coffee") | .id')" \ - --notes "Delicate floral Ethiopian; exceptional barista technique." \ + --rating 5 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="La Laja") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Prufrock Coffee") | .id')" \ - --notes "Interesting Mexican natural, lots of chocolate." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Ben Saïd Natural") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Prufrock Coffee") | .id')" \ - --notes "Guest roast from Tim Wendelboe; bergamot hit was incredible." \ + --rating 5 # Hola Coffee (Madrid) - 2 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Cerro Azul") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Hola Coffee") | .id')" \ - --notes "Clean Colombian washed, plum and grapefruit forward." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Guji Highland") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Hola Coffee") | .id')" \ - --notes "Peachy natural from April Coffee, worked well as espresso." \ + --rating 3 # Toma Café (Madrid) - 1 cup ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Daterra Sweet Collection") | .id')" \ - --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Toma Café") | .id')" \ - --notes "Smooth Brazilian, hazelnut and chocolate. Nice afternoon flat white." + --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Toma Café") | .id')" # The Barn (Berlin) - 3 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Gatomboya") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="The Barn") | .id')" \ - --notes "Their own roast; classic Kenyan brightness with tomato acidity." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Los Pirineos") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="The Barn") | .id')" \ - --notes "Honey-processed El Salvador, maple sweetness." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Halo Beriti") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="The Barn") | .id')" \ - --notes "La Cabra guest roast, jasmine and lemon." \ + --rating 5 # Companion Coffee (Berlin) - 2 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="El Paraiso 92 Anaerobic") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Companion Coffee") | .id')" \ - --notes "Wild anaerobic from Dak; passionfruit explosion." \ + --rating 5 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Oreti SL28") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Companion Coffee") | .id')" \ - --notes "Crisp Kenyan SL28, grapefruit and plum." \ + --rating 4 # Man Versus Machine (Munich) - 2 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Finca Tamana Washed") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Man Versus Machine") | .id')" \ - --notes "Clean Colombian, red apple and caramel. Beautiful V60." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="La Esmeralda Geisha") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Man Versus Machine") | .id')" \ - --notes "Incredible Geisha from Friedhats; jasmine and papaya. Worth every penny." \ + --rating 5 # Vits der Kaffee (Munich) - 1 cup ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="San Fermin") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Vits der Kaffee") | .id')" \ - --notes "Origin Coffee guest roast; fruity Colombian, blood orange finish." \ + --rating 3 # Full Court Press (Bristol) - 2 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Suke Quto") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Full Court Press") | .id')" \ - --notes "Natural Ethiopian from Stow Coffee; blackberry and jasmine." \ + --rating 5 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Death to Decaf") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Full Court Press") | .id')" \ - --notes "Surprisingly good decaf from Dark Arts. Cocoa and cherry." \ + --rating 3 # Small Street Espresso (Bristol) - 2 cups ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="Simbi") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Small Street Espresso") | .id')" \ - --notes "Rwandan washed from Bows; clean black tea and orange." \ + --rating 4 ./target/debug/brewlog cup add \ --roast-id "$(./target/debug/brewlog roast list | jq -r '.[] | select(.name=="La Chumeca") | .id')" \ --cafe-id "$(./target/debug/brewlog cafe list | jq -r '.[] | select(.name=="Small Street Espresso") | .id')" \ - --notes "Costa Rican honey from Bows; sweet mandarin and honeycomb." \ + --rating 4 # ============================================================================ diff --git a/src/application/routes/cups.rs b/src/application/routes/cups.rs index ed68ebc..6ce3977 100644 --- a/src/application/routes/cups.rs +++ b/src/application/routes/cups.rs @@ -142,7 +142,7 @@ pub(crate) async fn update_cup( Path(id): Path, Json(payload): Json, ) -> Result, ApiError> { - let has_changes = payload.notes.is_some() || payload.rating.is_some(); + let has_changes = payload.rating.is_some(); if !has_changes { return Err(AppError::validation("no changes provided").into()); diff --git a/src/domain/cups.rs b/src/domain/cups.rs index 491019b..1c9d9b8 100644 --- a/src/domain/cups.rs +++ b/src/domain/cups.rs @@ -9,7 +9,6 @@ pub struct Cup { pub id: CupId, pub roast_id: RoastId, pub cafe_id: CafeId, - pub notes: Option, pub rating: Option, pub created_at: DateTime, pub updated_at: DateTime, @@ -31,13 +30,11 @@ pub struct CupWithDetails { pub struct NewCup { pub roast_id: RoastId, pub cafe_id: CafeId, - pub notes: Option, pub rating: Option, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct UpdateCup { - pub notes: Option, pub rating: Option, } diff --git a/src/infrastructure/repositories/cups.rs b/src/infrastructure/repositories/cups.rs index aefa67a..b7666d5 100644 --- a/src/infrastructure/repositories/cups.rs +++ b/src/infrastructure/repositories/cups.rs @@ -13,7 +13,7 @@ use crate::infrastructure::database::DatabasePool; const BASE_SELECT: &str = r" SELECT - c.id, c.roast_id, c.cafe_id, c.notes, c.rating, + c.id, c.roast_id, c.cafe_id, c.rating, c.created_at, c.updated_at, r.name as roast_name, r.slug as roast_slug, rr.name as roaster_name, rr.slug as roaster_slug, @@ -57,7 +57,6 @@ impl SqlCupRepository { id: CupId::new(record.id), roast_id: RoastId::new(record.roast_id), cafe_id: CafeId::new(record.cafe_id), - notes: record.notes, rating: record.rating, created_at: record.created_at, updated_at: record.updated_at, @@ -70,7 +69,6 @@ impl SqlCupRepository { id: CupId::new(record.id), roast_id: RoastId::new(record.roast_id), cafe_id: CafeId::new(record.cafe_id), - notes: record.notes, rating: record.rating, created_at: record.created_at, updated_at: record.updated_at, @@ -141,12 +139,11 @@ impl CupRepository for SqlCupRepository { .map_err(|err| RepositoryError::unexpected(err.to_string()))?; let record = query_as::<_, CupRecord>( - "INSERT INTO cups (roast_id, cafe_id, notes, rating) VALUES (?, ?, ?, ?) \ - RETURNING id, roast_id, cafe_id, notes, rating, created_at, updated_at", + "INSERT INTO cups (roast_id, cafe_id, rating) VALUES (?, ?, ?) \ + RETURNING id, roast_id, cafe_id, rating, created_at, updated_at", ) .bind(new_cup.roast_id.into_inner()) .bind(new_cup.cafe_id.into_inner()) - .bind(new_cup.notes.as_deref()) .bind(new_cup.rating) .fetch_one(&mut *tx) .await @@ -196,7 +193,7 @@ impl CupRepository for SqlCupRepository { async fn get(&self, id: CupId) -> Result { let record = query_as::<_, CupRecord>( - "SELECT id, roast_id, cafe_id, notes, rating, created_at, updated_at FROM cups WHERE id = ?", + "SELECT id, roast_id, cafe_id, rating, created_at, updated_at FROM cups WHERE id = ?", ) .bind(i64::from(id)) .fetch_optional(&self.pool) @@ -268,7 +265,6 @@ impl CupRepository for SqlCupRepository { let mut builder = QueryBuilder::new("UPDATE cups SET updated_at = CURRENT_TIMESTAMP"); let mut sep = true; - push_update_field!(builder, sep, "notes", changes.notes); push_update_field!(builder, sep, "rating", changes.rating); let _ = sep; @@ -308,7 +304,6 @@ struct CupRecord { id: i64, roast_id: i64, cafe_id: i64, - notes: Option, rating: Option, created_at: DateTime, updated_at: DateTime, @@ -319,7 +314,6 @@ struct CupWithDetailsRecord { id: i64, roast_id: i64, cafe_id: i64, - notes: Option, rating: Option, created_at: DateTime, updated_at: DateTime, diff --git a/src/presentation/cli/cups.rs b/src/presentation/cli/cups.rs index e930b50..0531907 100644 --- a/src/presentation/cli/cups.rs +++ b/src/presentation/cli/cups.rs @@ -38,8 +38,6 @@ pub struct AddCupCommand { #[arg(long)] pub cafe_id: i64, #[arg(long)] - pub notes: Option, - #[arg(long)] pub rating: Option, } @@ -47,7 +45,6 @@ pub async fn add_cup(client: &BrewlogClient, command: AddCupCommand) -> Result<( let payload = NewCup { roast_id: RoastId::new(command.roast_id), cafe_id: CafeId::new(command.cafe_id), - notes: command.notes, rating: command.rating, }; @@ -67,14 +64,11 @@ pub struct UpdateCupCommand { #[arg(long)] pub id: i64, #[arg(long)] - pub notes: Option, - #[arg(long)] pub rating: Option, } pub async fn update_cup(client: &BrewlogClient, command: UpdateCupCommand) -> Result<()> { let payload = UpdateCup { - notes: command.notes, rating: command.rating, }; diff --git a/src/presentation/web/views/cups.rs b/src/presentation/web/views/cups.rs index 63a5674..d2ac982 100644 --- a/src/presentation/web/views/cups.rs +++ b/src/presentation/web/views/cups.rs @@ -9,8 +9,6 @@ pub struct CupView { pub roaster_slug: String, pub cafe_name: String, pub cafe_slug: String, - pub notes: String, - pub has_notes: bool, pub rating: String, pub has_rating: bool, pub created_at: String, @@ -18,8 +16,6 @@ pub struct CupView { impl CupView { pub fn from_domain(cup: CupWithDetails) -> Self { - let notes = cup.cup.notes.clone().unwrap_or_default(); - let has_notes = !notes.is_empty(); let rating = cup .cup .rating @@ -34,8 +30,6 @@ impl CupView { roaster_slug: cup.roaster_slug, cafe_name: cup.cafe_name, cafe_slug: cup.cafe_slug, - notes, - has_notes, rating, has_rating, created_at: cup.cup.created_at.format("%Y-%m-%d %H:%M").to_string(), diff --git a/templates/cups.html b/templates/cups.html index 2dbbd3f..f7ae0da 100644 --- a/templates/cups.html +++ b/templates/cups.html @@ -70,15 +70,6 @@ -