# 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 `DataTable` or `mantine-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` — pink - `reserved` — amber - `form_received` — yellow - `deposit_paid` — light green - `confirmed` — green - `completed` — grey - `cancelled` — 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 1. **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) 2. **Participants** - Editable table: name · age · `kind` (overnight | day_guest) · dietary tags · allergies · room (if overnight) 3. **Room plan** — split view, grid as primary editor + live floor-plan visualisation. Both backed by the same `room_assignments` model. - **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 4. **Schedule & meals** - Structured times for Frühstück / Mittagessen / Abendessen (validated against allowed-window config) - Free-text daily plan 5. **Extras** - Booking-time extras (cake, second seminar room, linen, early arrival, etc.) - On-site extras logged by staff (sauna, drinks, coffee) with `payment_method` flag (`cash` default · `invoice`) 6. **Invoices** - Deposit invoice (PDF + DATEV ref + paid status) - Final invoice (PDF + DATEV ref + paid status) - DATEV line-item export button (CSV/JSON) 7. **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_code` enum** - **Shift code enum** (DB-backed, not freeform): - `F` — Frühstück - `M` — Mittagessen - `A` — Abendessen - `S` — Spät / extra shift - `R-K` — Reinigung Küche - `R-HH` — Reinigung Haupthaus - `R-HH-Zi` — Reinigung Haupthaus Zimmer - `GR-K` — Grundreinigung Küche - `nur-A` — only dinner - `off` — 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 (`de` locale via `dayjs`) - `@mantine/hooks` — utilities - `mantine-react-table` (or `mantine-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