← Alle Projekte
Eisstock Soest (eisstock-soest.de)

Eisstock Soest – Buchungssystem für den Weihnachtsmarkt

Stundenweise buchbare Eisstockbahnen und beheizte Gondeln auf dem Soester Weihnachtsmarkt – mit Stripe-Anzahlung, Multi-Slot-Buchungen und einem Admin-Bereich für die Standcrew.

Laravel Livewire PHP Tailwind CSS

Idee

Auf dem Soester Weihnachtsmarkt gibt es zwei Eisstockbahnen und eine Reihe beheizter Gondeln, in denen sich Gruppen für ein, zwei Stunden in der Vorweihnachtszeit treffen können. Bisher lief die Reservierung über Mails und ein Excel auf dem Stand-Tablet. Das funktioniert genau so lange, bis ein Donnerstagabend voll ist und niemand mehr weiß, ob die Anfrage von Frau Schmidt jetzt bestätigt war oder nicht.

Daraus ist eisstock-soest.de geworden: ein schlankes Buchungssystem, das aus dem Telefon-Tetris einen normalen Online-Vorgang macht.

Was Besucher:innen tun

  • Termin und Uhrzeit auswählen, beliebig viele Stunden hintereinander oder verteilt über den Abend
  • Pro Slot Bahnen (0–2) und Gondeln (0–2) wählen
  • Optional Speisen/Getränke vorab einplanen
  • 50 % Anzahlung via Stripe Checkout, Rest am Stand
  • Bestätigungsmail mit Buchungsreferenz – an dieser Referenz zieht später die Standcrew die Reservierung in der Übersicht hoch

Wer alles auf 0 stellt (Bahnen, Gondeln, Essen) und nur ein Datum reserviert, wird trotzdem nicht durch den Bezahlflow geschickt – sondern direkt bestätigt.

Architektur-Entscheidungen, die was geändert haben

  • Eine Buchung kann mehrere Time-Slots umfassen. Statt jeder Stunde ihre eigene Reservierung zu geben, hängen alle Slots einer Buchung an derselben booking_reference. Die Bestätigungsmail fasst aufeinanderfolgende Slots automatisch zu Bereichen zusammen („2 Bahnen am 15.12. von 16:00–18:00 Uhr"), statt fünf separate Zeilen zu zeigen.
  • Optimistisch in der UI, pessimistisch beim Submit. Während der Auswahl zeigt Livewire die noch verfügbare Kapazität live an, ohne jeden Klick zu serialisieren. Beim eigentlichen Submit greifen lockForUpdate() auf den Time-Slots: erst dann wird die Kapazität nochmal hart geprüft und die Reservierung geschrieben. Das vermeidet Doppelbuchungen, ohne die UX langsam zu machen.
  • Doppelte Zeitzone, klar getrennt. Datenbank in UTC, Anzeige in Europe/Berlin. Eine Carbon-Macro inApplicationTimezone() ist die einzige Stelle, an der konvertiert wird – nirgendwo im Code rechnet jemand selbst mit Stunden.
  • Idempotente Confirmation-Mail. Stripe-Webhooks treffen schon mal doppelt ein. Das booking_confirmation_sent_at-Timestamp am Reservierungssatz ist die einzige Quelle der Wahrheit für „Mail ist raus" – nochmal versendet wird nichts.

Stack

Laravel 13, Livewire 4 mit Flux-Komponenten, Tailwind 4. Auth über Fortify inkl. 2FA für die Standcrew, Mailgun für die Zustellung, Stripe Checkout für die Anzahlung. Pest für die Tests, SQLite in der Entwicklung, MySQL im Betrieb.

Der Admin-Bereich hat drei Bildschirme: Time-Slots in Bulk anlegen (Datum von–bis × Uhrzeit von–bis), Reservierungen filtern nach Status/Bezahlung/Zeitraum und ein einfaches User-Management. Mehr braucht ein saisonaler Stand nicht.

Status

Live seit Frühjahr 2026, eingerichtet und für die Saison 2026 vorbereitet. Nächste Iteration: Storno-Handling über einen sicheren Link in der Bestätigungsmail und ein optionaler „Sammelrechnung am Saisonende"-Modus für den Veranstalter.

Diese Seite nutzt ausschließlich technisch notwendige Cookies. Kein Tracking, keine Werbung.