--- goal: DataObject Structure Summary — Reuse Strategy for 24HRS Messe-Lotse version: 1.2 date_created: 2026-06-10 last_updated: 2026-06-16 owner: 24HRS Team status: Planned tags: architecture, data-model, pimcore, reuse --- # Introduction ![Status: Planned](https://img.shields.io/badge/status-Planned-blue) Consolidated DataObject structures for the MesseLotse rewrite. Defines which existing Pimcore DataObjects are reused from `rkcFairBundle` and `dgmMediaBaseBundle`, what fields are added, and what new entities are created in `MessebauBundle`. **Reuse strategy:** Extend `fair` and `fairLocation` in `rkcFairBundle` with MesseLotse-specific fields. Reuse `Person` from `dgmMediaBaseBundle` as the contact/worker entity. All trade-fair-management logic lives in the new `MessebauBundle`. --- ## 1. fairLocation — `rkcFairBundle` (extend existing) | Field | Type | Notes | |------------------|----------------------------|----------------------------------| | active | bool | existing | | swidentifier | input | existing | | omitSync | bool | existing | | modified | datetime | existing | | address | input | existing | | imagesKey | input | existing | | vaAssetId | input | existing | | image1–5 | image | existing | | boxOptionsTree | input | existing | | boxes | relation | existing | | **+ name** | **input** | **new — locale name, e.g. "Messe Frankfurt"** | | **+ googleMapsUrl** | **input** | **new** | | **+ notes** | **textarea** | **new** | | **+ contacts** | **ContactAssignment[] (FC)** | **new — see §1a** | ### 1a. FieldCollection: ContactAssignment | Field | Type | Notes | |-----------|--------------------|------------------------------------| | person | many-to-one → Person | reuses dgmMediaBaseBundle Person | | role | select | technical / billing / operations / general | | validFrom | date | | | validTo | date | nullable (null = indefinite) | | notes | textarea | | *Same person+role+timeframe pattern as WorkerAssignment (§6c), scoped to fairLocation.* --- ## 2. fair — `rkcFairBundle` (extend existing) | Field | Type | Notes | |--------------------|----------------------------|----------------------------------| | name | input | existing | | swidentifier | input | existing | | active | bool | existing | | omitSync | bool | existing | | modified | datetime | existing | | location | many-to-one → fairLocation | existing | | setupStartDate | datetime | existing | | fairStartDate | datetime | existing | | fairEndDate | datetime | existing | | destructEndDate | datetime | existing | | imagesKey | input | existing | | vaAssetId | input | existing | | image1–5 | image | existing | | boxOptionsTree | input | existing | | boxes | relation | existing | | assignedArticles | relation | existing | | **+ setupEndDate** | **datetime** | **new** | | **+ destructStartDate** | **datetime** | **new** | | **+ hallsUsed** | **input** | **new — free text, e.g. "Halle 5.1, 6, 8"** | | **+ notes** | **textarea** | **new** | | **+ regulations** | **many-to-many → Asset** | **new — simple relation, no metadata** | | **+ documents** | **FairDocument[] (FieldCollection)** | **new — see §2a** | ### 2a. FieldCollection: FairDocument | Field | Type | Notes | |--------------|------------------------|----------------------------------------------------| | asset | many-to-one → Asset | the file | | documentType | select | `constructionBriefing` / `floorPlan` / `protocol` | | date | datetime | protocol date or revision date | | hallName | input | hall reference for floor plans | | remarks | textarea | optional | --- ## 3. Person — `dgmMediaBaseBundle` (reuse as-is) | Field | Type | Notes | |---------------------|-------------------------|------------------------------------| | firstname | input | existing | | lastname | input | existing | | email | input | existing | | company | input | existing | | salutation | select | existing | | gender | select | existing | | additionalAddresses | mediaBaseAddress[] (FC) | existing — contains telefonNumber, eMailAddress, faxNumber, full address | | ... +28 other fields | | existing | Used as relation target for: - `fairLocation.contactPerson` - `Customer.contactPerson` (future) - `WorkerAssignment.person` (future, Slice 5 of `architecture-vertical-slices-1.0.md`) --- ## 4. Customer — `MessebauBundle` (new DO) *Deferred — an existing Customer DO lives in a bundle not currently accessible. This section will be updated when that bundle is available.* | Field | Type | Notes | |-------------------|-------------------------|------------------------------------| | company | input | | | address | input | | | contactPerson | many-to-one → Person | reuses dgmMediaBaseBundle Person | | brandDoc | document | company-wide brand guidelines | | consultationDocs | document[] (gallery) | multi-fair planning docs | | contractDocs | document[] (gallery) | framework agreements | | notes | textarea | | --- ## 5. Job — `MessebauBundle` (new DO) ### 5a. Master data | Field | Type | Notes | |--------------|-----------------------------|----------------------------------------------------| | project | input | display name | | customer | many-to-one → Customer | | | fair | many-to-one → fair | rkcFairBundle | | standType | select | `Systemstand` / `Reihstand` / `Eckstand` / `Kopfstand` / `Blockstand` / `Inselstand` | | standSize | input | e.g. "6x4" | | standHeight | numeric | meters | | hall | input | e.g. "Halle 5.1 / Stand C12" | | area | numeric | m² | | workflowState| input | managed by Symfony Workflow | | notes | textarea | | ### 5b. Date overrides (all nullable — fallback to `fair`) | Field | Type | |------------------------|----------| | setupStartOverride | datetime | | setupEndOverride | datetime | | eventStartOverride | datetime | | eventEndOverride | datetime | | teardownStartOverride | datetime | | teardownEndOverride | datetime | ### 5c. Asset fields | Field | Type | Notes | |-------------------------|--------------|--------------------------------------------| | standImage | image | single booth photo | | standGallery | image[] | gallery | | briefingCustomerDoc | document | per-job override; null → inherit from customer | | briefingPlanDoc | document | per-job override; null → inherit from fair floorPlan | | briefingAdditionalDoc | document | | | powerConfirmation | document | | | wlanConfirmation | document | | | cleaningConfirmation | document | | | riggingQuote | document | | | riggingDrawing | document | | | riggingMesseConfirmation| document | | | standApprovalDoc | document | | | acceptancePhotos | image[] | | | acceptanceSignature | image | | | weeklyProtocols | document[] | | ### 5d. FieldCollections | FieldCollection | Fields | |----------------------|--------------------------------------------------------------------------------------------| | BookingPlatformInfo | portalLink, email, password (encrypted), deadline | | PowerInfo | kw, distributor, deadline | | WlanInfo | type, deadline | | CleaningInfo | deadline | | RiggingInfo | supplierFirstname, supplierLastname, supplierEmail, supplierPhone, messeFirstname, messeLastname, messeEmail, messePhone, deadline | | DruckproduktionInfo | qm, blockout, forexplatten, deadline | | CateringInfo | baristaEnabled, baristaPackage, days, drinksEnabled, drinksDetails, foodEnabled, foodDetails | | CostEstimate | standConstruction (int, EUR), activation (int, EUR), furniture (int, EUR), logistics (int, EUR) | | Material | type (flooring/standsystem/hardware/furniture), name, quantity, notes — **multi** | | ChecklistItem | text, checked, order — **multi** | --- ## 6. Resource Pool Entities — `MessebauBundle` (Slice 5) *All person references reuse `Person` from dgmMediaBaseBundle.* ### 6a. Tree-Based Assignment Pattern Assignment and booking entities are standalone DataObjects placed in the Pimcore tree under a `fair` or `Job` instance. Tree location expresses scope — no nullable `job` relation field is needed. ``` /Fairs/OMR2026/ ├── ResourceAssignments/ │ ├── WA-pool-01 (fair-pool worker) │ ├── PVA-pool-01 (fair-pool vehicle) │ └── ... ├── AccommodationBookings/ │ ├── Hotel-Central/ │ │ └── Occupants/ │ │ ├── Anna-Müller │ │ └── Max-Schmidt │ └── Airbnb-Loft/ │ └── Occupants/ │ └── Lisa-Weber ├── Travel/ │ ├── Bahn-HH-Berlin/ │ │ └── Passengers/ │ │ ├── Anna-Müller │ │ └── Max-Schmidt │ └── Mietwagen-Frankfurt/ │ └── Passengers/ │ └── Lisa-Weber ├── Jobs/ │ ├── BoothBrevo/ │ │ └── ResourceAssignments/ │ │ ├── WA-001 (job-dedicated worker) │ │ └── PVA-001 (job-dedicated vehicle) │ └── BoothDmexco/ │ └── ResourceAssignments/ │ └── WA-002 (job-dedicated worker) ``` **Scope**: parent folder is `.../ResourceAssignments/` under `fair` → fair-pool (available for all jobs). Parent folder is `.../Jobs/{job}/ResourceAssignments/` → dedicated to that specific job. Bookings live directly under fair. **Aggregation queries** (fair-level "how many Baristas?"): ```php $listing = new WorkerAssignment\Listing(); $listing->setCondition("o_path LIKE '/Fairs/OMR2026/%'"); $allAssignments = $listing->load(); ``` This returns both fair-pool and all job-dedicated assignments in one query. For scoped queries: ```php // Fair-pool only "o_path LIKE '/Fairs/OMR2026/ResourceAssignments/%'" // Specific job only "o_path LIKE '/Fairs/OMR2026/Jobs/BoothBrevo/ResourceAssignments/%'" ``` ### 6b. Pool Entities (shared resource catalog) | DO | Fields | Tree location | |---|---|---| | WorkerRole | name (Barista / Rigger / LorryDriver / FairWorker / Electrician / Cleaner) | `/ResourcePool/WorkerRoles/` | | PoolVehicle | name, type, licensePlate, state (owned/hired/toHire), notes | `/ResourcePool/Vehicles/` | | Equipment | name, description, state (owned/rented/toRent), notes | `/ResourcePool/Equipment/` | | Accommodation | name, address, bookingReference, type (hotel/apartment/other), notes | `/ResourcePool/Accommodations/` | ### 6c. Worker + Vehicle + Equipment Assignments (standalone DOs, tree-scoped) | DO | Fields | Tree location | |---|---|---| | WorkerAssignment | person → Person, role → WorkerRole, state (select: internal / hired / toHire, default from WorkerRole), startDate (datetime), endDate (datetime), offerDoc (document, nullable, external only), contractDoc (document, nullable, external only), billingDoc (document, nullable, external only), notes (textarea) | `/Fairs/{fair}/ResourceAssignments/` or `/Fairs/{fair}/Jobs/{job}/ResourceAssignments/` | | PoolVehicleAssignment | poolVehicle → PoolVehicle, startDate (datetime), endDate (datetime), notes | same pattern | | EquipmentAssignment | equipment → Equipment, startDate (datetime), endDate (datetime), notes | same pattern | ### 6d. Accommodation — Booking + Occupants Pattern One real-world booking covers N persons. Documents (offer/contract/billing) live on the booking parent. Occupants are tree children. **AccommodationBooking** (parent) | Field | Type | Notes | |---|---|---| | accommodation | → Accommodation | | | checkIn | date | | | checkOut | date | | | confirmationNumber | input | | | offerDoc | document | nullable | | contractDoc | document | nullable | | billingDoc | document | nullable | | totalCost | numeric (EUR) | nullable, for split billing | | notes | textarea | | Tree: `/Fairs/{fair}/AccommodationBookings/` **AccommodationOccupant** (tree child of booking) | Field | Type | Notes | |---|---|---| | person | → Person | | | costShare | numeric (EUR) | nullable, for split billing | Tree: `/Fairs/{fair}/AccommodationBookings/{booking}/Occupants/` ### 6e. Travel — Booking + Passengers Pattern Same pattern as accommodation: one booking covers N travelers. Documents on the parent, passengers as children. **TravelBooking** (parent) | Field | Type | Notes | |---|---|---| | transportMethod | select | train / plane / rentalVan / ownCar | | origin | input | | | destination | input | | | departureDateTime | datetime | | | arrivalDateTime | datetime | | | returnDepartureDateTime | datetime | nullable | | returnArrivalDateTime | datetime | nullable | | bookingReference | input | | | offerDoc | document | nullable | | contractDoc | document | nullable | | billingDoc | document | nullable | | totalCost | numeric (EUR) | nullable | | notes | textarea | | Tree: `/Fairs/{fair}/Travel/` **TravelPassenger** (tree child of booking) | Field | Type | Notes | |---|---|---| | person | → Person | | | costShare | numeric (EUR) | nullable | Tree: `/Fairs/{fair}/Travel/{booking}/Passengers/` --- ## 7. Bundle Responsibility Split | Bundle | Owns | Reuses | |-----------------------|-----------------------------------------------------|-----------------------------------| | `rkcFairBundle` | fair + fairLocation (extended) | — | | `dgmMediaBaseBundle` | Person | — | | `MessebauBundle` | Customer, Job, ContactAssignment FC, FairDocument FC, all Job FCs, resource pool entities | Person, fair, fairLocation | --- ## 8. Related Documents - [architecture-vertical-slices-1.0.md](architecture-vertical-slices-1.0.md) — implementation plan with 6 AI-sized vertical slices - [architecture-rewrite-1.0.md](architecture-rewrite-1.0.md) — original plan (superseded, retained for reference) - [ai-document-skills.md](ai-document-skills.md) — AI skill catalog and field routing matrix - [3d-booth-generation.md](3d-booth-generation.md) — SketchUp + Aluvision + MCP pipeline