Frontend reference

Midsummer has two separate Angular single-page apps. They are different projects with different framework versions and do not share component code.

App

Dir

Framework

Purpose

Main event SPA

ui/

Angular 21.x + PrimeNG 21.x (+ Kendo)

register, vendors, schedule, staff, shop, dashboard, displays

Tenant admin SPA

tenantui/

Angular 19.x + PrimeNG 19.x

org-level: events, settings, domains, memberships, api-tokens, stripe-keys, billing, connections

Both use TailwindCSS 4.x with the Aura preset (indigo primary). Built assets are served from front/static/ui/ via WhiteNoise.

Main SPA (ui/) layout

ui/src/app/
  apps/<module>/        feature components per Django app:
                          register, vendors, schedule, staff, shop, dashboard, displays
  register-form-components/   the form builder (see custom-form-system)
    primatives/              one folder per field type
    *-components.ts          the registries
    register-form-component-factory/   the dynamic renderer
  services/             REST + shared services (rest, qr-scanner, jury-websocket,
                        reports, registration-association, schedule-*, ...)
  shared/, components/  reusable UI (app-title-bar, nice-error)
  guards/, pipes/       route guards, custom pipes
  app.routes.ts         route table (/register, /vendors, /schedule, /staff, /shop, /displays)
  app.config.ts         standalone bootstrap + PrimeNG theme provider
ui/public/data/        static assets (e.g. previous-years registration reference data)

How Django serves the SPA

The Angular apps are compiled into Django static files by the render scripts (render-ui-elements.sh, render-tenant-ui-elements.sh), then Django serves a thin shell template via midsummer.common.views.angular_page / angular_page_event_protected that boots the named app. Per-module page routes are permission-gated in Python before the shell is served.

See Request resolution.

The form system on the frontend

The frontend half of the JSON form builder lives entirely under ui/src/app/apps/register/register-form-components/ — including the vendor, schedule, and shop form components (historically colocated there). See the custom form system for the full theory.

Notable components (high level)

  • register: checkin, rapid-checkin (+ display), merch-pick, merch-summary, merch-adjustment, metrics2, reports, badge settings, audit-log, staff-management-ping, name-watch-list, checkin-kiosks, stripe-transactions, and the form editor + all form primitives.

  • vendors: vendor-detail, vendor-display, vendor-checkin-form-viewer, vendor-jury-display, vendor-ping-conversations, vendor-task-component.

  • schedule: schedule-index, editor/editor2 (Kendo), form-editor, slot-editor, digital-signage, panel-details, responses, import/export, rooms/categories/tracks.

  • staff: staff-index, staff-hr (+ title dialogs), roster/shifts.

  • shop: items, cart, fulfillment terminals.

  • shared: app-title-bar, nice-error.

Services of note

rest (HTTP), qr-scanner, jury-websocket, register-reports, registration-association, rapid-checkin, schedule-display, schedule-edit, schedule, register-metrics2, registration-edit-log.

Build & type-check

# After editing, rebuild the SPA into Django static files:
./render-ui-elements.sh            # ui/
./render-tenant-ui-elements.sh     # tenantui/

# Fast type-check during iteration:
cd ui && npx ngc --noEmit -p tsconfig.app.json
# Full build:
cd ui && npx ng build

Exit 0 = pass. See First steps → Build & test gates.

Deep dive

The exhaustive component-by-component listing lives in documentation/frontend-structure.md (maintained by the syncer workflow).