Web-based check-in portal for Luma.com events with badge printing.
# Install dependencies
uv sync
# Copy and configure environment
cp .env.example .env
# Edit .env with your event name, Luma API key, printer settings
# Run the server
uv run uvicorn src.main:app --host 0.0.0.0 --port 8000 --reloadThen open:
- Check-in page: http://localhost:8000
- Admin dashboard: http://localhost:8000/admin
- Run server:
uv run uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload - Run tests:
uv run pytest tests/ - Add dependency:
uv add <package>
- Backend: Python FastAPI + SQLite (via aiosqlite)
- Frontend: Vanilla HTML/CSS/JS with Fuse.js for client-side fuzzy search
- Badge rendering: Pillow (300 DPI PNG for thermal labels)
- Printer: Brother QL via
brother_qllibrary (USB) - Luma API: httpx async client — background guest-list fetch + approval write-back
src/main.py— FastAPI app entry point, lifespan, background syncsrc/routes/api.py— Public check-in API (search, check-in, stats)src/routes/admin.py— Admin API (CSV upload, force check-in, reprint)src/database.py— SQLite schema and CRUD operationssrc/search.py— Fuzzy name matching with thefuzzsrc/badge.py— Badge image generation with Pillowsrc/printer.py— Brother QL printer interfacesrc/luma_client.py— Luma API wrapper with paginationsrc/csv_import.py— Luma CSV export parserstatic/js/checkin.js— Check-in page 5-screen state machinestatic/js/admin.js— Admin dashboard logic
- Load guests from CSV upload or Luma API → SQLite (includes approval_status: approved / pending_approval / waitlist)
- Attendee scans QR → opens check-in page → types name
- Fuse.js fuzzy search matches against cached guest list
- Attendee confirms → (if pending/waitlist and AUTO_APPROVE_ON_CHECKIN, approve in Luma) → server marks checked in locally → generates badge PNG → prints
- Background task drains queued guest approvals to Luma every 30s
The Luma public API has no check-in write endpoint — update-guest-status only
accepts approved | declined | pending_approval | waitlist. So:
- Approvals DO sync to Luma. Admin "Approve Pending/Waitlist" (bulk + per-row) and
door auto-approve call
POST /v1/events/guests/update-statuswithstatus="approved". - Check-in is LOCAL-ONLY. The portal is the source of truth for attendance; check-ins
are stored in
data/checkin.dband never appear on the Luma dashboard. Use the admin Export CSV for the attendance record. (The old check-in write-back was removed — it always 400'd becausechecked_inis not a valid Luma status.)