refactor(roasters): remove notes field from Roaster entity

- 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
This commit is contained in:
Jon Seager 2026-02-03 21:18:48 +00:00
parent ae82e8a16e
commit 4f7d31d47a
No known key found for this signature in database
19 changed files with 30 additions and 114 deletions

View file

@ -0,0 +1 @@
ALTER TABLE roasters DROP COLUMN notes;

View file

@ -16,8 +16,7 @@ fi
--name "Tim Wendelboe" \ --name "Tim Wendelboe" \
--country "Norway" \ --country "Norway" \
--city "Oslo" \ --city "Oslo" \
--homepage "https://timwendelboe.no" \ --homepage "https://timwendelboe.no"
--notes "World-renowned Nordic micro-roastery dedicated to clarity and sustainability."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Tim Wendelboe") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Tim Wendelboe") | .id')" \
@ -43,8 +42,7 @@ fi
--name "Coffee Collective" \ --name "Coffee Collective" \
--country "Denmark" \ --country "Denmark" \
--city "Copenhagen" \ --city "Copenhagen" \
--homepage "https://coffeecollective.dk" \ --homepage "https://coffeecollective.dk"
--notes "Pioneers of transparency and sustainability; multi-time Nordic roaster award winners."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Coffee Collective") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Coffee Collective") | .id')" \
@ -70,8 +68,7 @@ fi
--name "Drop Coffee" \ --name "Drop Coffee" \
--country "Sweden" \ --country "Sweden" \
--city "Stockholm" \ --city "Stockholm" \
--homepage "https://dropcoffee.com" \ --homepage "https://dropcoffee.com"
--notes "Award-winning Swedish roastery prized for its elegance and clean Scandinavian style."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Drop Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Drop Coffee") | .id')" \
@ -97,8 +94,7 @@ fi
--name "La Cabra" \ --name "La Cabra" \
--country "Denmark" \ --country "Denmark" \
--city "Aarhus" \ --city "Aarhus" \
--homepage "https://www.lacabra.dk" \ --homepage "https://www.lacabra.dk"
--notes "Scandinavian minimalist roastery known for clarity and innovative sourcing."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="La Cabra") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="La Cabra") | .id')" \
@ -124,8 +120,7 @@ fi
--name "April Coffee" \ --name "April Coffee" \
--country "Denmark" \ --country "Denmark" \
--city "Copenhagen" \ --city "Copenhagen" \
--homepage "https://aprilcoffeeroasters.com" \ --homepage "https://aprilcoffeeroasters.com"
--notes "Modern approach to Nordic coffee, emphasizing transparency and traceability."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="April Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="April Coffee") | .id')" \
@ -151,8 +146,7 @@ fi
--name "Assembly Coffee" \ --name "Assembly Coffee" \
--country "United Kingdom" \ --country "United Kingdom" \
--city "London" \ --city "London" \
--homepage "https://assemblycoffee.co.uk" \ --homepage "https://assemblycoffee.co.uk"
--notes "Based in Brixton, Assembly focuses on collaborative sourcing and education."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Assembly Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Assembly Coffee") | .id')" \
@ -178,8 +172,7 @@ fi
--name "Square Mile Coffee" \ --name "Square Mile Coffee" \
--country "United Kingdom" \ --country "United Kingdom" \
--city "London" \ --city "London" \
--homepage "https://squaremilecoffee.com" \ --homepage "https://squaremilecoffee.com"
--notes "One of London's pioneers; delivers balanced and clear, fruit-forward coffees."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Square Mile Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Square Mile Coffee") | .id')" \
@ -205,8 +198,7 @@ fi
--name "Dak Coffee Roasters" \ --name "Dak Coffee Roasters" \
--country "Netherlands" \ --country "Netherlands" \
--city "Amsterdam" \ --city "Amsterdam" \
--homepage "https://www.dakcoffeeroasters.com" \ --homepage "https://www.dakcoffeeroasters.com"
--notes "Highly experimental Dutch roastery; celebrates vibrant acidity and alternative processing."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Dak Coffee Roasters") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Dak Coffee Roasters") | .id')" \
@ -232,8 +224,7 @@ fi
--name "Bonanza Coffee" \ --name "Bonanza Coffee" \
--country "Germany" \ --country "Germany" \
--city "Berlin" \ --city "Berlin" \
--homepage "https://www.bonanzacoffee.de" \ --homepage "https://www.bonanzacoffee.de"
--notes "Pioneering Berlin roastery focused on brightness, balance, and freshness."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Bonanza Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Bonanza Coffee") | .id')" \
@ -259,8 +250,7 @@ fi
--name "Friedhats" \ --name "Friedhats" \
--country "Netherlands" \ --country "Netherlands" \
--city "Amsterdam" \ --city "Amsterdam" \
--homepage "https://friedhats.com" \ --homepage "https://friedhats.com"
--notes "Quirky branding meets serious, awarded, fruit-forward coffees from Amsterdam."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Friedhats") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Friedhats") | .id')" \
@ -286,8 +276,7 @@ fi
--name "Origin Coffee" \ --name "Origin Coffee" \
--country "United Kingdom" \ --country "United Kingdom" \
--city "Porthleven" \ --city "Porthleven" \
--homepage "https://origincoffee.co.uk" \ --homepage "https://origincoffee.co.uk"
--notes "Specialty roaster with close partnerships at origin; leading UK scene with cutting-edge lots."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Origin Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Origin Coffee") | .id')" \
@ -313,8 +302,7 @@ fi
--name "Dark Arts Coffee" \ --name "Dark Arts Coffee" \
--country "United Kingdom" \ --country "United Kingdom" \
--city "London" \ --city "London" \
--homepage "https://www.darkartscoffee.co.uk" \ --homepage "https://www.darkartscoffee.co.uk"
--notes "Playful, disruptive roaster with a cult following and flavor-forward offerings."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Dark Arts Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Dark Arts Coffee") | .id')" \
@ -340,8 +328,7 @@ fi
--name "KAWA Coffee" \ --name "KAWA Coffee" \
--country "France" \ --country "France" \
--city "Paris" \ --city "Paris" \
--homepage "https://www.kawa.coffee" \ --homepage "https://www.kawa.coffee"
--notes "One of Paris most exciting specialty roasteries, known for unusual and competition-level lots."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="KAWA Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="KAWA Coffee") | .id')" \
@ -367,8 +354,7 @@ fi
--name "Stow Coffee" \ --name "Stow Coffee" \
--country "Slovenia" \ --country "Slovenia" \
--city "Ljubljana" \ --city "Ljubljana" \
--homepage "https://www.stowcoffee.com" \ --homepage "https://www.stowcoffee.com"
--notes "Slovenias specialty leader, awarded for pure, brightly acidic profiles and innovation."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Stow Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Stow Coffee") | .id')" \
@ -394,8 +380,7 @@ fi
--name "Bows Coffee" \ --name "Bows Coffee" \
--country "Canada" \ --country "Canada" \
--city "Victoria" \ --city "Victoria" \
--homepage "https://bowscoffee.com" \ --homepage "https://bowscoffee.com"
--notes "Canadian micro-roaster with focus on clarity, complexity, and ethical sourcing."
./target/debug/brewlog roast add \ ./target/debug/brewlog roast add \
--roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Bows Coffee") | .id')" \ --roaster-id "$(./target/debug/brewlog roaster list | jq -r '.[] | select(.name=="Bows Coffee") | .id')" \

