Files
Messe-Lotse/plan/data-structure-summary.md
T
2026-09-29 09:40:32 +00:00

351 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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