Domain Model
Domain Model
Section titled “Domain Model”The Bartendie domain model outlines the core concepts, entities, and relationships within the home bar organization system. It provides a comprehensive view of the system’s structure using UML class diagrams.
What is a Domain Model?
Section titled “What is a Domain Model?”A domain model is a conceptual model of a system that describes:
- Entities: Objects with identity that persist over time
- Value Objects: Immutable objects defined by their attributes
- Aggregates: Clusters of entities and value objects treated as a unit
- Relationships: How different objects relate to each other
- Methods: Behaviors associated with the objects
Domain Overview
Section titled “Domain Overview”Bartendie is structured around several key domains:
- Event Planning: Creating and managing events, guest lists, and themes
- Menu Management: Designing balanced menus for events
- Recipe Management: Storing and organizing cocktail recipes
- Inventory Management: Tracking bar stocks and generating shopping lists
- Bar Setup: Managing tools, equipment, and glassware for events
The Bartendie Domain Model
Section titled “The Bartendie Domain Model”The diagram below shows the full domain model for the Bartendie system:
classDiagram
%% Event Aggregate
class Event {
<<Aggregate Root>>
+EventId UUID
+Name String
+Date DateTime
+Description String
+ExpectedGuestCount Integer
+Status EventStatus
+ScheduleEvent()
+ChangeDate()
+UpdateGuestCount(count)
+Cancel()
}
class Theme {
<<Value Object>>
+Name String
+ColorScheme String
+Style String
+Description String
+SuggestedIngredients List~String~
}
class GuestList {
+List~Guest~ Guests
+AddGuest()
+RemoveGuest()
+GetPreferences()
+TrackRSVP()
+GenerateAttendanceEstimate()
}
class Guest {
+GuestId UUID
+Name String
+PreferredSpirits List~String~
+DislikedIngredients List~String~
+FavoriteCocktails List~String~
+Allergies List~String~
+RSVPStatus RSVPStatus
+FlavorPreferences List~FlavorProfile~
}
class AttendanceEstimate {
<<Value Object>>
+ConfirmedCount Integer
+EstimatedTotal Integer
+ConfidenceLevel Float
+UpdateEstimate()
+AdjustForNoShows(percentage)
}
%% Venue Aggregate
class Venue {
<<Aggregate Root>>
+VenueId UUID
+Name String
+Address String
+CreateVenue()
+UpdateDetails()
+AddStorage()
+AddBar(bar)
+RemoveBar(barId)
}
class Storage {
+StorageId UUID
+Name String
+Type String
}
class Bar {
+BarId UUID
+Name String
+Description String
+VenueId UUID
+Features List~String~
+CreateBar()
+UpdateBar()
}
%% Menu Aggregate
class Menu {
<<Aggregate Root>>
+MenuId UUID
+Name String
+Description String
+EventId UUID
+IsFinal Boolean
+OverallFlavorProfile FlavorProfile
+CreateMenu()
+AddDrink()
+RemoveDrink()
+FinalizeMenu()
+CalculateIngredientNeeds()
+AnalyzeMenuBalance()
}
class DrinkItem {
+DrinkId UUID
+Name String
+Description String
+Category DrinkCategory
+IsFeatured Boolean
+Image URL
+Feature()
+Unfeature()
+UpdateRecipe()
}
class Recipe {
<<Aggregate Root>>
+RecipeId UUID
+Name String
+Description String
+Author String
+CreationDate DateTime
+Instructions String
+PrepTime TimeSpan
+GlassType GlassType
+IceType IceType
+GarnishInstructions String
+Rating Float
+RecipeBalance RecipeBalance
+RequiredTools List~RecipeTool~
+Tags List~Tag~
+CreateRecipe()
+UpdateRecipe()
+RateRecipe()
+TagRecipe()
}
class RecipeIngredient {
+IngredientId UUID
+Quantity Decimal
+Unit MeasurementUnit
+IsOptional Boolean
+Notes String
+UpdateQuantity()
}
class Ingredient {
<<Aggregate Root>>
+IngredientId UUID
+Name String
+Type IngredientType
+Category String
+FlavorProfile IngredientProfile
+Substitutes List~Ingredient~
+CreateIngredient()
+UpdateIngredient()
+AddSubstitute()
}
class IngredientProfile {
<<Value Object>>
+Sweet Integer
+Sour Integer
+Bitter Integer
+Umami Integer
+Spicy Integer
+Herbal Integer
+Floral Integer
+Fruity Integer
}
class RecipeBalance {
<<Value Object>>
+Sweet Integer
+Sour Integer
+Bitter Integer
+Umami Integer
+Spicy Integer
+Herbal Integer
+Floral Integer
+Fruity Integer
+CalculateBalance()
}
class RecipeTool {
+ToolId UUID
+Name String
+IsRequired Boolean
}
class BatchRecipe {
+BatchRecipeId UUID
+RecipeId UUID
+Servings Integer
+ScalingFactor Decimal
+TotalVolume Decimal
+CalculateScaledQuantities()
}
%% Inventory Aggregate
class Inventory {
<<Aggregate Root>>
+InventoryId UUID
+CheckStock(List~IngredientId~)
+GenerateShoppingList(Menu)
+UpdateStock(List~IngredientQuantity~)
+TrackTools()
+TrackGlassware()
+TrackEquipment()
+ScanProduct(barcode)
+LookupProductData(barcode)
+AlertLowStock()
}
class Product {
<<Aggregate Root>>
+ProductId UUID
+Name String
+Brand String
+Type ProductType
+Category String
+Volume Decimal
+VolumeUnit MeasurementUnit
+AlcoholContent Float
+TrackingMode TrackingMode
+DefaultPrice Decimal
+PriceHistory List~PriceHistoryEntry~
+Barcode ProductBarcode
+ProductData ProductData
+ImageUrl String
+Tags List~Tag~
+CreateProduct()
+UpdateProduct()
+GetTotalQuantity()
+GetAvailableAmount()
+AddToShoppingList()
+ScanBarcode()
+LookupProductData(barcode)
+RecordPrice(price, source, vendor)
}
class TrackingMode {
<<Enumeration>>
LEVEL_TRACKED
QUANTITY_ONLY
}
class ProductInstance {
+InstanceId UUID
+ProductId UUID
+Status InstanceStatus
+CurrentLevel ProductLevel
+StorageLocation String
+OpenedDate DateTime
+ExpirationDate DateTime
+PurchasePrice Decimal
+Notes String
+Open()
+UpdateLevel(amount)
+MarkEmpty()
+MarkDepleted()
}
class InstanceStatus {
<<Enumeration>>
UNOPENED
IN_USE
EMPTY
EXPIRED
}
class QuantityTracking {
+TrackingId UUID
+ProductId UUID
+TotalQuantity Integer
+Unit MeasurementUnit
+StorageLocation String
+LastRestocked DateTime
+MinimumStock Integer
+AddQuantity(amount)
+RemoveQuantity(amount)
+SetQuantity(amount)
+CheckLowStock()
}
class ShoppingList {
<<Aggregate Root>>
+ShoppingListId UUID
+EventId UUID
+MenuId UUID
+Status ShoppingListStatus
+GeneratedDate DateTime
+TotalEstimatedCost Decimal
+Items List~ShoppingListItem~
+GenerateFromMenu()
+AddItem()
+RemoveItem()
+CheckOffItem()
+CalculateTotalCost()
}
class ShoppingListItem {
+ItemId UUID
+IngredientId UUID
+ProductId UUID
+Name String
+Quantity Decimal
+Unit MeasurementUnit
+EstimatedCost Decimal
+IsChecked Boolean
+Category String
+CheckOff()
+UpdateQuantity()
}
class ProductBarcode {
<<Value Object>>
+Code String
+Type BarcodeType
+ScannedDate DateTime
}
class ProductData {
<<Value Object>>
+Name String
+Brand String
+Category String
+Volume String
+Description String
+ImageUrl String
+Ingredients String
+AlcoholPercentage Float
+Manufacturer String
+Country String
+Source ProductSource
}
class PriceHistoryEntry {
<<Value Object>>
+Price Decimal
+Date DateTime
+Source PriceSource
+Vendor String
+Notes String
}
class ProductSource {
<<Enumeration>>
OPENFOODFACTS
UPCITEMDB
BARCODEDLOOKUP
MANUAL
}
class PriceSource {
<<Enumeration>>
PURCHASE
MANUAL
SHOPPING_LIST
IMPORT
}
class ProductLevel {
<<Value Object>>
+CurrentAmount Decimal
+TotalCapacity Decimal
+Percentage Float
+Status LevelStatus
}
%% Bar Setup Aggregate
class BarSetup {
<<Aggregate Root>>
+SetupId UUID
+BarId UUID
+EventId UUID
+Layout String
+RequiredTools List~BarTool~
+RequiredEquipment List~Equipment~
+RequiredGlassware List~Glassware~
+SetupInstructions String
+Tags List~Tag~
+CreateSetup()
+AdjustLayout()
+FinalizeSetup()
+VerifyToolAvailability()
}
class BarTool {
+ToolId UUID
+Name String
+Type ToolType
+Quantity Integer
+Condition String
+IsAvailable Boolean
+AddTool()
+UpdateCondition()
}
class Equipment {
+EquipmentId UUID
+Name String
+Type String
+Quantity Integer
+Condition String
+IsAvailable Boolean
+AddEquipment()
+UpdateCondition()
}
class Glassware {
+GlasswareId UUID
+Type GlassType
+Quantity Integer
+Condition String
+IsAvailable Boolean
+AddGlassware()
+UpdateQuantity()
}
%% Batched Cocktail Aggregate
class BatchedCocktail {
<<Aggregate Root>>
+BatchId UUID
+EventId UUID
+RecipeId UUID
+BatchRecipe BatchRecipe
+Servings Integer
+PreparedDate DateTime
+ExpirationDate DateTime
+StorageLocation String
+Status BatchStatus
+CreateBatch()
+MarkAsServed()
+UpdateServings()
}
class BatchIngredient {
<<Value Object>>
+IngredientId UUID
+ScaledQuantity Decimal
+Unit MeasurementUnit
+CalculateScaled()
}
%% Flavor Profile System
class FlavorProfile {
+ProfileId UUID
+Name String
+Description String
+Characteristics List~FlavorCharacteristic~
+DefineProfile()
+UpdateProfile()
}
class FlavorCharacteristic {
<<Value Object>>
+Name String
+Intensity Integer
+Category String
}
%% Tagging System
class Taggable {
<<Interface>>
+ItemId UUID
+Tags List~Tag~
+AddTag(tag)
+RemoveTag(tag)
+GetTagsByType(type)
}
class Tag {
+TagId UUID
+Name String
+Type TagType
+Color String
+CreateTag()
}
%% Relationships
Event "1" *-- "1" Theme
Event "1" *-- "1" GuestList
Event "1" *-- "1" AttendanceEstimate
GuestList "1" *-- "*" Guest
Event "1" *-- "1" Venue
Event "1" *-- "1..*" Menu
Event "1" *-- "0..1" ShoppingList
Menu "1" *-- "*" DrinkItem
DrinkItem "1" *-- "1" Recipe
Recipe "1" *-- "*" RecipeIngredient
RecipeIngredient "*" -- "1" Ingredient
Recipe "1" -- "1" RecipeBalance
Recipe "*" -- "*" RecipeTool
Ingredient "1" -- "1" IngredientProfile
Ingredient "*" -- "*" Product
Event "1" *-- "1" BarSetup
Event "1" *-- "*" BatchedCocktail
BatchedCocktail "1" *-- "1" BatchRecipe
BatchedCocktail "1" *-- "*" BatchIngredient
BatchRecipe "1" -- "1" Recipe
Menu "1" -- "1" FlavorProfile
FlavorProfile "1" *-- "*" FlavorCharacteristic
Venue "1" *-- "*" Storage
Venue "1" *-- "*" Bar
BarSetup "1" -- "1" Bar
BarSetup "*" -- "*" BarTool
BarSetup "*" -- "*" Equipment
BarSetup "*" -- "*" Glassware
ShoppingList "1" *-- "*" ShoppingListItem
ShoppingListItem "*" -- "0..1" Ingredient
ShoppingListItem "*" -- "0..1" Product
Product "1" -- "1" ProductBarcode
Product "1" -- "1" ProductData
Product "1" -- "1" TrackingMode
Product "1" -- "*" ProductInstance : level-tracked >
Product "1" -- "0..1" QuantityTracking : quantity-only >
ProductInstance "1" -- "1" InstanceStatus
ProductInstance "1" -- "1" ProductLevel
Recipe --|> Taggable
Product --|> Taggable
Event --|> Taggable
BarSetup --|> Taggable
Taggable "*" -- "*" Tag
%% User Management Aggregate
class User {
<<Aggregate Root>>
+UserId UUID
+Username String
+Email String
+PasswordHash String
+Profile UserProfile
+Roles List~Role~
+IsActive Boolean
+CreatedAt DateTime
+LastLoginAt DateTime
+CreateUser()
+UpdateProfile()
+ChangePassword()
+AssignRole()
+Activate()
+Deactivate()
}
class UserProfile {
<<Value Object>>
+FirstName String
+LastName String
+DisplayName String
+Avatar String
+Preferences UserPreferences
+UpdateProfile()
}
class Role {
+RoleId UUID
+Name String
+Description String
+Permissions List~Permission~
+CreateRole()
+UpdateRole()
+AddPermission()
+RemovePermission()
}
class Permission {
<<Value Object>>
+Name String
+Resource String
+Action String
+Description String
}
%% Notification Aggregate
class Notification {
<<Aggregate Root>>
+NotificationId UUID
+UserId UUID
+Type NotificationType
+Title String
+Message String
+IsRead Boolean
+CreatedAt DateTime
+ReadAt DateTime
+ExpiresAt DateTime
+CreateNotification()
+MarkAsRead()
+Archive()
}
%% Audit Aggregate
class AuditLog {
<<Aggregate Root>>
+LogId UUID
+UserId UUID
+EntityType String
+EntityId UUID
+Action String
+OldValues String
+NewValues String
+Timestamp DateTime
+IPAddress String
+UserAgent String
+LogAction()
+GetHistory()
}
%% Additional Relationships
User "1" *-- "1" UserProfile
User "*" -- "*" Role
Role "1" *-- "*" Permission
User "1" -- "*" Notification
User "1" -- "*" AuditLog
Core Aggregates
Section titled “Core Aggregates”The Bartendie system is organized around several key aggregates:
Event Aggregate
Section titled “Event Aggregate”The Event Aggregate represents a planned cocktail event, including:
- Event: The main entity with date, name, and description
- Theme: Value object defining the event’s stylistic concept
- GuestList: Collection of guests with preferences and RSVP status
- AttendanceEstimate: Projection of expected attendance
Events are the central organizing concept in Bartendie, providing context for menus, guest preferences, and bar setup.
Venue Aggregate
Section titled “Venue Aggregate”The Venue Aggregate represents physical locations where events take place.
- Venue: The root entity for a physical location, including its address and available facilities. The venue manages multiple bars and storage areas within its boundaries.
- Storage: A designated area within a venue for storing inventory (e.g., dry storage, cold storage).
- Bar: A specific bar area within a venue that can be set up for an event. Each bar has a unique identity, name, description, and features that define its capabilities.
Bar Entity Details
Section titled “Bar Entity Details”The Bar entity represents a physical bar location within a venue and includes:
Attributes:
- BarId: Unique identifier for the bar
- Name: Descriptive name (e.g., “Main Bar”, “Kitchen Counter Bar”)
- Description: Optional detailed description of the bar’s characteristics
- VenueId: Reference to the parent venue
- Features: List of bar capabilities (e.g., “Full Service”, “Wine Bar”, “Coffee Station”)
Behaviors:
- CreateBar(): Initialize a new bar within the venue
- UpdateBar(): Modify bar details and features
Relationship to Venue: Bars exist within the composition boundary of a Venue. A venue can contain multiple bars, but each bar belongs to exactly one venue. The venue is responsible for managing the lifecycle of its bars through the AddBar() and RemoveBar() methods.
Venues provide the physical context for events and contain the spaces used for storage and service.
Menu Aggregate
Section titled “Menu Aggregate”The Menu Aggregate represents a curated collection of drinks for an event:
- Menu: The main entity containing drink items
- DrinkItem: Individual cocktail offerings on a menu
- FlavorProfile: The overall flavor balance of the menu
Menus are linked to events and contain references to recipes that will be served.
Recipe Aggregate
Section titled “Recipe Aggregate”The Recipe Aggregate defines how to prepare specific cocktails:
- Recipe: The main entity with ingredients, instructions, and preparation details
- RecipeIngredient: Specific ingredient with quantity and unit measurements, linking recipes to ingredients
- Ingredient: Abstract ingredient concept (e.g., “vodka”) that can map to multiple products
- IngredientProfile: Flavor characteristics of an ingredient (sweet, sour, bitter, etc.)
- RecipeBalance: Analysis of flavor components calculated from ingredient profiles
- RecipeTool: Mapping between recipes and required bar tools
- BatchRecipe: Scaled version of a recipe for multiple servings with adjusted quantities
Recipes are the foundation of drink preparation and are referenced by menu items. The ingredient abstraction allows recipes to specify generic ingredients (e.g., “bourbon”) while the inventory tracks specific products (e.g., “Maker’s Mark Bourbon”).
Inventory Aggregate
Section titled “Inventory Aggregate”The Inventory Aggregate tracks all available bar ingredients and tools using two distinct inventory tracking patterns:
- Inventory: The main entity managing all available items
- Product: Product type/definition with brand, type, and tracking mode (not a specific bottle)
- TrackingMode: Enumeration defining how a product is tracked (LEVEL_TRACKED or QUANTITY_ONLY)
- ProductInstance: Individual bottle/container for level-tracked products (e.g., “Maker’s Mark bottle #1 at 45% full”)
- InstanceStatus: Status of a product instance (UNOPENED, IN_USE, EMPTY, EXPIRED)
- QuantityTracking: Simple count-based tracking for quantity-only products (e.g., “24 bottles of Topo Chico”)
- ProductBarcode: Value object containing barcode information for product lookup
- ProductData: Value object with product information from external databases
- ProductLevel: Value object tracking current fill level and status of individual instances
- Ingredient: Component used in recipes, mapped to products
- ShoppingList: Needed items based on planned menus and current inventory
- ShoppingListItem: Individual item on a shopping list with quantity, cost, and check-off status
Inventory Tracking Patterns
Section titled “Inventory Tracking Patterns”The inventory system supports two distinct tracking patterns based on product characteristics:
Level-Tracked Products (TrackingMode.LEVEL_TRACKED):
- Used for premium spirits, liqueurs, and expensive bottles where individual bottle tracking is valuable
- Each physical bottle is represented by a ProductInstance entity
- Tracks individual bottle lifecycle: UNOPENED → IN_USE → EMPTY
- Maintains precise fill levels for each bottle (e.g., “bottle #1 is 45% full, bottle #2 is unopened”)
- Enables tracking which specific bottle was used when and where it’s stored
- Total available amount is calculated by summing all non-empty instance volumes
Quantity-Only Products (TrackingMode.QUANTITY_ONLY):
- Used for mixers, canned beverages, and consumables where items are fungible
- Single QuantityTracking entity per product maintains a simple count
- No individual item identity or level tracking needed
- Efficient for high-volume, low-value items
- Simple increment/decrement operations for stock updates
The inventory system allows tracking of stock levels and generation of shopping lists based on planned menus. Products can be scanned via barcode to auto-populate product data from external databases. Multiple products can map to a single ingredient (e.g., different bourbon brands all map to “bourbon” ingredient).
Barcode Scanning and Product Data Lookup
Section titled “Barcode Scanning and Product Data Lookup”The system supports barcode scanning for automatic product identification and data population:
Barcode Scanning Workflow:
- User scans product barcode using mobile device or barcode scanner
- System extracts barcode code and type (UPC, EAN, QR, CODE128)
- System attempts product data lookup from multiple external sources:
- OpenFoodFacts: Open database of food products
- UPCitemdb: UPC product database
- BarcodeLookup: Commercial barcode lookup service
- If product data is found, ProductData value object is populated with:
- Product name, brand, category
- Volume information
- Description and ingredients
- Image URL
- Alcohol percentage (if applicable)
- Manufacturer and country information
- ProductBarcode value object stores the scanned barcode with timestamp
- User can review and edit auto-populated data before creating product
- If no data is found, user manually enters product information
Price History Tracking:
Products maintain a price history to track cost changes over time:
- Each PriceHistoryEntry records price, date, source (purchase, manual, shopping list, import), vendor, and optional notes
- Default price is typically the most recent purchase price
- Price history enables cost analysis and budget planning for events
- Historical price data helps identify trends and optimize purchasing decisions
For detailed information about the inventory tracking patterns, see Inventory Tracking Patterns.
Bar Setup Aggregate
Section titled “Bar Setup Aggregate”The Bar Setup Aggregate defines the physical arrangement and tools needed for an event:
- BarSetup: The main entity defining layout and required items for a specific event
- BarTool: Specific implement for drink preparation (shaker, jigger, strainer, etc.) with quantity and availability tracking
- Equipment: Larger items required for bar operation (ice maker, blender, etc.) with condition tracking
- Glassware: Specific vessels for serving drinks (coupe, rocks, highball, etc.) with quantity tracking
Bar setup ensures that all necessary tools and equipment are available for an event. The system can verify tool availability against inventory and generate a checklist of required items based on the event’s menu.
Batched Cocktail Aggregate
Section titled “Batched Cocktail Aggregate”The Batched Cocktail Aggregate manages pre-made cocktails for events:
- BatchedCocktail: The main entity representing prepared batches with servings, preparation date, and storage location
- BatchRecipe: Modified recipe for large-scale preparation with scaling factor and total volume calculations
- BatchIngredient: Scaled ingredient quantities for batch preparation based on the number of servings
Batched cocktails help in efficient service during events by allowing preparation in advance. The system automatically scales ingredient quantities based on the desired number of servings and tracks batch status (prepared, serving, depleted). This is essential for events with 20+ guests where individual cocktail preparation would be impractical.
User Management Aggregate
Section titled “User Management Aggregate”The User Management Aggregate handles authentication, authorization, and user profiles:
- User: The main entity representing a system user with authentication credentials and profile information
- UserProfile: Value object containing personal information and preferences
- Role: Entity defining user roles with associated permissions
- Permission: Value object defining specific access rights to resources and actions
This aggregate ensures secure access to the system and proper authorization for different user types (hosts, bartenders, administrators).
Notification Aggregate
Section titled “Notification Aggregate”The Notification Aggregate manages system communications and alerts:
- Notification: The main entity representing messages, alerts, and reminders sent to users
This aggregate handles various types of notifications including inventory alerts, event reminders, and system messages.
Audit Aggregate
Section titled “Audit Aggregate”The Audit Aggregate provides comprehensive tracking and history:
- AuditLog: The main entity recording all system operations, changes, and user actions
This aggregate ensures accountability, compliance, and provides detailed history for troubleshooting and analysis.
Cross-Cutting Concepts
Section titled “Cross-Cutting Concepts”Flavor Profile System
Section titled “Flavor Profile System”The Flavor Profile System analyzes and categorizes flavors across the system:
- FlavorProfile: Collection of taste characteristics used to describe menus and overall flavor balance
- FlavorCharacteristic: Specific taste attribute with name, intensity (0-10), and category
- IngredientProfile: Flavor properties of specific ingredients, defining their taste characteristics on a 0-10 scale for: sweet, sour, bitter, umami, spicy, herbal, floral, and fruity
- RecipeBalance: Analysis of a recipe’s flavor components, calculated by aggregating ingredient profiles using the same eight characteristics
Flavor Characteristics (0-10 scale):
- Sweet: Sugar content and perceived sweetness
- Sour: Acidity and tartness
- Bitter: Bitterness from herbs, coffee, or alcohol
- Umami: Savory, meaty flavors
- Spicy: Heat and spice intensity
- Herbal: Botanical and herbal notes
- Floral: Floral and perfumed aromas
- Fruity: Fruit flavors and esters
This system helps in creating balanced menus and matching drinks to guest preferences. The system can:
- Calculate overall menu balance by analyzing all drinks across all eight flavor dimensions
- Identify gaps in flavor profiles (e.g., “menu is too sweet, needs more bitter drinks”)
- Match recipes to guest flavor preferences
- Suggest complementary drinks for menu variety
- Calculate recipe balance by aggregating ingredient profiles with weighted quantities
Tagging System
Section titled “Tagging System”The Tagging System provides organization and categorization:
- Taggable: Interface for entities that can be tagged (implemented by Recipe, Product, Event, BarSetup)
- Tag: Label applied to various entities for organization with name, type, and color
Many entities implement the Taggable interface, allowing for flexible categorization and search. Tag types include:
- Occasion: party, wedding, holiday, casual
- Season: summer, winter, spring, fall
- Flavor: citrus, tropical, herbal, spicy
- Technique: shaken, stirred, built, blended
- Difficulty: easy, intermediate, advanced
Value Objects
Section titled “Value Objects”The model uses several value objects to represent immutable concepts:
- Theme: Defines the stylistic concept for an event with name, color scheme, style, and suggested ingredients
- AttendanceEstimate: Projection of expected attendance with confirmed count, estimated total, and confidence level
- UserProfile: User personal information with first name, last name, display name, avatar, and preferences
- Permission: Access rights with resource, action, and description
- RecipeBalance: Analysis of a recipe’s flavor components (sweet, sour, bitter, umami, spicy, herbal, floral, fruity)
- IngredientProfile: Flavor characteristics of an ingredient (sweet, sour, bitter, umami, spicy, herbal, floral, fruity) on a 0-10 scale
- ProductBarcode: Identification code for a product with code, barcode type, and scanned date timestamp
- ProductData: Descriptive information about a product from external databases (name, brand, category, volume, description, image URL, ingredients, alcohol percentage, manufacturer, country, source)
- ProductLevel: Current amount and status of a product with percentage and level status
- PriceHistoryEntry: Historical price record with price, date, source, vendor, and notes
- BatchIngredient: Scaled ingredient for batch preparation with calculated quantities
- FlavorCharacteristic: Specific taste attribute with name, intensity (0-10), and category
Enumerations
Section titled “Enumerations”The model includes several enumerations to represent fixed sets of values:
- EventStatus: Status of an event (planned, in_progress, completed, cancelled)
- RSVPStatus: Status of a guest’s RSVP (invited, confirmed, declined, maybe, no_response)
- DrinkCategory: Category of a drink (signature, classic, mocktail, punch, shot, etc.)
- IngredientType: Type of ingredient (spirit, mixer, modifier, sweetener, garnish, bitters, other)
- ProductType: Type of product (spirit, wine, beer, mixer, garnish, tool, equipment, glassware, other)
- TrackingMode: Inventory tracking mode for products (LEVEL_TRACKED for individual bottle tracking, QUANTITY_ONLY for simple count-based tracking)
- InstanceStatus: Status of a product instance (UNOPENED, IN_USE, EMPTY, EXPIRED)
- MeasurementUnit: Unit of measurement (oz, ml, cl, l, dash, tsp, tbsp, cup, count, etc.)
- GlassType: Type of glass (coupe, rocks, highball, collins, flute, martini, wine, shot, etc.)
- ToolType: Type of bar tool (shaker, strainer, jigger, spoon, muddler, peeler, knife, etc.)
- IceType: Type of ice (cube, sphere, crushed, cracked, block, none, etc.)
- ShoppingListStatus: Status of a shopping list (draft, final, in_progress, completed)
- TagType: Type of tag (occasion, season, flavor, technique, difficulty, style, etc.)
- NotificationType: Type of notification (info, warning, error, success, reminder, alert, system)
- BatchStatus: Status of a batched cocktail (preparing, ready, serving, depleted)
- LevelStatus: Status of product level (full, high, medium, low, empty)
- BarcodeType: Type of barcode (UPC, EAN, QR, CODE128)
- ProductSource: Source of product data (OPENFOODFACTS, UPCITEMDB, BARCODEDLOOKUP, MANUAL)
- PriceSource: Source of price data (PURCHASE, MANUAL, SHOPPING_LIST, IMPORT)
External Systems
Section titled “External Systems”The model interacts with several external systems:
- OpenFoodFacts: Open database of food products providing product information via barcode lookup
- UPCitemdb: UPC product database for product data retrieval
- BarcodeLookup: Commercial barcode lookup service for comprehensive product information
- BarcodeScanner: External system (mobile device or hardware scanner) for scanning product barcodes
These external systems are used during the barcode scanning workflow to automatically populate ProductData when a product is scanned. The system attempts lookup from multiple sources in order of preference, falling back to manual entry if no data is found.
Domain Model Implementation
Section titled “Domain Model Implementation”The domain model provides a blueprint for implementation using domain-driven design principles:
- Entities will be implemented as classes with identity and persistence
- Value Objects will be implemented as immutable classes
- Aggregates will enforce consistency boundaries and rules
- Repositories will provide data access for aggregates
- Services will implement operations that don’t naturally belong to entities
Implementation Guidelines
Section titled “Implementation Guidelines”Aggregate Boundaries:
- Each aggregate root controls access to its internal entities
- External references use IDs, not direct object references
- Transactions should not span multiple aggregates
Value Object Immutability:
- All value objects are immutable after creation
- Changes create new instances rather than modifying existing ones
- Equality is based on attribute values, not identity
Repository Patterns:
- One repository per aggregate root
- Repositories return fully-formed aggregates
- Queries should be optimized for common access patterns
Domain Services:
- Used for operations that don’t naturally fit within an entity
- Examples: ShoppingListGenerator, MenuBalancer, BatchRecipeScaler
- Services coordinate between multiple aggregates
This comprehensive domain model serves as the foundation for the Bartendie system, ensuring that the software accurately reflects the needs and workflows of home bartenders planning and executing cocktail events.
Related Documentation
Section titled “Related Documentation”- Inventory Tracking Patterns: Detailed analysis of level-tracked vs quantity-only inventory patterns
- Context Map: See how these aggregates relate to bounded contexts
- Event Storming: Understand the dynamic behavior of these entities
- Command Flow: See how commands flow through these aggregates
- Business Rules: Review the constraints and validation rules for these entities
- Error Handling: Understand error patterns for domain operations
Ubiquitous Language
Section titled “Ubiquitous Language”For a comprehensive glossary of terms used throughout the Bartendie system, refer to the Glossary document.