chore: seminarhof customer project

This commit is contained in:
e2e
2026-07-10 23:45:12 +02:00
commit 5a060fd8f2
188 changed files with 20779 additions and 0 deletions

View File

View File

@@ -0,0 +1,102 @@
@admin @bookings
Feature: Admin booking detail — read & edit
The admin booking-detail page replaces the spreadsheet admins must be able
to *edit* every column they used to edit, not just look at it.
Background:
Given "the admin" is logged in
When they visit "/admin/bookings/b_yoga_2026_summer"
# ── Read ────────────────────────────────────────────────────────────────
Scenario: admin opens the summer retreat detail
Then they see "Summer Yoga Retreat 2026"
And they see "Yoga Retreat e.V."
And they see "Teilnehmende"
Scenario: admin sees the seeded participant list
When they click "Teilnehmende"
Then they see "Anja Weber"
And they see "Bernd Krause"
# ── Edit booking metadata ───────────────────────────────────────────────
Scenario: admin edits the course name and persists across reload
When they fill "courseName" with "Summer Yoga Retreat 2026 revised"
And they click "Änderungen speichern"
Then they see "Gespeichert"
When they visit "/admin/bookings/b_yoga_2026_summer"
Then they see "Summer Yoga Retreat 2026 revised"
Scenario: admin updates expected participants
When they fill "expectedPersons" with "32"
And they click "Änderungen speichern"
Then they see "Gespeichert"
Scenario: admin toggles half-house and online listing flags
When they select "Ja" from "halfHouse"
And they select "Ja" from "onlineAd"
And they click "Änderungen speichern"
Then they see "Gespeichert"
Scenario: admin cannot save when no field changed
Then they see "Änderungen speichern"
# Save button is disabled until a field is touched — clicking has no effect.
# ── Edit organisation ──────────────────────────────────────────────────
Scenario: admin edits organisation contact email and phone
When they fill "organisation-email" with "ops@yoga-retreat.example"
And they fill "organisation-phone" with "+49 30 12345678"
And they click "Organisation speichern"
Then they see "Organisation gespeichert"
When they visit "/admin/bookings/b_yoga_2026_summer"
Then the field "organisation-email" has value "ops@yoga-retreat.example"
And the field "organisation-phone" has value "+49 30 12345678"
Scenario: organisation save rejects an invalid email
When they fill "organisation-email" with "not-an-email"
And they click "Organisation speichern"
Then they do not see "Organisation gespeichert"
# ── Booking status transitions ─────────────────────────────────────────
Scenario: admin cancels a booking
# ConfirmButton: first click arms, second click (testid `-confirm`) fires.
When they trigger booking action "action-cancel-booking"
Then they see "Storniert"
And they do not see "Buchung stornieren"
# ── Participants CRUD ──────────────────────────────────────────────────
Scenario: admin adds a participant
When they click "Teilnehmende"
And they fill "new-participant-name" with "Ingrid Vogel"
And they click "Hinzufügen"
Then they see "Ingrid Vogel"
Scenario: admin removes a participant
When they click "Teilnehmende"
And they accept the next confirmation
And they click "remove-participant-p_s_08"
Then they do not see "Hans Becker"
Scenario: admin changes a participant's diet
When they click "Teilnehmende"
And they select "Pescetarisch" from "participant-diet-p_s_06"
Then the field "participant-diet-p_s_06" has value "Pescetarisch"
# ── Allergies CRUD ─────────────────────────────────────────────────────
Scenario: admin adds an allergy to a participant
When they click "Teilnehmende"
And they fill "new-allergy-p_s_02" with "shellfish"
And they click "add-allergy-p_s_02"
Then they see "Meeresfrüchte"
Scenario: admin removes an existing allergy
When they click "Teilnehmende"
And they click "remove-allergy-p_s_01-nuts"
Then they do not see "nuts"
# ── Rooms assign / unassign ────────────────────────────────────────────
Scenario: admin assigns and then unassigns a participant to a room
When they click "Zimmer"
And they select "Anja Weber" from "assign-room-r_1"
Then they see "Anja Weber"
When they click "Entfernen"
Then the field "assign-room-r_1" has value ""

View File

@@ -0,0 +1,39 @@
@auth
Feature: Authentication
Users authenticate with email + password. Sessions are cookie-based.
Roles (client / admin / owner) gate access to portals.
Scenario: client logs in and lands on their portal
When "the client" logs in
Then the URL contains "/"
And they see "Seminarhof Drawehn"
Scenario: admin logs in and reaches the admin bookings list
When "the admin" logs in
And they visit "/admin/bookings"
Then they see "Buchungen"
And they see "Summer Yoga Retreat"
Scenario: owner logs in and reaches the admin bookings list
When "the owner" logs in
And they visit "/admin/bookings"
Then they see "Buchungen"
Scenario: wrong password is rejected
Given "the client" visits "/login"
When they fill "input[type=email]" with "demo@yoga-retreat.example"
And they fill "input[type=password]" with "wrong-password"
And they click "Anmelden"
Then they see "E-Mail oder Passwort ist falsch."
Scenario: client is redirected away from the admin portal
When "the client" logs in
And they visit "/admin/bookings"
Then the URL does not contain "/admin/"
Scenario: logout clears the session
Given "the client" is logged in
When they visit "/logout"
Then they see "Sie wurden abgemeldet. Bis bald."
When they click "Zurück zur Anmeldung"
Then the URL contains "/login"

