6.8 KiB
Seminarhof — product backlog
Status legend: ✅ done · 🟡 partial · ⬜ todo · 🔮 phase 2
✅ Shipped
- Enquiry table. Public enquiries land in
enquiry(notbooking). Admin view at/admin/enquirieswith approve / waitlist / decline. - Approve flow. Requires start + end date and a client — either pick an
existing one (searchable autosuggest) or create a new one (email required,
defaults to the enquiry contact email; rejects duplicate emails). Creates a
reservedbooking linked viabooking.enquiry_id. organization→clientrename (+client_memberalready models multiple login users per client; one is seeded from the enquiry email).course→eventrename across the codebase.- Enquiry required fields trimmed: event name + contact email only; privacy-policy consent only (no T&C checkbox).
- Booking-detail "Enquiry" milestone sources its date from the enquiry's real submission time, not the approval timestamp.
Backlog (epics)
E1 · Calendar / availability
- ✅ 1.1 Hide
enquirystatus on public availability — show it to admins/owners only.getAvailabilityreads the optional session and filters out enquiry-state bookings for non-staff; the legend drops the enquiry swatch when no such day is present. - ✅ 1.2 Half-house: render the day cell split by a diagonal line (two
triangles, one per half-house booking) instead of the current dot. On hover,
show both events being held that day.
getAvailabilityreturns a per-daybookings[](deterministic order);availability.tsxrenders the diagonallinear-gradientsplit when two half-house bookings share a day and lists both in the tooltip. Single half-house days keep the corner dot. - ⬜ 1.3 Hover → rich detail card for bookings that are reserved AND public.
- ⬜ 1.4 Waitlist dot in the top-right corner of the day cell. (Pairs with E6 — the wishlist/waitlist data.)
- 🔮 1.5 Google Calendar auto-sync. Phase 2.
E2 · Actions hub + transition safety ✅
- ✅ 2.1 All booking actions consolidated into one header hub
(
BookingActions.tsx), beside Cancel booking.BookingStatusPanelis now display-only (timeline + next-action alert). - ✅ 2.2 Every transition goes through a two-click
ConfirmButton(ConfirmButton.tsx): first click arms ("Confirm?", red); second commits; auto-reverts after 3s. Replaced the rawwindow.confirmfor cancel too.
E3 · Contract form + invoicing (big rock; status-model redesign approved)
-
🟡 3.1 Binding booking form scoped to a booking — core fields shipped. Client opens a passwordless magic link (
/booking-form/$token), lands logged-in as a provisionedclientuser, and fills name/company, billing address, phone, website, payment method (Cash / bank transfer), event basics + AGB/privacy consents. Submit is legally binding (stampscontractResponse='approved'+agbAcceptedAt/privacyAcceptedAt). Token = a short-lived signed JWT via@pikku/jose(no token table). Admin mints the link from the booking actions hub. Deferred to E7/E5: the priced add-on groups (extras / room equipment / materials) that feed the final invoice. -
✅ 3.2 Sending the contract → recorded response / binding. (Lifecycle work —
recordContractResponse+ the form submit both mark it binding.) -
⬜ 3.3 Generate a preview invoice PDF from the form → email to client
- admin → upload into files. (Depends on E5 — blocked.)
-
✅ 3.4 14-day deadline for signing + sending the deposit. (Lifecycle cron: deposit
dueOn=+14d, day-7 reminder, day-14 overdue flag.) -
⬜ 3.5 On bank receipt, admin uploads the official invoice and marks it paid → deposit paid. (Mark-paid done via
recordDepositReceived; the upload depends on E5 — blocked.) -
✅ 3.6 Status-model redesign — done by the lifecycle work: enum is
enquiry → reserved → confirmed → ended(+cancelled); contract-signed + deposit-paid are sub-milestones insidereserved, shown as a timeline inBookingStatusPanel.Auth note: the magic link issues the same DB-session as password login (reuses
lib/session.ts);app_useris reused by email,client_memberlinks the user to the client org.consumeBookingFormLinkrejects cancelled/ended bookings and re-checks org membership.
E4 · Admin dashboard ✅
- ✅ Required-actions hub at
/admin(the admin landing): four "needs action" cards — pending enquiries (with a waitlist badge), contracts to send, contracts awaiting response, deposits outstanding — plus an "upcoming events" column (confirmed, next 30 days). One read-onlygetAdminDashboardfunction (pikkuFunc,isAdminOrOwner) aggregates the buckets from existing booking / enquiry / invoice / contract data; each card row links to its workspace (enquiries list or booking detail). "Deposits outstanding" ≠ overdue — the 14-day deadline lands with E7.
E5 · File uploads (infra prerequisite for E3.3 + event images)
- ⬜ Upload invoices.
- ⬜ Upload public event images.
E6 · Multi-date / wishlist enquiries
- ⬜ 6.1 Enquiry form allows multiple date options, sorted by priority.
- ⬜ 6.2 "Wishlist" path when dates conflict: instead of approve→booking,
keep it as a wishlist with its own workspace table. (Builds on the existing
waitlisted_at.)
E7 · Post-confirmation editing rules + finalizing state
- ⬜ New lifecycle state
finalizing(badge "Finalizing"), entered automatically 14 days before start:confirmed → finalizing → ended. Add the enum value, afinalizing_atcolumn, and the auto-transition (cron). - ⬜ After confirmed, participants (count) / rooms (allocation) / diet are editable up to 14 days before the event starts.
- ⬜ Entering
finalizing(the 14-day mark) → auto-create a project/base invoice. - ⬜ Edits after the 14-day mark are still allowed but produce a differing (delta) invoice.
- ⬜ Allergies remain editable until the event ends, with no invoice change.
E8 · Rename completed → ended ✅
- ✅ Status value
completed→endedand columncompleted_at→ended_at, end-to-end (DB-first). Enum now:enquiry → reserved → confirmed → ended(+cancelled);finalizingslots in beforeendedlater via E7.
E9 · Unified public site chrome
- ⬜ Make the public enquiry / events / availability pages match the seminarhof-drawehn.de header + footer for one cohesive website/app feel.
Next up
Quick wins E8 + E2 are shipped. Suggested next sequence (per epic notes above): E5 (file uploads — unblocks E3.3) → E3 (contract + invoicing, incl. status-model redesign) → E4 (dashboard) → E6 / E7 / E9.