View file

@ -163,8 +163,7 @@ pub(crate) async fn update_roaster(
let has_changes = payload.name.is_some() let has_changes = payload.name.is_some()
|| payload.country.is_some() || payload.country.is_some()
|| payload.city.is_some() || payload.city.is_some()
|| payload.homepage.is_some() || payload.homepage.is_some();
|| payload.notes.is_some();
if !has_changes { if !has_changes {
return Err(AppError::validation("no changes provided").into()); return Err(AppError::validation("no changes provided").into());

View file

@ -58,7 +58,6 @@ pub(crate) struct BagScanSubmission {
roaster_country: String, roaster_country: String,
roaster_city: Option<String>, roaster_city: Option<String>,
roaster_homepage: Option<String>, roaster_homepage: Option<String>,
roaster_notes: Option<String>,
roast_name: String, roast_name: String,
origin: String, origin: String,
region: String, region: String,
@ -84,7 +83,6 @@ pub(crate) async fn submit_scan(
country: submission.roaster_country, country: submission.roaster_country,
city: submission.roaster_city, city: submission.roaster_city,
homepage: submission.roaster_homepage, homepage: submission.roaster_homepage,
notes: submission.roaster_notes,
} }
.normalize(); .normalize();

View file

@ -12,7 +12,6 @@ pub struct Roaster {
pub country: String, pub country: String,
pub city: Option<String>, pub city: Option<String>,
pub homepage: Option<String>, pub homepage: Option<String>,
pub notes: Option<String>,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
} }
@ -22,7 +21,6 @@ pub struct NewRoaster {
pub country: String, pub country: String,
pub city: Option<String>, pub city: Option<String>,
pub homepage: Option<String>, pub homepage: Option<String>,
pub notes: Option<String>,
} }
impl NewRoaster { impl NewRoaster {
@ -31,7 +29,6 @@ impl NewRoaster {
self.country = self.country.trim().to_string(); self.country = self.country.trim().to_string();
self.city = normalize_optional_field(self.city); self.city = normalize_optional_field(self.city);
self.homepage = normalize_optional_field(self.homepage); self.homepage = normalize_optional_field(self.homepage);
self.notes = normalize_optional_field(self.notes);
self self
} }
@ -61,7 +58,6 @@ pub struct UpdateRoaster {
pub country: Option<String>, pub country: Option<String>,
pub city: Option<String>, pub city: Option<String>,
pub homepage: Option<String>, pub homepage: Option<String>,
pub notes: Option<String>,
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]

View file

@ -13,7 +13,6 @@ const ROASTER_PROMPT: &str = r#"Extract coffee roaster information from this inp
- "country": the country the roaster is based in - "country": the country the roaster is based in
- "city": the city the roaster is based in - "city": the city the roaster is based in
- "homepage": the roaster's website URL - "homepage": the roaster's website URL
- "notes": a single sentence describing the roaster (e.g. sourcing philosophy, speciality, or founding story)
Return ONLY the JSON object, no other text."#; Return ONLY the JSON object, no other text."#;
@ -35,8 +34,7 @@ const SCAN_PROMPT: &str = r#"Extract both the coffee roaster and the roast infor
"name": "the roaster's name", "name": "the roaster's name",
"country": "country the roaster is based in", "country": "country the roaster is based in",
"city": "city the roaster is based in", "city": "city the roaster is based in",
"homepage": "the roaster's website URL", "homepage": "the roaster's website URL"
"notes": "a single sentence describing the roaster"
}, },
"roast": { "roast": {
"name": "the name of this specific coffee/roast", "name": "the name of this specific coffee/roast",
@ -64,7 +62,6 @@ pub struct ExtractedRoaster {
pub country: Option<String>, pub country: Option<String>,
pub city: Option<String>, pub city: Option<String>,
pub homepage: Option<String>, pub homepage: Option<String>,
pub notes: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]

View file

@ -87,7 +87,7 @@ impl BackupService {
async fn export_roasters(&self) -> anyhow::Result<Vec<Roaster>> { async fn export_roasters(&self) -> anyhow::Result<Vec<Roaster>> {
let records = sqlx::query_as::<_, RoasterRecord>( let records = sqlx::query_as::<_, RoasterRecord>(
"SELECT id, name, slug, country, city, homepage, notes, created_at FROM roasters ORDER BY id", "SELECT id, name, slug, country, city, homepage, created_at FROM roasters ORDER BY id",
) )
.fetch_all(&self.pool) .fetch_all(&self.pool)
.await .await
@ -212,7 +212,7 @@ impl BackupService {
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
for roaster in roasters { for roaster in roasters {
sqlx::query( sqlx::query(
"INSERT INTO roasters (id, name, slug, country, city, homepage, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", "INSERT INTO roasters (id, name, slug, country, city, homepage, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
) )
.bind(i64::from(roaster.id)) .bind(i64::from(roaster.id))
.bind(&roaster.name) .bind(&roaster.name)
@ -220,7 +220,6 @@ impl BackupService {
.bind(&roaster.country) .bind(&roaster.country)
.bind(roaster.city.as_deref()) .bind(roaster.city.as_deref())
.bind(roaster.homepage.as_deref()) .bind(roaster.homepage.as_deref())
.bind(roaster.notes.as_deref())
.bind(roaster.created_at) .bind(roaster.created_at)
.execute(&mut **tx) .execute(&mut **tx)
.await .await
@ -422,7 +421,6 @@ struct RoasterRecord {
country: String, country: String,
city: Option<String>, city: Option<String>,
homepage: Option<String>, homepage: Option<String>,
notes: Option<String>,
created_at: DateTime<Utc>, created_at: DateTime<Utc>,
} }
@ -435,7 +433,6 @@ impl RoasterRecord {
country: self.country, country: self.country,
city: self.city, city: self.city,
homepage: self.homepage, homepage: self.homepage,
notes: self.notes,
created_at: self.created_at, created_at: self.created_at,
} }
} }

View file

@ -43,7 +43,6 @@ impl SqlRoasterRepository {
country, country,
city, city,
homepage, homepage,
notes,
created_at, created_at,
} = record; } = record;
@ -54,7 +53,6 @@ impl SqlRoasterRepository {
country, country,
city, city,
homepage, homepage,
notes,
created_at, created_at,
} }
} }
@ -107,15 +105,14 @@ impl RoasterRepository for SqlRoasterRepository {
let created_at = Utc::now(); let created_at = Utc::now();
let record = query_as::<_, RoasterRecord>( let record = query_as::<_, RoasterRecord>(
"INSERT INTO roasters (name, slug, country, city, homepage, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)\ "INSERT INTO roasters (name, slug, country, city, homepage, created_at) VALUES (?, ?, ?, ?, ?, ?)\
RETURNING id, name, slug, country, city, homepage, notes, created_at", RETURNING id, name, slug, country, city, homepage, created_at",
) )
.bind(&new_roaster.name) .bind(&new_roaster.name)
.bind(&slug) .bind(&slug)
.bind(&new_roaster.country) .bind(&new_roaster.country)
.bind(new_roaster.city.as_deref()) .bind(new_roaster.city.as_deref())
.bind(new_roaster.homepage.as_deref()) .bind(new_roaster.homepage.as_deref())
.bind(new_roaster.notes.as_deref())
.bind(created_at) .bind(created_at)
.fetch_one(&mut *tx) .fetch_one(&mut *tx)
.await .await
@ -159,12 +156,12 @@ impl RoasterRepository for SqlRoasterRepository {
async fn get(&self, id: RoasterId) -> Result<Roaster, RepositoryError> { async fn get(&self, id: RoasterId) -> Result<Roaster, RepositoryError> {
let record = query_as::<_, RoasterRecord>( let record = query_as::<_, RoasterRecord>(
"SELECT id, name, slug, country, city, homepage, notes, created_at FROM roasters WHERE id = ?", "SELECT id, name, slug, country, city, homepage, created_at FROM roasters WHERE id = ?",
) )
.bind(i64::from(id)) .bind(i64::from(id))
.fetch_optional(&self.pool) .fetch_optional(&self.pool)
.await .await
.map_err(|err| RepositoryError::unexpected(err.to_string()))?; .map_err(|err| RepositoryError::unexpected(err.to_string()))?;
match record { match record {
Some(record) => Ok(Self::into_domain(record)), Some(record) => Ok(Self::into_domain(record)),
@ -174,7 +171,7 @@ impl RoasterRepository for SqlRoasterRepository {
async fn get_by_slug(&self, slug: &str) -> Result<Roaster, RepositoryError> { async fn get_by_slug(&self, slug: &str) -> Result<Roaster, RepositoryError> {
let record = query_as::<_, RoasterRecord>( let record = query_as::<_, RoasterRecord>(
"SELECT id, name, slug, country, city, homepage, notes, created_at FROM roasters WHERE slug = ?", "SELECT id, name, slug, country, city, homepage, created_at FROM roasters WHERE slug = ?",
) )
.bind(slug) .bind(slug)
.fetch_optional(&self.pool) .fetch_optional(&self.pool)
@ -195,8 +192,7 @@ impl RoasterRepository for SqlRoasterRepository {
use crate::infrastructure::repositories::pagination::SearchFilter; use crate::infrastructure::repositories::pagination::SearchFilter;
let order_clause = Self::order_clause(request); let order_clause = Self::order_clause(request);
let base_query = let base_query = "SELECT id, name, slug, country, city, homepage, created_at FROM roasters";
"SELECT id, name, slug, country, city, homepage, notes, created_at FROM roasters";
let count_query = "SELECT COUNT(*) FROM roasters"; let count_query = "SELECT COUNT(*) FROM roasters";
let sf = let sf =
search.and_then(|t| SearchFilter::new(t, vec!["name", "country", "COALESCE(city,'')"])); search.and_then(|t| SearchFilter::new(t, vec!["name", "country", "COALESCE(city,'')"]));
@ -225,7 +221,6 @@ impl RoasterRepository for SqlRoasterRepository {
push_update_field!(builder, sep, "country", changes.country); push_update_field!(builder, sep, "country", changes.country);
push_update_field!(builder, sep, "city", changes.city); push_update_field!(builder, sep, "city", changes.city);
push_update_field!(builder, sep, "homepage", changes.homepage); push_update_field!(builder, sep, "homepage", changes.homepage);
push_update_field!(builder, sep, "notes", changes.notes);
if !sep { if !sep {
return Err(RepositoryError::unexpected( return Err(RepositoryError::unexpected(
@ -272,6 +267,5 @@ struct RoasterRecord {
country: String, country: String,
city: Option<String>, city: Option<String>,
homepage: Option<String>, homepage: Option<String>,
notes: Option<String>,
created_at: DateTime<Utc>, created_at: DateTime<Utc>,
} }

View file

@ -41,8 +41,6 @@ pub struct AddRoasterCommand {
pub city: Option<String>, pub city: Option<String>,
#[arg(long)] #[arg(long)]
pub homepage: Option<String>, pub homepage: Option<String>,
#[arg(long)]
pub notes: Option<String>,
} }
pub async fn add_roaster(client: &BrewlogClient, command: AddRoasterCommand) -> Result<()> { pub async fn add_roaster(client: &BrewlogClient, command: AddRoasterCommand) -> Result<()> {
@ -51,7 +49,6 @@ pub async fn add_roaster(client: &BrewlogClient, command: AddRoasterCommand) ->
country: command.country, country: command.country,
city: command.city, city: command.city,
homepage: command.homepage, homepage: command.homepage,
notes: command.notes,
}; };
let roaster = client.roasters().create(&payload).await?; let roaster = client.roasters().create(&payload).await?;
@ -77,8 +74,6 @@ pub struct UpdateRoasterCommand {
pub city: Option<String>, pub city: Option<String>,
#[arg(long)] #[arg(long)]
pub homepage: Option<String>, pub homepage: Option<String>,
#[arg(long)]
pub notes: Option<String>,
} }
pub async fn update_roaster(client: &BrewlogClient, command: UpdateRoasterCommand) -> Result<()> { pub async fn update_roaster(client: &BrewlogClient, command: UpdateRoasterCommand) -> Result<()> {
@ -87,7 +82,6 @@ pub async fn update_roaster(client: &BrewlogClient, command: UpdateRoasterComman
country: command.country, country: command.country,
city: command.city, city: command.city,
homepage: command.homepage, homepage: command.homepage,
notes: command.notes,
}; };
let roaster = client let roaster = client

View file

@ -32,7 +32,6 @@ pub struct RoasterView {
pub has_homepage: bool, pub has_homepage: bool,
pub homepage_url: String, pub homepage_url: String,
pub homepage_label: String, pub homepage_label: String,
pub notes: String,
pub created_at: String, pub created_at: String,
pub created_at_sort_key: i64, pub created_at_sort_key: i64,
} }
@ -46,7 +45,6 @@ impl From<Roaster> for RoasterView {
country, country,
city, city,
homepage, homepage,
notes,
created_at, created_at,
} = roaster; } = roaster;
@ -66,7 +64,6 @@ impl From<Roaster> for RoasterView {
has_homepage, has_homepage,
homepage_url: homepage.clone(), homepage_url: homepage.clone(),
homepage_label: homepage, homepage_label: homepage,
notes: notes.unwrap_or_else(|| "This roaster has no notes yet.".to_string()),
created_at: created_at_label, created_at: created_at_label,
created_at_sort_key, created_at_sort_key,
} }

View file

@ -21,7 +21,6 @@
{% call table::sortable_header("Added", "created-at", navigator, "#roaster-list") %} {% call table::sortable_header("Added", "created-at", navigator, "#roaster-list") %}
{% call table::sortable_header("Name", "name", navigator, "#roaster-list") %} {% call table::sortable_header("Name", "name", navigator, "#roaster-list") %}
{% call table::sortable_header("Location", "country", navigator, "#roaster-list") %} {% call table::sortable_header("Location", "country", navigator, "#roaster-list") %}
<th scope="col" class="px-4 py-3">Notes</th>
<th scope="col" class="px-4 py-3 text-right">Actions</th> <th scope="col" class="px-4 py-3 text-right">Actions</th>
</tr> </tr>
</thead> </thead>
@ -54,7 +53,6 @@
{% if !roaster.city.is_empty() %} {% if !roaster.city.is_empty() %}
<td data-label="City" class="px-4 py-3 whitespace-nowrap md:hidden">{{ roaster.city }}</td> <td data-label="City" class="px-4 py-3 whitespace-nowrap md:hidden">{{ roaster.city }}</td>
{% endif %} {% endif %}
<td data-label="Notes" class="mobile-hidden px-4 py-3 text-sm text-stone-600">{{ roaster.notes }}</td>
<td data-label="" class="px-4 py-3 text-right"> <td data-label="" class="px-4 py-3 text-right">
<div class="inline-flex items-center gap-1"> <div class="inline-flex items-center gap-1">
{% if roaster.has_homepage %} {% if roaster.has_homepage %}

View file

@ -47,7 +47,6 @@ block content %}
<dd class="text-right">{{ roaster.created_at }}</dd> <dd class="text-right">{{ roaster.created_at }}</dd>
</div> </div>
</dl> </dl>
<p class="text-sm text-stone-600">{{ roaster.notes }}</p>
</section> </section>
<section class="flex flex-col gap-4"> <section class="flex flex-col gap-4">

View file

@ -11,7 +11,6 @@
if (data.country) form.querySelector('[name="country"]').value = data.country; if (data.country) form.querySelector('[name="country"]').value = data.country;
if (data.city) form.querySelector('[name="city"]').value = data.city; if (data.city) form.querySelector('[name="city"]').value = data.city;
if (data.homepage) form.querySelector('[name="homepage"]').value = data.homepage; if (data.homepage) form.querySelector('[name="homepage"]').value = data.homepage;
if (data.notes) form.querySelector('[name="notes"]').value = data.notes;
} }
</script> </script>
{% endif %} {% endif %}
@ -133,15 +132,6 @@
placeholder="https://example.coffee" placeholder="https://example.coffee"
/> />
</label> </label>
<label class="sm:col-span-2 flex flex-col gap-1 text-sm">
<span class="text-stone-700">Notes</span>
<textarea
name="notes"
rows="3"
class="input-field"
placeholder="Short description, sourcing approach, or contact details"
></textarea>
</label>
</div> </div>
<div class="flex items-center justify-end gap-2"> <div class="flex items-center justify-end gap-2">
<button <button

View file

@ -13,7 +13,6 @@
if (data.roaster.country) form.querySelector('[name="roaster_country"]').value = data.roaster.country; if (data.roaster.country) form.querySelector('[name="roaster_country"]').value = data.roaster.country;
if (data.roaster.city) form.querySelector('[name="roaster_city"]').value = data.roaster.city; if (data.roaster.city) form.querySelector('[name="roaster_city"]').value = data.roaster.city;
if (data.roaster.homepage) form.querySelector('[name="roaster_homepage"]').value = data.roaster.homepage; if (data.roaster.homepage) form.querySelector('[name="roaster_homepage"]').value = data.roaster.homepage;
if (data.roaster.notes) form.querySelector('[name="roaster_notes"]').value = data.roaster.notes;
} }
if (data.roast) { if (data.roast) {
if (data.roast.name) form.querySelector('[name="roast_name"]').value = data.roast.name; if (data.roast.name) form.querySelector('[name="roast_name"]').value = data.roast.name;
@ -152,10 +151,6 @@
<span class="text-stone-700">Homepage</span> <span class="text-stone-700">Homepage</span>
<input type="url" name="roaster_homepage" class="input-field" placeholder="https://example.coffee" /> <input type="url" name="roaster_homepage" class="input-field" placeholder="https://example.coffee" />
</label> </label>
<label class="sm:col-span-2 flex flex-col gap-1 text-sm">
<span class="text-stone-700">Notes</span>
<textarea name="roaster_notes" rows="2" class="input-field" placeholder="Short description of the roaster"></textarea>
</label>
</div> </div>
</div> </div>

View file

@ -122,7 +122,6 @@ async fn populate_test_data(db: &TestDb) -> (Roaster, Roast, Bag, Gear, Gear, Ge
country: "UK".to_string(), country: "UK".to_string(),
city: Some("London".to_string()), city: Some("London".to_string()),
homepage: Some("https://shop.squaremilecoffee.com".to_string()), homepage: Some("https://shop.squaremilecoffee.com".to_string()),
notes: Some("Great seasonal espresso".to_string()),
}) })
.await .await
.expect("failed to create roaster"); .expect("failed to create roaster");
@ -305,7 +304,6 @@ async fn backup_and_restore_round_trip() {
assert_eq!(restored_roaster.country, roaster.country); assert_eq!(restored_roaster.country, roaster.country);
assert_eq!(restored_roaster.city, roaster.city); assert_eq!(restored_roaster.city, roaster.city);
assert_eq!(restored_roaster.homepage, roaster.homepage); assert_eq!(restored_roaster.homepage, roaster.homepage);
assert_eq!(restored_roaster.notes, roaster.notes);
assert_eq!(restored_roaster.created_at, roaster.created_at); assert_eq!(restored_roaster.created_at, roaster.created_at);
// Roasts // Roasts
@ -405,7 +403,6 @@ async fn restore_to_non_empty_database_fails() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}) })
.await .await
.expect("failed to create roaster"); .expect("failed to create roaster");

View file

@ -70,7 +70,6 @@ async fn roasters_create_with_datastar_header_returns_fragment() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
let response = client let response = client
@ -103,7 +102,6 @@ async fn roasters_create_without_datastar_header_returns_json() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
let response = client let response = client

View file

@ -325,7 +325,6 @@ pub async fn create_roaster_with_name(app: &TestApp, name: &str) -> Roaster {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}, },
) )
.await .await

View file

@ -12,7 +12,6 @@ async fn creating_a_roaster_returns_a_201_for_valid_data() {
country: "United Kingdom".to_string(), country: "United Kingdom".to_string(),
city: Some("London".to_string()), city: Some("London".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: Some("Great coffee".to_string()),
}; };
// Act // Act
@ -32,7 +31,6 @@ async fn creating_a_roaster_returns_a_201_for_valid_data() {
assert_eq!(roaster.country, "United Kingdom"); assert_eq!(roaster.country, "United Kingdom");
assert_eq!(roaster.city, Some("London".to_string())); assert_eq!(roaster.city, Some("London".to_string()));
assert_eq!(roaster.homepage, Some("https://example.com".to_string())); assert_eq!(roaster.homepage, Some("https://example.com".to_string()));
assert_eq!(roaster.notes, Some("Great coffee".to_string()));
} }
#[tokio::test] #[tokio::test]
@ -46,7 +44,6 @@ async fn creating_a_roaster_persists_the_data() {
country: "France".to_string(), country: "France".to_string(),
city: Some("Paris".to_string()), city: Some("Paris".to_string()),
homepage: None, homepage: None,
notes: None,
}; };
// Act // Act
@ -83,7 +80,6 @@ async fn getting_a_roaster_returns_a_200_for_valid_id() {
country: "Germany".to_string(), country: "Germany".to_string(),
city: Some("Berlin".to_string()), city: Some("Berlin".to_string()),
homepage: None, homepage: None,
notes: None,
}; };
let create_response = client let create_response = client
@ -163,7 +159,6 @@ async fn listing_roasters_returns_a_200_with_multiple_roasters() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
let roaster2 = NewRoaster { let roaster2 = NewRoaster {
@ -171,7 +166,6 @@ async fn listing_roasters_returns_a_200_with_multiple_roasters() {
country: "USA".to_string(), country: "USA".to_string(),
city: Some("New York".to_string()), city: Some("New York".to_string()),
homepage: None, homepage: None,
notes: None,
}; };
client client
@ -215,7 +209,6 @@ async fn updating_a_roaster_returns_a_200_for_valid_data() {
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Manchester".to_string()), city: Some("Manchester".to_string()),
homepage: None, homepage: None,
notes: None,
}; };
let create_response = client let create_response = client
@ -236,7 +229,6 @@ async fn updating_a_roaster_returns_a_200_for_valid_data() {
country: None, country: None,
city: Some("Liverpool".to_string()), city: Some("Liverpool".to_string()),
homepage: Some("https://updated.com".to_string()), homepage: Some("https://updated.com".to_string()),
notes: None,
}; };
// Act // Act
@ -272,7 +264,6 @@ async fn updating_a_roaster_with_no_changes_returns_a_400() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
let create_response = client let create_response = client
@ -293,7 +284,6 @@ async fn updating_a_roaster_with_no_changes_returns_a_400() {
country: None, country: None,
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
// Act // Act
@ -320,7 +310,6 @@ async fn updating_a_nonexistent_roaster_returns_a_404() {
country: None, country: None,
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
// Act // Act
@ -347,7 +336,6 @@ async fn deleting_a_roaster_returns_a_204_for_valid_id() {
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
let create_response = client let create_response = client
@ -414,7 +402,6 @@ async fn creating_a_roaster_with_empty_name_returns_a_201_after_normalization()
country: "UK".to_string(), country: "UK".to_string(),
city: None, city: None,
homepage: None, homepage: None,
notes: None,
}; };
// Act // Act

View file

@ -41,7 +41,6 @@ async fn seed_timeline_with_roasts(
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Bristol".to_string()), city: Some("Bristol".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: None,
}, },
) )
.await; .await;
@ -94,7 +93,6 @@ async fn creating_a_roaster_surfaces_on_the_timeline() {
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Bristol".to_string()), city: Some("Bristol".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: None,
}, },
) )
.await; .await;
@ -136,7 +134,6 @@ async fn creating_a_roast_surfaces_on_the_timeline() {
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Bristol".to_string()), city: Some("Bristol".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: None,
}, },
) )
.await .await
@ -181,7 +178,6 @@ async fn creating_a_bag_surfaces_on_the_timeline() {
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Bristol".to_string()), city: Some("Bristol".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: None,
}, },
) )
.await .await
@ -342,7 +338,6 @@ async fn closing_a_bag_surfaces_on_the_timeline() {
country: "UK".to_string(), country: "UK".to_string(),
city: Some("Bristol".to_string()), city: Some("Bristol".to_string()),
homepage: Some("https://example.com".to_string()), homepage: Some("https://example.com".to_string()),
notes: None,
}, },
) )
.await .await