Skip to content

Product Entity Relationships

Complete reference for how product entities relate to each other in the database.

erDiagram
    Market {
        int id PK
        string code "ES, DE, FR"
        string name
        json supported_locales
        json country_codes
        json currency_codes
    }

    TcaiProfile {
        int id PK
        string name
        string description "nullable"
        text custom_instructions
        boolean is_default
    }

    ProductTemplate {
        int id PK
        int tcai_profile_id FK "nullable"
        string title
        string sku
        string source_locale
        json itinerary
        int duration
        json highlights
        json categories
    }

    ProductByMarket {
        int id PK
        int product_template_id FK
        int market_id FK
        string locale
        string sku
        string status
        date search_start_date
        date search_end_date
        json excluded_dates
    }

    ProductComponent {
        int id PK
        int product_template_id FK
        string component_name
        string component_type
        int sequence_order
        string inventory_type
        int inventory_id
    }

    ProductByMarketTranslation {
        int id PK
        int product_by_market_id FK
        string locale
        string title
        string url_slug
        json itinerary
    }

    ProductByMarketFlightConfig {
        int id PK
        int product_by_market_id FK
        int airport_id FK
        string type
        boolean is_active
    }

    ProductByMarketFlightLeg {
        int id PK
        int flight_config_id FK
        int leg_index
        int day_offset
        string flight_type
        int origin_airport_id FK
        int destination_airport_id FK
    }

    CmsRegion {
        int id PK
        string slug
        string image "nullable"
        int sort_order
        boolean status
    }

    CmsRegionTranslation {
        int id PK
        int cms_region_id FK
        string locale
        string name
        string description "nullable"
    }

    CmsCountry {
        int id PK
        int cms_region_id FK
        string slug
        string image "nullable"
        int sort_order
        boolean status
    }

    CmsCountryTranslation {
        int id PK
        int cms_country_id FK
        string locale
        string name
        string description "nullable"
    }

    AgentConversation {
        string id PK "UUID 36"
        int user_id FK
        string title
    }

    AgentConversationMessage {
        string id PK "UUID 36"
        string conversation_id FK
        int user_id FK
        string agent
        string role
        text content
    }

    TcaiProfile ||--o{ ProductTemplate : "has"
    Market ||--o{ ProductByMarket : "has"
    ProductTemplate ||--o{ ProductByMarket : "has"
    ProductTemplate ||--o{ ProductComponent : "has"
    ProductByMarket ||--o{ ProductByMarketTranslation : "has"
    ProductByMarket ||--o{ ProductByMarketFlightConfig : "has"
    ProductByMarketFlightConfig ||--o{ ProductByMarketFlightLeg : "has"
    CmsRegion ||--o{ CmsRegionTranslation : "has"
    CmsRegion ||--o{ CmsCountry : "has"
    CmsCountry ||--o{ CmsCountryTranslation : "has"
    CmsCountry }o--o{ ProductByMarket : "cms_country_product_by_market"
    AgentConversation ||--o{ AgentConversationMessage : "has"
ParentChildCardinalityForeign Key
TcaiProfileProductTemplate1:Ntcai_profile_id (nullable, nullOnDelete)
ProductTemplateProductByMarket1:Nproduct_template_id
ProductTemplateProductComponent1:Nproduct_template_id
MarketProductByMarket1:Nmarket_id
ProductByMarketProductByMarketTranslation1:Nproduct_by_market_id
ProductByMarketProductByMarketFlightConfig1:Nproduct_by_market_id
ProductByMarketFlightConfigProductByMarketFlightLeg1:Nflight_config_id
AirportProductByMarketFlightConfig1:Nairport_id
AirportProductByMarketFlightLeg1:Norigin_airport_id, destination_airport_id
CmsRegionCmsRegionTranslation1:Ncms_region_id
CmsRegionCmsCountry1:Ncms_region_id
CmsCountryCmsCountryTranslation1:Ncms_country_id
CmsCountryProductByMarketM:Ncms_country_product_by_market pivot
AgentConversationAgentConversationMessage1:Nconversation_id

Master definition of a travel package. Defines what a trip IS.

  • Stores base content in source locale
  • Contains itinerary (cities, nights)
  • Auto-calculates duration
  • Has no airport/flight data

Market-specific configuration for selling a template.

  • Links template to a specific market + locale
  • Configures flight search date ranges
  • Unique per template + market + locale combination

Localized content for display.

  • One per ProductByMarket (primary locale)
  • Contains translated titles, descriptions, itinerary
  • Holds SEO metadata (url_slug, meta_*)

Departure airport configuration.

  • One per departure airport per ProductByMarket
  • Defines flight search type (multi_city, separate)
  • Contains all flight legs for that departure

Individual flight segments.

  • Ordered by leg_index
  • Stores origin/destination airports
  • Tracks day_offset from trip start
  • Classifies as international, domestic, or arnk

Components that make up a product template.

  • Links to inventory items (transfers, hotels)
  • Defines sequence and day placement
  • Supports mandatory/optional components

AI content generation profile for product templates (TCAI = Trip Content AI).

  • Stores custom instructions that guide AI when generating/refining product content
  • One profile can be shared across many templates
  • Exactly one profile may be marked is_default
  • Deleting a profile nullifies tcai_profile_id on linked templates (nullOnDelete)

CMS content hierarchy for the public-facing destination pages.

  • Regions group countries (e.g. “Europe” contains “Italy”, “Spain”)
  • Both use a translations table for multi-locale support (name, description)
  • Countries link to ProductByMarket via a pivot table with sort_order
  • status boolean controls visibility on the frontend
  • slug used for URL routing on the Astro frontend

AgentConversation / AgentConversationMessage

Section titled “AgentConversation / AgentConversationMessage”

Laravel AI package tables storing admin-panel AI chat history.

  • String UUIDs (36 chars) as primary keys
  • Messages store agent name, role, content, plus serialized tool_calls, tool_results, usage, and meta
  • Indexed on (user_id, updated_at) and (conversation_id, user_id, updated_at)
TableColumnsPurpose
products_by_marketproduct_template_id, market_id, localeOne product per template/market/locale
products_by_marketskuUnique market SKU
product_by_market_flight_configsproduct_by_market_id, airport_idOne config per departure airport
product_by_market_translationsproduct_by_market_id, localeOne translation per locale
product_by_market_translationslocale, url_slugUnique URL slugs per locale

All child entities cascade delete from their parents:

flowchart TD
    TP[TcaiProfile deleted] --> TPNULL["ProductTemplate.tcai_profile_id → NULL"]
    PT[ProductTemplate deleted] --> PBM[All ProductByMarket deleted]
    PBM --> PBMT[All ProductByMarketTranslation deleted]
    PBM --> PBMFC[All ProductByMarketFlightConfig deleted]
    PBMFC --> PBMFL[All ProductByMarketFlightLeg deleted]
    CR[CmsRegion deleted] --> CRT[All CmsRegionTranslation deleted]
    CR --> CC[All CmsCountry deleted]
    CC --> CCT[All CmsCountryTranslation deleted]
    CC --> CCPBM[Pivot rows in cms_country_product_by_market deleted]
ProductByMarket::with([
'productTemplate',
'market',
'translation',
'flightConfigs.legs',
'flightConfigs.airport',
])->find($id);
ProductByMarket::query()
->where('market_id', $marketId)
->where('status', 'active')
->with(['productTemplate', 'translation'])
->get();
$product->flightConfigs()
->active()
->with('airport')
->get()
->pluck('airport');
ModelLocation
TcaiProfilebackend/app/Models/TcaiProfile.php
ProductTemplatebackend/app/Models/ProductTemplate.php
ProductByMarketbackend/app/Models/ProductByMarket.php
ProductByMarketTranslationbackend/app/Models/ProductByMarketTranslation.php
ProductByMarketFlightConfigbackend/app/Models/ProductByMarketFlightConfig.php
ProductByMarketFlightLegbackend/app/Models/ProductByMarketFlightLeg.php
ProductComponentbackend/app/Models/ProductComponent.php
Marketbackend/app/Models/Market.php
CmsRegionbackend/app/Models/CmsRegion.php
CmsRegionTranslationbackend/app/Models/CmsRegionTranslation.php
CmsCountrybackend/app/Models/CmsCountry.php
CmsCountryTranslationbackend/app/Models/CmsCountryTranslation.php