Add My Bar, Bartender, Recommend features + drink images

- Drink Images: upload/display photos of bottles/cans on drink cards and detail pages
- My Bar: inventory tracker for spirits, liqueurs, mixers, bitters, garnishes, tools
- Bartender: AI-powered cocktail recipe generation, "what can I make" suggestions,
  saved recipes. Cross-references bar inventory for ingredient availability.
- Recommend: AI flavor profile analysis, personalized drink recommendations,
  "find similar" drinks based on highly-rated favorites
- Navigation: desktop sidebar with all 8 routes, mobile bottom nav with
  4 primary items + "More" popup menu
- New Prisma models: BarItem, Recipe, FlavorProfile
- Backup/restore updated to include bar items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
JP Scott
2026-03-01 18:28:02 -07:00
parent d8f069cce4
commit 2ac2c4b2d4
40 changed files with 3709 additions and 11 deletions

View File

@@ -28,6 +28,9 @@ model User {
preferences UserPreference?
wishlistItems WishlistItem[]
sharedLists SharedList[]
barItems BarItem[]
recipes Recipe[]
flavorProfile FlavorProfile?
}
model Account {
@@ -123,6 +126,7 @@ model Drink {
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
ratings Rating[]
menuItems MenuItem[]
recipes Recipe[]
@@index([userId])
@@index([userId, type])
@@ -249,3 +253,72 @@ model SharedList {
@@index([userId])
@@index([slug])
}
// ─── Bar Inventory ──────────────────────────────────────────────
enum BarItemCategory {
SPIRITS
LIQUEURS
MIXERS
BITTERS
GARNISHES
TOOLS
}
enum BarItemQuantity {
FULL
HALF
LOW
EMPTY
}
model BarItem {
id String @id @default(cuid())
userId String
name String
category BarItemCategory
quantity BarItemQuantity @default(FULL)
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([userId, category])
}
// ─── Recipes ────────────────────────────────────────────────────
model Recipe {
id String @id @default(cuid())
userId String
title String
ingredients Json // [{ name: string, amount: string, available: boolean }]
steps Json // string[]
garnish String?
glassware String?
sourceDrinkId String?
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
sourceDrink Drink? @relation(fields: [sourceDrinkId], references: [id], onDelete: SetNull)
@@index([userId])
}
// ─── Flavor Profile ─────────────────────────────────────────────
model FlavorProfile {
id String @id @default(cuid())
userId String @unique
profileText String @db.Text
profileData Json?
generatedAt DateTime @default(now())
ratingCount Int @default(0)
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}