View File

@@ -0,0 +1,8 @@
@public @availability
Feature: Public availability calendar
Visitors can see which days the venue is free to book.
Scenario: visitor opens the availability calendar
Given "a visitor" visits "/availability"
Then they see "Seminarhof Drawehn"
And they see "2026"

View File

@@ -0,0 +1,43 @@
@booking @flow
Feature: Full booking flow — enquiry through confirmed
A client submits an enquiry via the public form. The admin then drives
the booking through every step: approval, contract, deposit, confirmation.
# Guest: submit enquiry
Scenario: client submits an enquiry via the public form
Given "a guest" visits "/enquiry"
When they fill "courseName" with "E2E Full Flow Test"
And they fill "startDate" with "2028-06-15"
And they fill "endDate" with "2028-06-22"
And they fill "organisationName" with "E2E Organisation"
And they fill "contactEmail" with "e2e@example.com"
And they turn on "agbAccepted"
And they turn on "privacyAccepted"
And they click "Anfrage absenden"
Then they see "Ihre Anfrage ist eingegangen"
# ── Admin: full flow from enquiry to confirmed ──────────────────────────
Scenario: admin drives a booking from enquiry through to confirmed
Given the app data is reset
And "the admin" is logged in
# 1. Open the seeded enquiry directly
When they visit "/admin/bookings/b_lc_enquiry"
# 2. Approve the enquiry → reserved
When they trigger booking action "action-approve-enquiry"
Then they see "Reserviert"
And the audit log tab includes "Reservierung bestätigt"
# 3. Send the contract manually (bypasses the 365-day cron window)
When they trigger booking action "action-send-contract"
Then the audit log tab includes "Vertrag & Anzahlungsrechnung"
# 4. Record the client's contract signature
When they trigger booking action "action-contract-approved"
Then they see "Anzahlung als erhalten markieren"
# 5. Record the deposit received → confirmed
When they trigger booking action "action-deposit-received"
Then they see "Bestätigt"
And the audit log tab includes "Buchung bestätigt"

View File

@@ -0,0 +1,26 @@
@admin @lifecycle
Feature: Booking lifecycle — rule-based cron assertions
Verifies each cron rule fires against pre-seeded bookings whose dates are
computed relative to today in testReset, so the rules always trigger.
Background:
Given the app data is reset
And "the admin" is logged in
# ── R1: contract + deposit email ────────────────────────────────────────
Scenario: lifecycle R1 — cron sends contract and deposit email to a reserved booking
# b_lc_reserved: reserved, no contractSentAt, startDate 200 days away
Then the lifecycle cron sent 1 contracts
And the audit log for "b_lc_reserved" includes "Vertrag & Anzahlungsrechnung"
# ── R2: deposit reminder ─────────────────────────────────────────────────
Scenario: lifecycle R2 — cron sends deposit reminder when deposit is 7+ days unpaid
# b_lc_contract_sent: contractSentAt 8 days ago, deposit invoice unpaid
Then the lifecycle cron sent 1 reminders
And the audit log for "b_lc_contract_sent" includes "Anzahlungserinnerung"
# ── R4: auto-complete ────────────────────────────────────────────────────
Scenario: lifecycle R4 — cron auto-completes a confirmed booking after it ends
# b_lc_confirmed: confirmed, endDate yesterday
Then the lifecycle cron completed 1 bookings
And the booking "b_lc_confirmed" has status "Beendet"

View File

@@ -0,0 +1,13 @@
@public @events
Feature: Public events listing
Anyone can browse the public retreats listing without logging in. Only
bookings flagged for online listing appear here.
Scenario: visitor sees the published summer retreat
Given "a visitor" visits "/events"
Then they see "Summer Yoga Retreat 2026"
And they see "Yoga Retreat e.V."
Scenario: unpublished retreats stay hidden
Given "a visitor" visits "/events"
Then they do not see "Winter Stille 2026"

View File

@@ -0,0 +1,30 @@
@admin @invoices
Feature: Invoice creation and payment recording
Admin issues invoices against a booking and records payments when they
arrive. Both actions create audit trail entries.
Background:
Given "the admin" is logged in
When they visit "/admin/bookings/b_yoga_2026_summer"
And they click "Rechnungen"
Scenario: admin creates a final invoice
When they create an invoice numbered "2026-FIN-002" for 1500.00
Then they see "2026-FIN-002"
And they see "Offen"
Scenario: admin creates an invoice with an attached PDF
When they attach invoice PDF "invoice-sample.pdf"
And they create an invoice numbered "2026-PDF-001" for 500.00
Then they see "PDF öffnen"
Scenario: admin records a payment on an outstanding invoice
When they create an invoice numbered "2026-PAY-001" for 250.00
And they mark invoice "2026-PAY-001" as paid on "2026-05-10"
Then they see "Bezahlt"
Scenario: admin cancels an outstanding invoice
When they create an invoice numbered "2026-CXL-001" for 100.00
And they accept the next confirmation
And they click "invoice-cancel-2026-CXL-001"
Then they see "Storniert"