Packages
Packages & Associated Models
Introduction
On CaterCow, a Package represents a curated, pre-portioned selection from a restaurant's menu, designed to simplify the ordering process for any group size. Instead of a customer calculating how many trays of food are needed, a Package encodes the correct ratios of entrees, sides, and other items for a given headcount. For how packages relate to menu items, see Menus.
When a user views a Package, it comes with pre-selected defaults, creating a complete meal that can be ordered without any changes. However, users retain the flexibility to customize their order by selecting different options. This system streamlines the corporate catering experience, ensuring a well-balanced and sufficient meal for any event.
The data models supporting this functionality are interconnected, with the Package model at the center. This document outlines the key models and their relationships, referencing the database schema and a sample API response (example-package.json).
Entity-Relationship Diagram (ERD)
Core Models
Package
The Package is the central model. It defines a specific catering offering from a Brand.

Key packages table columns:
| Column | Type | Description |
|---|---|---|
id | int | Unique identifier for the package. |
brand_id | bigint | A foreign key linking to the brands table, representing the restaurant providing the package. |
name | varchar | The customer-facing name of the package (e.g., "DIY Asian-Inspired Som Buffet"). |
summary | text | A brief, enticing description of the package used in search results and headers. |
price | decimal | The base price per person for the package. |
min_qty / max_qty | int | The minimum and maximum number of people (headcount) the package can be ordered for. |
increment_by | tinyint | Enforces that the order headcount must be a multiple of this number. For example, if a bakery only offers bagels in dozens, the headcount for an order must be divisible by 12. |
submission_lead_time_hours | int | The number of hours before the event that an order must be placed. This stacks with kitchen-specific lead times. |
package_type | int | An enum for the high-level meal type (e.g., Breakfast, Lunch/Dinner). See Enums section. |
package_category | int | An enum for the specific cuisine category (e.g., lunch_asian_fusion, dessert_baked_goods). See Enums section. |
presentation_type | int | An enum indicating how the food is served (buffet, individual, mixed). See Enums section. |
set_up_type | int | An enum describing the level of setup provided (Drop Off, Basic Setup, Staff On-site). |
choices_enabled | boolean | A flag that indicates if the modern PackageItem choice structure is used. |
menu_item_id | bigint | A foreign key to a menu_items record, used when a package represents a single, non-customizable menu item. |
PackageItem
A PackageItem is a single deliverable component within a Package. This can be an edible item (like an entree or a side), an inedible item (like sternos or plates), or even a service (like a server). If a PackageItem has selectable PackageItemOption records, it functions as a "Choice Group" (e.g., "Choose your Proteins").

Key package_items table columns:
| Column | Type | Description |
|---|---|---|
id | int | Unique identifier. |
package_id | int | Foreign key linking to the packages table. |
name | varchar | The name of the choice group or item (e.g., "Your choice of Proteins"). |
description | text | Further context for the item or choice. |
choice_type | int | An enum determining the rules for selection. Key values include: constant_sum (e.g., choose 2 of 5 options for a set price), inclusion (a-la-carte style), and presentation (choose between buffet/individual). |
minimum_choosable_options | int | The minimum number of options a customer must select from this group. |
maximum_choosable_options | int | The maximum number of options a customer can select. |
extra_vegetarian_choices | int | Allows customers to select additional vegetarian options without counting against maximum_choosable_options, ensuring dietary needs are met. |
extra_choice_interval | int | For every X the headcount is above the packages min_qty, the customer is granted another option. This is so small orders don't have too many choices, but large orders can choose from more entrees/sides as needed. |
increment_by | int | Similar to the package-level rule, but applies to the quantity of items within this specific group. |
menu_item_id | bigint | Foreign key to menu_items. This links a package component back to its source item on the full restaurant menu. See Menu Synchronization. |
modifier_group_id | bigint | Foreign key to modifier_groups. Used when the item's options are derived from a modifier group on the full menu. See Menu Synchronization. |
PackageItemOption
A PackageItemOption is one of the specific, selectable choices within a PackageItem group. For example, "Grilled Lemongrass Chicken" is an option within the "Proteins" item group.

Key package_item_options table columns:
| Column | Type | Description |
|---|---|---|
id | int | Unique identifier. |
package_item_id | int | Foreign key linking to the parent package_items record. |
name | varchar | The name of the option (e.g., "Grilled Steak"). |
description | text | A description of the specific option. |
default | boolean | A flag indicating if this option is pre-selected when a user views the package. |
price_premium | decimal | An additional cost added to the base per-person price if this option is selected (e.g., $1.50 extra for Salmon). |
vegan / vegetarian / gluten_free / contains_nuts | boolean | Flags for dietary information. |
menu_item_id | bigint | Foreign key linking this specific option to its corresponding menu_items record. See Menu Synchronization. |
PackageNote
This model stores important contextual information about a Package that can be shared with either the customer, the restaurant, or both.
Key package_notes table columns:
| Column | Type | Description |
|---|---|---|
id | int | Unique identifier. |
package_id | int | Foreign key linking to the packages table. |
content | text | The text of the note. |
recipient_type | int | An enum that controls the visibility of the note (e.g., for caterers, for customers). |
Supporting Models & Concepts
Enums
The system uses a set of predefined enumerations (enums) to categorize packages, which are crucial for search, filtering, and organization. The primary enums include:
- Package Types: High-level categories like
breakfast,lunch_or_dinner, anddessert. - Package Categories: More specific cuisine-based categories like
lunch_mexicananddessert_baked_goods. Each category belongs to a type. - Presentation Types: Defines how the package is served:
individual: Individually wrapped portions.buffet: Served family-style in trays.mixed: The customer can choose between individual and buffet styles.
PackageTemplate
A PackageTemplate is a blueprint for creating new packages, representing the most granular level of classification (e.g., "Build Your Own Taco Bar"). Templates contain predefined choices and groups, which significantly speeds up the process of adding new, similarly-structured packages to the platform.
Menu Synchronization
Packages are synced with a restaurant's canonical MenuItem records. This ensures that package details like pricing, descriptions, and dietary information stay up-to-date.
MenuItem: The source of truth for any single item a restaurant offers. It contains the core details, including dietary flags and price.- Extrapolation Logic: The system has internal logic that transforms attributes from a
MenuIteminto attributes for aPackageItemorPackageItemOption. For example, theprice_premiumon aPackageItemOptionis calculated by comparing the option'sMenuItemprice to the base price of its choice group. This allows the system to automatically calculate upcharges.
Images (Photo)
High-quality images are crucial for marketing. The photos table stores images for various models, linked via a polymorphic association (imageable_type and imageable_id).
- For a
Package,imageable_typewould be 'Package' andimageable_idwould be thepackages.id. - As seen in the
example-package.jsonfile, image URLs are provided in various sizes and formats.
Collections
The collections model groups packages for specific holidays, seasons, or themes (e.g., "St. Patrick's Day Specials"). This is a many-to-many relationship managed through the collections_packages join table, allowing a package to appear in multiple collections. This is a powerful marketing tool for events and corporate celebrations.
Pricing & Headcount
Packages are designed around a simple, per-headcount pricing model.
- Base Price: The
packages.priceis the starting price per person. - Premiums: Selecting certain
PackageItemOptions can increase the per-person price via theprice_premiumfield. - All-In Pricing: For clients who need to filter by a total budget, the system can estimate the final price, including the food subtotal (price x headcount), fees, and delivery, to provide an "all-in" view during the discovery phase.