Skip to content

Feat/organizer dashboard - #94

Merged
manoahLinks merged 3 commits into
mainfrom
feat/organizer-dashboard
Jun 14, 2026
Merged

Feat/organizer dashboard#94
manoahLinks merged 3 commits into
mainfrom
feat/organizer-dashboard

Conversation

@manoahLinks

Copy link
Copy Markdown
Contributor

closes #43
closes #44
closes #45

Add GET /api/organizer/events — the organizer dashboard landing. Returns
the caller's events (status-filterable, paginated, newest-first) each with
per-event and per-ticket-type stats (sold, available, revenue, checked-in),
plus a top-level summary across ALL their events.

Stats are derived with grouped aggregations (event.count, ticket.groupBy
by type+status, ticketType price lookup) — no ticket rows loaded into
memory. "Sold" = CONFIRMED|USED, "checkedIn" = USED, revenue = sold x
current type price. 4 unit tests cover stat derivation, status exclusion,
filter/pagination passthrough, and the empty-organizer case.
Add GET /api/organizer/events/:id/analytics (owner or admin; 404/403
guarded). Returns overview KPIs (revenue, sold, available, checked-in,
check-in rate, avg ticket price), gap-filled daily sales for charting,
and breakdowns by ticket type, payment provider, and payment channel.

Revenue/provider/channel are derived from SUCCESS transactions (channel
read from metadata, persisted at settlement); sold/check-in counts from
ticket.groupBy. Daily series is zero-filled from the first sale day to
today so the chart has no date holes. 7 unit tests cover auth, KPI/
breakdown math, gap-fill, unknown-channel bucketing, and the no-sales case.
Add two owner/admin endpoints for an event's attendees:
- GET /organizer/events/:id/attendees — paginated roster (default 50,
  max 200) filterable by status, ticketTypeId, and name/email search
  (case-insensitive), with event-wide summary counts (total, confirmed,
  checked-in, cancelled).
- GET /organizer/events/:id/attendees/export — full CSV download with
  RFC-4180 escaping and a {slug}-attendees.csv filename.

Plumbing: add a @SkipTransform() decorator + Reflector check in
TransformInterceptor so the CSV route returns its raw body instead of
the {success,data} envelope (wired via app.get(Reflector) in main.ts).
shared assertEventAccess() guards both endpoints (404/403).

8 tests cover auth, row mapping, summary counts, filter passthrough, and
CSV header/escaping/filename.
@manoahLinks
manoahLinks merged commit d5dbead into main Jun 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Organizer: Attendee list + CSV export Organizer: Event analytics (revenue chart, ticket breakdown) Organizer: My events with sales stats

1 participant