v0.4.5 — settings, sessions, and event admin
Pre-release
Pre-release
[0.4.5] - 2026-06-24
Added
- MFA enrollment split into three steps: TOTP QR/setup-key confirm → dedicated backup-codes page → full session; new
backup_codes_requiredsession stage and DB migration POST /mfa/enroll/backup-codesroute andhandleTotpBackupCodesCompleteAPI endpoint; session promoted toFULLonly after backup-codes acknowledgment- 6-digit centered OTP input field with auto-focus, paste support, keyboard navigation, and backup-recovery-code toggle
GET /smart redirect: authenticated users land on/admin(or/operator), unauthenticated users on/login- Admitto favicon set: SVG, 32 × 32 PNG, Apple touch icon, and ICO fallback served from
/favicon.* - SSO button label per identity provider (
login_button_label); default falls back to "Continue with SSO" - Admin sidebar: checkmark brand mark (correct
admitto-mark.svg),All events+Settingsitems always pinned to footer - Settings sub-navigation: horizontal tab bar (General · Identity providers · Cloudflare Access) rendered on both SPA and SSR settings pages
- Identity-provider and Cloudflare Access admin pages rendered with full sidebar shell matching the SPA layout (sticky layout, design-system CSS tokens)
- Event card: date icon, location pin icon, attendee count stat with user icon; hover lift effect
- Event overview landing page at
/admin/events/:id/overviewwith quick stats and navigation links to live admin sections - Shared admin shell (
StaffShell): sidebar with independent scroll, slim topbar, optional settings subnav, and mobile drawer navigation - Staff topbar: mailer status indicator (configured dot + provider label), role badge (SA/AD/OP), icon-only sign out
- Sidebar footer: Users & roles link for org admins and superadmins (page ships in a follow-up PR)
- Dev-only demo bar (
import.meta.env.DEV) to trigger sample toasts from the admin shell - Admin check-in v2: split layout with scan bar, connection banner, stats/progress sidebar, color-dot recent scans, and fullscreen camera overlay with QR viewfinder
- Create event UI:
POST /api/admin/events, New event modal (title, slug, date, location), redirect to attendees after create - Events picker visual polish: active status badge, responsive 2/3-column grid, empty state with Create event CTA
- Attendees v2:
rsvp_statusmigration, wider list table (STATUS/MAIL/CHECK-IN/actions), manualPOST /attendees, full attendee detail page with activity log, Add attendee modal - Event settings page at
/admin/events/:id/settings: edit title, date, location, capacity; superadmin PII CSV export; archive/unarchive from danger zone;capacityfield on Event
Changed
GET /api/admin/meincludesmailer_status(provider presence only — no credentials);/api/auth/meunchanged for operator sessions- Toast stack position: top-right below the staff topbar (
--topbar-h) instead of bottom-right - Admin check-in: keyboard wedge
inputMode="none", auto-submit for long tokens, Esc to clear result state - README: local dev onboarding (
Run locally), Nodeenginesalignment,infra/vsdeploy/distinction; newapps/admin/README.md - Admin Vite dev proxy: forward
/mfato@admitto/webso MFA enrollment works on:5173 - Login page
<title>fixed to "Admitto"; addedapplication-name,og:site_name, anddescriptionmeta tags for password-manager naming - MFA page heading changed from
<h1>to<p class="auth-page-action">to preserve correct document semantics; Admitto brand uses<h1> - CSRF fix: Nginx forwards
$http_host(with port) inHostandX-Forwarded-Hostheaders so127.0.0.1:8080logins no longer return 403 - Superadmin instance settings at
/admin/settingswith branding panel — live theme preview, anti-lockout guards, and links to OIDC / Cloudflare Access admin pages (#96) - Settings → Mail transport panel: configure provider, masked secrets, env-locked fields, and test send (#99)
- Settings → Sessions and Security panels: list/revoke staff sessions, bulk operator revoke, session TTL and MFA policy;
GET/PATCH /api/admin/system-settings(#112) - Event archiving:
Event.archived_athides completed events from default lists; superadmin archive/unarchive; archived events read-only on admin mutating APIs; Active/Archived tabs; check-in stays available (ADR 0022) (#116) - Admin shell layout: single main scroll region (subnav + page content),
100dvhviewport, Overview in live event sidebar segments; events picker opens archived tab when no active events remain; active event cards are fully clickable - MFA enrollment and verify: step progress indicator (
Step X of 3), no OTP autofocus on the QR step, auto-submit after six digits, and submit loading state on auth forms - Settings horizontal subnav uses consistent styling across SPA and SSR; Identity providers and Cloudflare Access open via full-page navigation to SSR admin pages
- Admin sidebar chrome trimmed: redundant context labels and duplicate Instance settings header action removed
@admitto/uidesign system:Spinner,EmptyState,Skeleton, andToastProvider/useToast(#120)- Admin app root wrapped with
ToastProvider; recoverableErrorBoundaryon render errors (#97, #120) - Admin UX micro-fixes: import column reference table and CSV template download; delivery log purpose filter; compose dirty-state guard; attendee drawer discard confirmation; check-in stats admitted/total (#121)
POST /mfa/enroll/download-codes— backup codes as.txtduring enrollment (#117)- Check-in:
NoteModalreplaceswindow.promptfor attendee notes (#114) - Runtime upgraded to Node 24 LTS; React 18 → 19 across admin and web (#111, #110)
- Login, MFA, and superadmin identity-provider HTML pages aligned with Admitto design tokens (#117)
- OIDC group mapping role picker uses a select; provider list supports inline enable/disable (#117)
- Cloudflare Access admin form shows status badge, fall-through explanation, and enable warning (#117)
- Requirements and Communication panels use
ConfirmDialoginstead of nativewindow.confirm(#97)
Fixed
- Guest ticket page now prints correctly (white background, no wallet buttons, no shadows)
- Export: sanitize dynamic attribute column headers against formula injection (#97)
- Local dev: login/MFA CSRF when
Origin/Refererabsent (Safari); admin SPA dist path afternpm run build -w @admitto/admin(#115) - Admin page shell document title uses event name prefix without regressing the visible
h1(#118) - SSO failure on
/loginshows a dedicated fallback banner; removed placeholder “SSO coming soon” when no IdP is configured (#117) - Check-in card coloured left border per scan status (#114)
- Login page title and heading: “Sign in to Admitto” (#114)
- Sidebar Overview section shows “Soon” until built (v1.0) (#114)
- Settings subnav active tab uses path prefix matching instead of exact pathname equality
- Sidebar “Soon” badges render with correct styling (
.nav-item--soon,.nav-item__badge) - Global link hover underline no longer appears on sidebar brand, navigation items, or button-styled links (SPA and SSR settings shell)
- OIDC admin form: URL fields use
type="url"; group→role mapping rows can be added/removed; scope type select; SSO button live preview on provider form; failed save re-renders submitted mapping drafts - Cloudflare Access settings: clearer operator copy and field hints; test action labeled “Test connection”
- Events picker: search by title/location; content width capped at 1100px; grid capped at three columns on wide screens
- Check-in camera: removed fullscreen toggle (browser instability); debounce repeated ZXing decodes; extract ticket token from QR URLs with trailing slash or query (
packages/tickets) - Check-in invalid/revoked scans show dedicated feedback card instead of silent failure
- Requirements:
@admitto/uiSwitch missing thumb restored; item table uses name + auto-generated key; drawer layout cleanup - Event picker cards: removed hover lift/underline noise
- Vercel Git deploys disabled via root
vercel.json(self-hosted Docker only)
Security
- Branding
font_family_nameallowlist on save and ticket-page render (blocks CSS/HTML injection via custom fonts) (#96) deploy/validate-env.shpre-flight fordeploy/.env; production boot fails fast whenREDIS_URLis missing, unauthenticated, orENCRYPTION_KEYis invalid- PENtest hardening: structured audit events for rate limits, MFA, OIDC login, logout, admin 403, and settings changes — ISO
tson each event (#123) - Production
BASE_URLmust usehttps://(exceptlocalhost/127.0.0.1smoke) (#123) - OIDC ID token verification restricts JWT algorithms to RS/ES/PS family (no
none) (#123) - Deploy Redis requires
REDIS_PASSWORD; compose wires authenticatedREDIS_URL(#123) - Nginx proxy baseline security headers (HSTS, nosniff, frame deny); Docker bridge gateway for RealIP behind NPM (#123)
/healthzand/readyzresponses include baseline security headers (#123)- GitHub Releases for
v0.x.yare pre-release untilv1.0.0;publish-containersets the flag automatically (#123) - PENtest follow-up: rate limits on MFA enroll,
/healthz, admin import/template preview, and OIDC provider discover/test; OIDC outbound fetch resolves DNS before connect; malformedX-Forwarded-Forfalls back to socket IP (no sharedunknownbucket) docs/SECURITY-CONTROLS.md: rate-limit matrix,TRUST_PROXYtrust model, SSRF/DNS-rebind guards, PEN retest checklist for operators
Deploy
- Container image:
ghcr.io/solarssk/admitto:0.4.5(rolling:0.4) - Migrations apply automatically on container start (with pre-migration backup when pending). No manual
migrate deploy.