[E10] Export Participants
Summary
EP export to XLSX. Single-shape export covering both human-Excel editing and clean re-import round-trip cases. The shape includes our internal PKs alongside source-system reference columns and a timing-export reference column, so a re-import via E06 in (sourceSystem=<self>, trustPKs=true) mode preserves all linkages.
Replaces the current ad-hoc workflow (direct SQL → manual CSV) with a first-class endpoint and a permission-gated UI affordance.
Actor & Context
Actor: event organiser, results officer, tenant admin.
Frequency: ad-hoc — typically before timing-system handoff, after registration close, during corrections, for offline reporting.
Precondition: event exists; user has EVENT_MANAGER or read permission on the event.
Entry point: Export participants button on E02 Event Participants; or from E05 event tile menu.
Main Flow
-
User clicks
Export participantson E02. Optional filters from E02 (category, status, etc.) carry into the export query. -
Browser triggers
GET /api/event-participants/export?eventId=X&format=xlsx(filters as additional query params). -
Backend streams an XLSX file with the canonical EP-export shape (see Export Shape below).
-
File downloads; user opens in Excel.
Alternative Flows
-
AF-1: Empty result set — endpoint returns a header-only XLSX so re-import round-trip semantics are preserved.
-
AF-2: Permission denied (no read access to the event) — 403, UI button disabled with tooltip.
-
AF-3: Backend error during streaming — partial file rejected; UI surfaces a toast and a retry affordance.
Export Shape
Single shape, ~30 columns. Sized for both human readability and re-import round-trip.
| Column | Source | Notes |
|---|---|---|
|
|
Our PK. Drives re-import direct match ( |
|
|
Our Person PK. Drives re-import direct match. |
|
|
External system’s EP UID, if EP was originally imported from one. Blank for self-source EPs. |
|
|
Display-only on re-import; never consumed as identifier. Blank for self-source EPs. |
|
per |
Populated to match what the timing system expects: |
|
|
Always present. |
|
|
Identity tuple. |
|
|
Standard PII. |
|
EP |
Event-day fields. |
|
EP linkage |
When applicable. |
(other columns per current EP model) |
Round-trip-safe only. |
Acceptance Criteria
-
Endpoint
GET /api/event-participants/export?eventId=X&format=xlsxreturns a valid XLSX stream. -
Permission: same as EP read.
-
Round-trip integration test: export → re-import via E06 (
sourceSystem=<self>, trustPKs=true) → assert no field drift, noregistrationIdblanking. -
Human readability: column ordering puts identity + race-day fields ahead of system PKs.
-
sourceSystemNamepopulated only whenRegistrationSystem.is_self=false(per F11 US #696). -
TimingExternalReferenceIDpopulated perEvent.preferredTimingIdentifier. -
Empty result set returns header-only XLSX (round-trip safe).
API Surface
| Call | Purpose |
|---|---|
|
Stream the export. Filters from E02 (category, status, etc.) accepted as additional query params. |
|
Reads |
|
Reads |
Out of Scope
-
CSV format — XLSX only for v1. CSV variant is a low-cost follow-up if demand surfaces.
-
Print-friendly PDF — unrelated; covered by Registration & Financial Reports.
-
Export-with-custom-column-selection — operators get the canonical shape; custom subsets are a future enhancement.
-
Timing-system export — distinct shape, narrow column set, see E11 Timing System Export.
Design Anchors
Design Decisions
-
Single export shape (2026-05-04). Earlier brainstorm considered three modes: human-Excel / re-import / timing-system. Reduced to ONE shape covering human + re-import; timing-system gets its own use-case (E11) with a deliberately narrow column set. Rationale: re-import shape and human-Excel shape need exactly the same columns (operators edit values then re-upload); separating them adds complexity without value.
-
sourceSystemNameis informational only (2026-05-04). Per F11 (US #696), the column is populated only when EP’s sourceRegistrationSystem.is_self=false. On re-import, the column is never consumed as an identifier or matching key — the operator-selected source system on the upload screen drives all matching logic. The column exists purely so a human reader knows "this EP came from <X>" when scanning a mixed-source export. -
TimingExternalReferenceIDpopulated per Event default (2026-05-04). Per F11 (US #696), the column carries whateverEvent.preferredTimingIdentifiersays. On a fresh event with defaultPERSON_ID, the column showsEP.person.id. AfterEvent.preferredTimingIdentifieris locked by a timing-export call (F12 US #697), this export reflects that locked value. Operators get a clean handoff to manually-edit-friendly format if they need to feed external systems. -
Round-trip semantics: blank-cell-never-overwrites (2026-05-04). When this export is re-imported via E06, the existing
EP.registrationIdis preserved when the row’ssourceSystemParticipantIdcell is blank. This is the standard policy from Participant Identity Correlation § Identity Update Policy. It guards against operator deletes-cell-and-re-saves-Excel destroying a carefully-tracked external linkage.
Notes
This use-case exists today only as ad-hoc SQL queries. The 2026-04-22 wp_users incident was partly enabled by operators having no first-class export tool — they were forced to compose CSVs manually, and re-import flow was ambiguous. F11 (US #696) ships the endpoint; this .adoc is the screen + UX scoping.