You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 93fb35c
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CLAUDE.md
+15Lines changed: 15 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -166,6 +166,21 @@ Gotchas:
166
166
- Code lives under `backend/ee/Seating/` and `frontend/src/ee/seating/`. A product is seated iff a price **band** links to it (never call a band a tier), and `seat_claims` has no status column — HELD/SOLD/BLOCKED derive from the owning order via `SeatClaimRepository`, so never add a sweeper or stored status
167
167
- Any new path that sells a ticket must claim a seat (under `SeatingEventLockService::lock`, order lock first) or refuse seated products, and anything that voids a ticket must release its claim. Rules that exist in both PHP and TS are pinned to `backend/tests/Fixtures/seating/` — change the fixture first
168
168
169
+
#### Lineup & schedule
170
+
- Profiles (speakers, artists, hosts) belong to the organizer and are reused across events. `event_lineup_entries` puts a profile on an event (billing tier, role, `is_hidden`), `event_spaces` are stages/rooms (optionally tied to one of the event's `event_locations`), and `event_schedule_items` are time slots linked to lineup entries through `event_schedule_item_performers`
171
+
- Writing a profile needs organizer access; event-only members can add existing profiles to their event's lineup and schedule. Hidden entries, and untitled slots whose people are all hidden, are filtered for the public endpoint in `GetEventLineupHandler`
172
+
- Profile photos are `PROFILE_IMAGE` images on the generic `/images` endpoint, ordered by `images.sort_order` (nulls last, so new uploads go to the end); the first is the main photo. Link types come from `ProfileLinkType::fromUrl`, never from the client
173
+
- Schedule days use a 05:00 boundary (`DAY_BOUNDARY_HOUR` in `utilites/lineupSchedule.ts`, kept free of dependencies so e2e unit specs can import it) so late sets stay on their night. Per-date lineups for recurring events are derived, never stored: a date shows the slots that fall on it plus people with no slots at all (`lineupForOccurrence`)
174
+
- Duplicating an event copies its lineup through `EventLineupCloneService`; single events shift slot times by the start-date offset, recurring events keep them
175
+
- The run-sheet export (`LineupExport`) and the import share column names: the browser parses CSV/XLSX itself (`utilites/spreadsheetReader.ts`, XLSX via `DecompressionStream` + `DOMParser`, no library) and `utilites/lineupImport.ts` (dependency-free, unit-tested from e2e) builds the preview; the server only receives clean JSON. Header labels are translated with the Lingui context "Lineup spreadsheet column", whose translations must equal the backend's `__()` header strings so a localized export re-imports. People and stages match by `nameKey` (lowercase, collapsed whitespace) on both sides — keep `ImportLineupHandler::key` and `nameKey` identical or the preview lies. The preview mirrors every server validation limit so one bad cell never fails the whole import. `ImportLineupHandler` locks the event row, writes through repositories in bulk (not the per-row upsert handlers — far too slow for 1,000 slots), skips slots that already exist, and dispatches the spam check once. Import needs organizer write access because it creates profiles
176
+
- Lineup highlights in order and ticket emails come from `EmailLineupHighlightsService`, gated on the LINEUP/SCHEDULE homepage sections, and per-date only for recurring events (the same rule the widget strip and event page use). Mailables keep the DTO in a non-readonly property with a `null` default so mails queued before a deploy still unserialize
177
+
178
+
#### Homepage sections
179
+
- The event homepage renders `event_settings.homepage_sections` in order: one JSON list of `{id, type, enabled, heading, …}`. A `null` list, or a missing built-in, falls back to the default order (`resolveHomepageSections`), so events that never saved sections look exactly as before. The hero and footer are fixed. `TICKETS` is always present and enabled, enforced server-side
180
+
- The About section renders `event.description`; never copy the description into a section (SEO, listings, emails and the API all read it). Extra copy belongs in `TEXT` sections
181
+
-`HomepageSectionsSanitizer` is the only writer: it purifies HTML, de-duplicates built-ins, keeps only gallery/sponsor image ids that are this event's `EVENT_GALLERY`/`EVENT_SPONSOR_LOGO` images and only allows YouTube/Vimeo video links. New section text must also be added to `EventSpamCheckContentService::homepageSectionContent`
182
+
- Organizer pages use the same system via `organizer_settings.homepage_sections` (`sanitizeForOrganizer`, built-ins `EVENTS` (always shown)/`ABOUT`/`CONTACT`/`PAST_EVENTS`, images `ORGANIZER_GALLERY`/`ORGANIZER_SPONSOR_LOGO`). Layout rules live in `utilites/homepageSectionLayout.ts` (dependency-free, unit-tested from e2e): a leading run of ABOUT/CONTACT renders inside the profile card, and PAST_EVENTS directly after EVENTS is the Past tab, elsewhere its own list — so the default order reproduces the classic organizer page
183
+
169
184
#### Abuse & spam
170
185
- Treat every user-typed string that can reach an email to an unverified address as a spam vector. Never greet with a user-supplied name in account/auth emails, and validate person-name fields with `PersonNameRule` (blocks URLs, phone numbers, markup; allows every script)
171
186
- Buyer/attendee mail that carries event content implements `ContainsEventContent` (+ `ProvidesEventContent`). `BaseMail::send()` swaps it for the content-free `UnpublishedEventUpdateMail` while the event is DRAFT or PENDING_MANUAL_REVIEW, unless every recipient is a verified member of the event's account. New event-scoped mailables must implement the interface
0 commit comments