11 KiB
Admin Portal — UI Design
Audience: Sarah (owner) and Christina (admin assistant). Christina is the heaviest user (booking admin all day). Sarah uses it for oversight, pricing/AGB updates, and high-stakes status decisions.
Theme: shared Mantine tokens with the client portal (dark surface, red primary), but denser components — admin is data-heavy, not card-warm.
Navigation
Sidebar (collapsible to icons-only on smaller screens):
- Dashboard (default landing)
- Bookings
- Calendar
- Cooks (rota + roster)
- Organisations (incl. Stammgruppen)
- Pricing (year-versioned)
- AGB (versioned PDFs)
- Venues (multi-tenant — switch venue here)
- Settings
1. Dashboard (landing)
Static layout for v1. Configurable widget mosaic deferred to v1.5.
┌──────────────────────────────────────────────────────────────┐
│ Action queue [N items] │ full-width
│ Overdue Orga-Mails, missing deposits, missing room plans, │
│ missing dietary info. Each row → one-click action. │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────┐ ┌──────────────────────────────┐
│ This week │ │ Recent client activity │
│ Arrivals + departures │ │ Last 48h booking edits │
│ next 7 days, completeness│ │ across all bookings │
│ %, flags │ │ │
└──────────────────────────┘ └──────────────────────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Pipeline / │ │ Cook rota │ │ Quick actions │
│ financial │ │ status │ │ + New booking │
│ KPIs │ │ unassigned │ │ + New enquiry │
└──────────────┘ └──────────────┘ │ + Send Orga-Mail │
└──────────────────────┘
12-column CSS Grid. Top hero spans 12. Mid row 6+6. Bottom row 4+4+4. Mobile collapses to 1 column.
Widget contracts (v1.5 readiness)
Each section is built as a self-contained React component with a stable key. When the configurable mosaic ships, these become draggable widgets with no contract changes.
2. Bookings list
Table-first. Replaces the Buchungsübersicht spreadsheet.
- Library: Mantine
DataTableormantine-react-table - Columns: Year · Date range · Group / Organisation · Status pill · Persons · Half-house · Orga-Mail sent · Deposit · Final invoice · Notes (truncated)
- Filters (sidebar drawer): status, year, half-house, has-deposit, has-final-invoice, organisation, missing-info (room plan / dietary / headcount)
- Sticky header + virtualised rows
- Bulk actions (with confirmation modals): send Orga-Mail to selected, export DATEV CSV, mark deposit received
- Full-text search: organisation name + course name
- Default sort: date ASC, current year first
- Row click: opens booking detail in same tab
3. Calendar view
Replaces the Belegungsplan spreadsheet.
- Views: month (default), quarter, year
- Status colouring mapped to theme tokens:
enquiry— pinkreserved— amberform_received— yellowdeposit_paid— light greenconfirmed— greencompleted— greycancelled— strikethrough red
- Half-house rendering: day cell splits visually into top/bottom halves when two groups overlap
- Click cell or booking → open booking detail
- Drag-and-drop reschedule opens a modal that surfaces the cancellation-policy implications (e.g. "this falls within 12 weeks of arrival — fees may apply")
- Year header strip: occupancy %, free-day count
- Filter chips above: org, status (multi-select)
4. Single booking detail
The workhorse. Tabbed organisation.
Sticky header
- Group name · status pill · dates (large) · headcount · half-house badge
- Status-transition button (contextual)
- Quick actions: edit, send Orga-Mail, send reminder, attach invoice, cancel
Main column (left, ~70%) — tabs
- Overview
- Completeness checklist (Orga-Mail sent · deposit · room plan · dietary · headcount · schedule)
- Key dates timeline
- Flags (flying changeover · dogs · wheelchair · individual invoicing)
- Pricing summary (line items + total)
- Participants
- Editable table: name · age ·
kind(overnight | day_guest) · dietary tags · allergies · room (if overnight)
- Editable table: name · age ·
- Room plan — split view, grid as primary editor + live floor-plan
visualisation. Both backed by the same
room_assignmentsmodel.- Left — assignment grid: rows = overnight participants; columns = name · age · dietary tags · room (combobox with live capacity counter) · notes. Bulk-select participants → assign to a room. Keyboard-fast (Tab / type-to-search / Enter to commit). Inline validation: overcapacity, conflicting flags (e.g. wheelchair user only assignable to Rooms 1 and 2).
- Right — floor plan visualisation: SVG overlay on top of
grundrisse.pdf, hot-spotted with room rectangles. Each room shows number, capacity dots filled per occupant, flag icons. Live-updates as the grid changes. Click a room → highlights its occupants in the grid. Hover a participant → highlights their room. - v1.5 enrichment: click-room-to-assign-selected (spatial click-select pattern matching the rest of admin)
- Post-MVP: drag a participant card onto a room on the floor plan
- Schedule & meals
- Structured times for Frühstück / Mittagessen / Abendessen (validated against allowed-window config)
- Free-text daily plan
- Extras
- Booking-time extras (cake, second seminar room, linen, early arrival, etc.)
- On-site extras logged by staff (sauna, drinks, coffee) with
payment_methodflag (cashdefault ·invoice)
- Invoices
- Deposit invoice (PDF + DATEV ref + paid status)
- Final invoice (PDF + DATEV ref + paid status)
- DATEV line-item export button (CSV/JSON)
- Audit log
- Full change history: who · when · field · before → after
Side column (right, ~30%) — always visible
- Organiser contact (name · email · phone · billing address · organisation link)
- Internal notes (Bemerkungen) — markdown, per-booking
- Recent activity (last 5 changes, link to full audit)
- Linked enquiry (if any)
- Assigned KOCH/IN per event day
5. Cook rota grid
Replaces the Küchenplan spreadsheet.
- Layout: one row per day, one column per cook
- Left columns (locked / sticky): day-of-month · seminar room occupants (Mandala · Yogaraum) · PAX · KOCH/IN · KOMMENTARE
- Right columns: one per active staff cook + EXTERN
- Cells: edit-on-click, code-aware text input with autocomplete from
the
shift_codeenum - Shift code enum (DB-backed, not freeform):
F— FrühstückM— MittagessenA— AbendessenS— Spät / extra shiftR-K— Reinigung KücheR-HH— Reinigung HaupthausR-HH-Zi— Reinigung Haupthaus ZimmerGR-K— Grundreinigung Küchenur-A— only dinneroff— explicit off- Plus optional explicit time (
HH:mm) and per-cell free-text note
- Multiple codes per cell: combine via
/(e.g.F/M); UI renders each as a coloured chip - Bracket convention (
(...)) marking event start/end is auto-rendered by the grid from each booking's start/end dates — not typed - Filters above grid: month, cook, event
- Conflict highlighting: when a cook has overlapping shifts on the same day, cell shows a warning badge
Schema implication
shift_codes
code text PK -- 'F' | 'M' | 'A' | 'S' | 'R-K' | …
label text
color text -- theme token
cook_assignments
id uuid
venue_id uuid → venues
booking_id uuid → bookings (nullable for non-event days e.g. GR-K)
cook_id uuid → cooks
date date
shift_codes text[] → shift_codes.code
explicit_time time
note text
6. Auxiliary admin screens (CRUD, low design effort)
- Organisations — list + detail; Stammgruppe boolean toggle; merge duplicates
- Pricing — year-versioned editor (one form per year, fields for EZ / DZ / MBZ / day guest / kids 3–10 / cake / sauna / linen / etc.)
- AGB — upload PDF per year; list previous versions
- Venues — switch active venue (multi-tenant); edit venue settings (allowed meal-time windows, default Half House split, etc.)
- Cooks — roster: name · kind (
staff|external_vendor|inactive) · compensation model + amount · notes - Settings — current user profile, notifications preferences, language preference, email signature
Styling & component approach
Mantine as the component library. Theme tokens (red primary on dark surface from the client-portal screenshot) shared across all four surfaces — same tokens, surface-specific compositions. Admin uses denser Mantine compositions; client uses warmer card-based ones.
Mantine ecosystem packages used:
@mantine/core— components@mantine/dates— date pickers (delocale viadayjs)@mantine/hooks— utilitiesmantine-react-table(ormantine-datatable) — bookings list virtualisation, filtering, bulk select
No drag-and-drop in MVP. Interactions previously sketched with DnD become click-select-then-target. DnD is a post-MVP enrichment, not a load-bearing primitive — the click pattern works without it.
- Calendar reschedule — "Reschedule" button → date-picker modal that surfaces cancellation-policy implications inline. Drag-to- reschedule possible later as enrichment.
- Room plan — split view: assignment grid + live floor-plan SVG. Grid is the primary editor; floor plan visualises live. v1.5 adds click-room-to-assign; post-MVP adds participant drag onto the plan.
- Cook rota grid — click cell → autocomplete input for shift codes.
Non-goals (defer to v1.5+)
- Configurable widget mosaic dashboard
- Real-time websocket updates (polled refresh in v1)
- Per-user dashboard layout
- WhatsApp staff notifications (email + in-app only)
- HR / applicant tracking