Files
seminarhof-e2e-mqowtqw3/apps/app/src/specs.md
2026-06-22 09:44:35 +02:00

6.8 KiB

Seminarhof — product backlog

Status legend: done · 🟡 partial · todo · 🔮 phase 2


Shipped

  • Enquiry table. Public enquiries land in enquiry (not booking). Admin view at /admin/enquiries with 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 reserved booking linked via booking.enquiry_id.
  • organizationclient rename (+ client_member already models multiple login users per client; one is seeded from the enquiry email).
  • courseevent rename 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 enquiry status on public availability — show it to admins/owners only. getAvailability reads 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. getAvailability returns a per-day bookings[] (deterministic order); availability.tsx renders the diagonal linear-gradient split 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. BookingStatusPanel is 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 raw window.confirm for 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 provisioned client user, and fills name/company, billing address, phone, website, payment method (Cash / bank transfer), event basics + AGB/privacy consents. Submit is legally binding (stamps contractResponse='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 inside reserved, shown as a timeline in BookingStatusPanel.

    Auth note: the magic link issues the same DB-session as password login (reuses lib/session.ts); app_user is reused by email, client_member links the user to the client org. consumeBookingFormLink rejects 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-only getAdminDashboard function (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, a finalizing_at column, 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 completedended

  • Status value completedended and column completed_atended_at, end-to-end (DB-first). Enum now: enquiry → reserved → confirmed → ended (+ cancelled); finalizing slots in before ended later 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.