# Fit wie ein Fisch — Buchungstool

Spezifikation und Zielstruktur für das dritte Buchungssystem im KSB-Portal.

**Quelle:** `docs/Anforderungen Buchungstool Fit wie ein Fisch.docx`  
**Stand:** 2026-08-25  
**Status:** Phase 3 — Anmeldung speichern + Slot-API live; E-Mail folgt  
**Verwandte Systeme:** Schwimmcontainer (`/booking`), Bewegungszentrum (`/booking/courses`), Hub (`/buchung`)

---

## Einordnung im Gesamtsystem

| System | Öffentlicher Einstieg | Admin-Kontext | Technischer Slug |
|--------|----------------------|---------------|------------------|
| Schwimmcontainer | `/booking` | `admin_system = swim` | `swim` / `appointment` |
| Bewegungszentrum | `/booking/courses` … | `admin_system = bz` | `bz` / `course_booking` |
| **Fit wie ein Fisch** | **`/booking/fisch`** (geplant) | **`admin_system = fisch`** | **`fisch`** |
| Kreissportbund | extern | `admin_system = ksb` | `ksb` |

Bereits vorhanden:

- Öffentlicher Hub `/buchung` mit Card „Fit wie ein Fisch“ (aktuell externer Link `fit-fisch.de`)
- Admin-System-Switcher mit Farbe `#0e5f8a` und Platzhalter `admin/systems/fisch.html.twig`

Nach Umsetzung verweisen Hub-Card und Admin-Menü auf die internen Routen statt auf das externe Portal.

---

## Grundprinzip Dateistruktur

**Alle Dateien dieses Tools liegen in eigenen Ordnern bzw. tragen das Präfix `Fisch` / den Slug `fisch`.**

So bleiben Schwimm-, BZ- und Fisch-Code klar getrennt; gemeinsame Infrastruktur (Mailer, Security, Twig-Basis) wird wiederverwendet, **nicht** die fachlichen Entities der anderen Tools.

### Namenskonventionen

| Ebene | Muster | Beispiel |
|-------|--------|----------|
| Route (öffentlich) | `/booking/fisch/…` | `/booking/fisch/anmeldung` |
| Route (Admin) | `/admin/fisch/…` | `/admin/fisch/kurse` |
| Route-Namen | `fisch_*` / `admin_fisch_*` | `fisch_booking_step1`, `admin_fisch_courses_index` |
| Controller | `App\Controller\Fisch\…` / `App\Controller\Admin\Fisch\…` | `FischBookingController` |
| Entity | `Fisch*` | `FischCourse`, `FischRegistration` |
| Repository | `Fisch*Repository` | `FischCourseRepository` |
| Service | `App\Service\Fisch\…` | `FischCapacityService` |
| Twig (öffentlich) | `templates/fisch_booking/…` | `step1_landing.html.twig` |
| Twig (Admin) | `templates/admin/fisch/…` | `courses/index.html.twig` |
| CSS/JS | `public/css/fisch-*.css`, `public/js/fisch-*.js` | `fisch-booking-theme.css` |
| Migration | `Version…` + Kommentar „Fisch …“ | Tabellen `fisch_*` |
| E-Mail-Templates | Typen `FISCH_*` in eigener Admin-Seite | `/admin/fisch/email-templates/` |
| Console-Commands | `app:fisch:…` | `app:fisch:waitlist-offer` |

**Nicht mischen mit:** `Availability`, `Appointment`, `Course`, `CourseBooking`, `EventCenter*` — außer bewusst als Quelle für Wiederverwendungsmuster (Warteliste, Mail-Versand).

---

## Ziel-Verzeichnisbaum (Neu anzulegen)

```
src/
├── Controller/
│   ├── Fisch/
│   │   ├── FischBookingController.php          # Öffentlicher Flow
│   │   └── FischBookingApiController.php       # AJAX: freie Zeiten nach Geburtsdatum + Pool
│   └── Admin/Fisch/
│       ├── FischDashboardController.php
│       ├── FischCourseController.php           # Kursübersicht + Kapazität
│       ├── FischParticipantController.php      # Teilnehmerübersicht + Verschieben
│       ├── FischWaitlistController.php
│       ├── FischBulkRegistrationController.php # Sammelanmeldung / Reservierungslinks
│       ├── FischParentMailController.php       # Elternbriefe / Filter-Mail
│       └── FischEmailTemplateController.php
├── Entity/
│   ├── FischPool.php                           # Schwimmbad (6 Standorte)
│   ├── FischCourse.php                         # Pool + Uhrzeit + Altersgruppe + Kapazität
│   ├── FischRegistration.php                   # Anmeldung Kind + Eltern
│   ├── FischWaitlistEntry.php
│   ├── FischBulkRegistration.php                 # Kita / Sammelanmeldung
│   ├── FischBulkRegistrationLink.php
│   └── FischLandingContent.php                 # optional: editierbarer Infotext Startseite
├── Repository/
│   └── Fisch*.php
├── Service/Fisch/
│   ├── FischAgeGroupResolver.php               # 5–6 vs. 7–12 aus Geburtsdatum
│   ├── FischCapacityService.php                # Belegung, Sperre, Überbuchung verhindern
│   ├── FischCourseFilterService.php            # Freie Zeiten für Maske
│   ├── FischRegistrationService.php
│   ├── FischWaitlistService.php
│   ├── FischBulkRegistrationService.php
│   └── FischParentMailService.php
├── Form/Fisch/…
└── Command/
    └── FischSendCourseReminderCommand.php      # z. B. 1 Woche vor Start

templates/
├── fisch_booking/
│   ├── _layout.html.twig                       # Gemeinsames Layout (Hero, Footer, Partner)
│   ├── _fisch_assets.html.twig
│   ├── _fisch_partners.html.twig
│   ├── _fisch_footer.html.twig
│   ├── _landing_content_default.html.twig      # Standard-Begrüßung (fit-fisch.de)
│   ├── landing.html.twig                       # Startseite
│   ├── register.html.twig                      # Anmeldemaske
│   ├── thanks.html.twig
│   ├── waitlist.html.twig
│   └── waitlist_thanks.html.twig
└── admin/fisch/
    ├── dashboard/index.html.twig
    ├── courses/
    │   ├── index.html.twig                     # Abb. 1 — Kursübersicht
    │   └── participants.html.twig              # Kursteilnehmerliste
    ├── participants/
    │   └── index.html.twig                     # Abb. 2 — TN-Übersicht
    ├── waitlist/index.html.twig
    ├── bulk_registration/…
    ├── parent_mail/…
    └── email_templates/…

public/
├── css/
│   ├── fisch-booking-theme.css
│   └── fisch-admin.css
├── images/fisch/
│   ├── hero.png                                # Banner (von fit-fisch.de)
│   ├── logo-ksb.png
│   └── clients/ (Stadt Düren, AOK)
└── js/
    ├── fisch-booking-form.js                   # Geburtsdatum → Zeiten laden
    └── fisch-admin.js

migrations/
└── Version…_CreateFischBookingTables.php
```

---

## Funktionale Anforderungen

### 1. Öffentliche Startseite

- Aufbau **ähnlich wie bisher** (bestehendes Fit-wie-ein-Fisch-Portal als Referenz).
- **Informationstext für Eltern** — wünschenswert im Admin editierbar (`FischLandingContent` oder CMS-Feld).
- **Logos:** KSB + Sponsoren.
- Während der Anmeldephase: **Button zur Anmeldemaske** (Route z. B. `fisch_booking_register`).
- Anmeldephase steuerbar (Start/Ende im Admin oder per Konfiguration).

### 2. Anmeldemaske (Datenerfassung)

Alle Felder **Pflicht**, sofern nicht anders angegeben.

#### Kind

| Feld | Pflicht | Hinweis |
|------|---------|---------|
| Vorname | ja | |
| Nachname | ja | |
| Geburtsdatum | ja | **Optisch hervorgehoben**; freie Kursplätze erst danach sichtbar |
| Adresse | ja | |
| Telefonnummer | ja | |

#### Eltern / Erziehungsberechtigte

| Feld | Pflicht | Hinweis |
|------|---------|---------|
| E-Mail | ja | für Bestätigung / Infomails |
| Name Erziehungsberechtigte | ja | |

#### Gesundheit

- Auswahl **Ja / Nein** (Vorauswahl: **Nein**).
- Zusatzfeld „Gesundheitliche Einschränkungen“ nur bei **Ja** sichtbar und dann Pflicht.

#### Alterslogik (zentral, nicht manuell wählbar)

- Zielgruppe **5–6 Jahre** oder **7–12 Jahre** wird **automatisch** aus dem Geburtsdatum ermittelt.
- Eltern dürfen **keine Kursart selbst wählen** — verhindert Fehlbuchungen.
- UI-Hinweis: „Freie Kurszeiten werden nach Eingabe des Geburtsdatums angezeigt.“

#### Schwimmbad (6 Standorte)

1. Rurbad  
2. Goethestraße  
3. Birkesdorf  
4. Merken  
5. Derichsweiler  
6. Arnoldweiler  

#### Uhrzeit (Startzeiten)

`08:30`, `09:30`, `10:30`, `11:30`, `12:30`, `13:30`, `14:30`, `15:30`

#### Filterlogik (Kern)

```
Geburtsdatum + Schwimmbad
  → passende Altersgruppe
  → nur Kurse mit freien Plätzen
  → nur passende Startzeiten anzeigen
```

Volle Kurse (**12 Plätze**, Standard) werden **nicht** angeboten.

### 3. Absenden & Bestätigung

- Absenden nur bei vollständigen Pflichtfeldern.
- Nach Absenden: **Hinweisseite** im Browser.
- **Automatische Bestätigungs-E-Mail** an die Eltern.
- **Offen klären:** Bestätigungslink in der Mail wie bisher vs. reine Info-Mail (Aufwand abhängig).
- **Keine Überbuchung:** transaktionale Buchung mit Kapazitätsprüfung / pessimistischer Sperre (analog Wartelisten-Logik BZ/Swim).

### 4. Warteliste

- Wenn gewünschtes Schwimmbad **und/oder** alle passenden Uhrzeiten voll: Option **Warteliste**.
- **Vor Eintrag:** Präferenzen abfragen (Schwimmbäder, Uhrzeiten).
- Backend: Eintragsdatum nachvollziehbar („seit wann auf Warteliste“).
- Admin kann TN von Warteliste in Kurs verschieben.

### 5. Automatisierung (Pflicht)

| Regel | Umsetzung |
|-------|-----------|
| Max. 12 Plätze pro Kurs (Standard) | `FischCourse.maxCapacity`, Default 12 |
| Kurs voll → keine weitere Anmeldung | `FischCapacityService` + DB-Constraint / Lock |
| Volle Kurse in Maske ausblenden | Filter in `FischCourseFilterService` |
| Kapazität kurzfristig änderbar (10, 13, …) | Admin-Feld am Kurs, sofort wirksam |

---

## Backend-Anforderungen

### Kursübersicht (Abbildung 1)

- Liste aller Kurse mit **Auslastung** (z. B. `8/12`).
- Sortierung nach: **Uhrzeit**, **Standort**, **Zielgruppe**, **Auslastung**.
- **Kapazität pro Kurs editierbar** (kurzfristig 10, 13, …).
- Drill-down: **Kursteilnehmerliste** pro Kurs.
- **Excel-Export** der Teilnehmer mit **wählbaren Spalten** (Adresse optional).

### Teilnehmerübersicht (Abbildung 2)

- Alle Teilnehmer, alle Standorte, alle Uhrzeiten.
- Sortieren + **Schnellsuche** nach: Name, Vorname, Geburtsdatum, E-Mail, Schwimmbad, Anmeldezeit.
- **Bearbeiten** der Stammdaten.
- **Verschieben** in anderen Kurs (inkl. Kapazitätsprüfung).

### Warteliste (Admin)

- Filter: Name, Vorname, Alter, E-Mail.
- Anzeige Wartelisten-Datum.
- Aktion: in Kurs übernehmen.

### Sonderthemen

| Funktion | Beschreibung |
|----------|--------------|
| **Sammelanmeldung (Kitas)** | Kurs wählen, Plätze reservieren, Institution-E-Mail → Links per Mail; Plätze ab Reservierung blockiert |
| **Einzel-Anmeldelink** | Einem Elternteil Link für einen konkreten Kurs; Platz reserviert/blockiert |
| **Elternbriefe / Infomails** | An alle oder gefiltert (z. B. nur ein Schwimmbad); Anhänge (PDF); Versand **aus dem System**, nicht Outlook |
| **Kursarten umstellen** | Im Anmeldezeitraum Altersgrenzen anpassen (7–12 → 5–6 etc.) — Admin-Konfiguration pro Kurs oder global |

### Bonus (optional, Zeit abhängig)

- **Krankmeldung** durch Eltern — kann entfallen, wenn zu aufwendig.

---

## Öffentlicher Buchungsflow (Vorschlag)

```
/booking/fisch                    → Landing (Info, Logos, Button)
/booking/fisch/anmeldung          → Anmeldemaske
/booking/fisch/danke              → Bestätigung nach Absenden
/booking/fisch/warteliste         → Wartelisten-Formular
/booking/fisch/link/{token}       → Einzel-/Sammel-Anmeldelink

API (JSON):
/booking/fisch/api/slots          → GET: birthDate, poolId → freie Zeiten
/booking/fisch/api/register       → POST: Anmeldung
/booking/fisch/api/waitlist       → POST: Warteliste
```

Fortschrittsanzeige optional (einfacher als Schwimm-5-Schritte-Flow).

---

## Admin-Routen (Vorschlag)

```
/admin/fisch                           → Dashboard
/admin/fisch/kurse                     → Kursübersicht
/admin/fisch/kurse/{id}/teilnehmer     → Kursteilnehmer
/admin/fisch/teilnehmer                → Gesamt-Teilnehmer
/admin/fisch/warteliste
/admin/fisch/sammelanmeldung
/admin/fisch/elternbriefe
/admin/fisch/email-templates
/admin/fisch/einstellungen             → Landing-Text, Anmeldephase, Sponsoren-Logos
```

Menü in `admin_base.html.twig` unter `{% elseif admin_system == 'fisch' %}` erweitern (Platzhalter „Portal öffnen“ entfernen).

---

## Admin-Menü — Altes System (Referenz)

Quelle: Sidebar des bisherigen Fit-wie-ein-Fisch-Portals (`fit-fisch.de`), Screenshot 2026-08-25.

### Struktur (Original)

| Bereich | Menüpunkt | Kurzbeschreibung (vermutlich) |
|---------|-----------|--------------------------------|
| — | **Dashboard** | Übersicht / Kennzahlen |
| **Kursverwaltung** | **Kurse** | Kursübersicht, Auslastung, Kapazität |
| | **Teilnehmer** | Alle Teilnehmer, bearbeiten, verschieben |
| | **Warteliste** | Wartelisten-Einträge, in Kurs übernehmen |
| | **Übungsleiter** | Kursleiter / Personal am Becken |
| | **Anwesenheit täglich** | Tages-Anwesenheit / Check-in |
| **Standortverwaltung** | **Standorte** | Schwimmbäder (Rurbad, Goethestraße, …) |
| | **Standortkategorien** | Gruppierung/Kategorien der Standorte |
| **Einstellungen** | **Grundeinstellungen** | Saison, Anmeldephase, Landing-Text |
| | **Benutzer** | Admin-Benutzer des Fisch-Systems |
| | **Mandanten** | Multi-Mandant (falls genutzt) |
| | **Textvorlagen** | E-Mail-/Elternbrief-Vorlagen |
| | **Sammelanmeldung** | Kita-Links, reservierte Plätze |

### Abgleich mit neuem System (Stand 2026-08-25, Abend)

| Alt | Neu (Route / Status) |
|-----|----------------------|
| Dashboard | `/admin/fisch` — **live** |
| Kurse | `/admin/fisch/kurse` — **live** (DB) |
| Teilnehmer | `/admin/fisch/teilnehmer` — **live** (DB) |
| Warteliste | `/admin/fisch/warteliste` — **live** (DB, Aktionen folgen) |
| Übungsleiter | `/admin/fisch/uebungsleiter` — **Platzhalter** |
| Anwesenheit täglich | `/admin/fisch/anwesenheit` — **Platzhalter** |
| Standorte | `/admin/fisch/standorte` — **Anzeige** (`fisch_pool`, CRUD folgt) |
| Standortkategorien | `/admin/fisch/standortkategorien` — **Anzeige** (A/B aus Grundeinstellungen) |
| Grundeinstellungen | `/admin/fisch/grundeinstellungen` — **live** (`fisch_season_config`) |
| Benutzer | KSB-weit unter `/admin` — **getrennt halten** |
| Mandanten | — **entfällt** (nur KSB Düren) |
| Textvorlagen | `/admin/fisch/email-templates` — **Platzhalter** (Menü: Textvorlagen) |
| Sammelanmeldung | `/admin/fisch/sammelanmeldung` — **Platzhalter** |
| *(zusätzlich neu)* | Elternbriefe — `/admin/fisch/elternbriefe` |

**Sidebar:** umgesetzt in `admin_base.html.twig` — Abschnitte *Kursverwaltung*, *Standortverwaltung*, *Einstellungen*, *Portal*.

---

## Admin-Oberflächen — Altes System (Screenshots 2026-08-25)

Impressionen vom bisherigen Portal (`fit-fisch.de` / Kreissportbund Düren). Gemeinsames UI-Muster: **DataTables** mit Spaltenfiltern, Excel-Export, Pagination, Breadcrumbs `Admin / …`.

### Kurse

| Element | Details |
|---------|---------|
| Spalten | ID, **Start**, **Ende**, Standort, Dauer (min.), **Zielgruppe**, Kapazität, **Auslastung** (z. B. `10/12`), Menü |
| Zielgruppe | **A** = Kinder 5–6 · **B** = Kinder 6–11 (siehe Standortkategorien) |
| Aktionen | Bearbeiten, Duplizieren, Löschen |
| Toolbar | Zeilenanzahl, Excel-Download, „Kurs erstellen“, Suche |
| Beispiel | Merken, 45 min, Kapazität 12, Auslastung 10/12 |

→ Neu: Kurse als **Pool + Uhrzeit + Altersgruppe** (Saison), Auslastung live; Start/Ende/Dauer pro Saison noch offen.

### Teilnehmer

| Element | Details |
|---------|---------|
| Spalten | **Anwesend** (Icon Ja/Nein + Fisch-Symbol), Nachname, Vorname, Geburtsdatum, PLZ, Ort, E-Mail, **Start**, Standort, **Einrichtung (Kita/Schule)**, Eingetragen am, Menü |
| Toolbar | Excel, „Teilnehmer erstellen“, Suche |
| Umfang | Beispiel: **596 Einträge** |
| Besonderheit | Spalte **Anwesend** — Tages-Anwesenheit direkt in der Liste |

→ Neu: Kernfelder vorhanden; PLZ/Ort/Einrichtung/Anwesenheit noch ergänzen.

### Warteliste

| Element | Details |
|---------|---------|
| Spalten | ID, Nachname, Vorname, Geburtsdatum, **Gewünschter Standort**, Ort, E-Mail, Mobilfunknummer, Eingetragen am, Menü |
| Aktionen | Info, **Wechsel/Verschieben** (in Kurs?), Löschen |
| Toolbar | Excel, Suche; Button **„Erinnerung“** (unten links) |
| Umfang | Beispiel: **194 Einträge** |

→ Neu: Einträge + Präferenzen in DB; Verschieben, Erinnerungs-Mail offen.

### Übungsleiter*innen

| Element | Details |
|---------|---------|
| Spalten | ID, Nachname, Vorname, Geburtsdatum, Mobilfunknummer, E-Mail, Menü |
| Aktionen | Ansehen, Bearbeiten, E-Mail, Löschen |
| Toolbar | Excel, „Übungsleiter*in erstellen“ |

→ Neu: Modul **noch nicht** angelegt (`FischInstructor` o. ä.).

### Standorte

| Element | Details |
|---------|---------|
| Spalten | ID, Name, Beschreibung, Menü (Bearbeiten/Löschen) |
| Beispiele | Arnoldsweiler, Birkesdorf, Derichsweiler, Goethestraße, Merken, **Rurbad 1**, **Rurbad 2** |
| Beschreibungen | z. B. „Lehrschwimmbecken an der Grundschule“, „Schwimmbad Goethestraße“ |
| Toolbar | Excel, „Standort erstellen“ |

→ Neu: `fisch_pool` (6 Bäder, **Rurbad nur einmal** — ggf. Alt-Daten zusammenführen).

### Standortkategorien (= Altersgruppen)

| ID | Name | Beschreibung | Alter min | Alter max |
|----|------|--------------|-----------|-----------|
| 1 | **A** | Kinder zwischen 5 und 6 | 4,50 | 6,99 |
| 2 | **B** | Kinder zwischen 6 und 11 | 7,00 | 11,00 |

→ Neu: Entspricht `FischCourse::AGE_GROUP_5_6` / `7_12`; Dezimalalter für Grenzfälle prüfen.

### Grundeinstellungen (Key-Value)

Einzelne Zeilen mit **Speichern**-Button pro Key:

| Key | Beispielwert | Bedeutung |
|-----|--------------|-----------|
| `portal_open_from` | 15.09.2023 00:00 | Anmeldephase Start |
| `portal_open_to` | 12.10.2023 23:59 | Anmeldephase Ende |
| `alter_von` | 6 | Mindestalter (Portal) |
| `alter_bis` | 12 | Höchstalter (Portal) |
| `kurs_start` | 2023-10-23 00:00:00 | Kurszeitraum Start |
| `kurs_ende` | 2023-10-24 08:45:00 | Kurszeitraum Ende |

→ Neu: **`/admin/fisch/grundeinstellungen`** — live; Anmeldung prüft zusätzlich Datumsfenster.

### Textvorlagen

- Accordion nach **Mandant** (z. B. „Kreissportbund Düren“, „Heinsberg“) mit Badge **Aktiv**
- Typen z. B. **„Startseite Begrüßung“** — langer HTML/Text für Landingpage
- Aktionen: Bearbeiten, Löschen; Button „Neue Textvorlage erstellen“
- Beispieltext: Kooperation KSB/Stadt Düren/AOK, 630 Plätze, Herbstferien 2023

→ Neu: `/admin/fisch/email-templates` + Landing-Text; Mandanten-Struktur vermutlich entfällt (nur KSB).

### Sammelanmeldung

Formular (Kita/Schule):

| Feld | Pflicht |
|------|---------|
| Einrichtung (Kita/Schule) | ja |
| E-Mail der Einrichtung | ja |
| Standort (Dropdown) | ja |
| Kurstermine (Dropdown) | ja |
| Anzahl (Plätze) | ja |

→ Absenden erzeugt Links/E-Mails an Institution; Plätze reserviert. Neu: Platzhalter-Seite, Logik in `fisch_bulk_registration` vorbereitet.

### UI-/Technik-Merkmale (Alt)

- Dunkle Sidebar, helle Content-Fläche, blauer Active-State
- Breadcrumb: `Admin / [Seite]`, Header „Kreissportbund Düren“
- Tabellen: Sortierung, **Filterzeile** unter Spaltenköpfen, Pagination
- Durchgängig **Excel-Export** auf Listen-Seiten

---

## Datenmodell (Skizze)

### `fisch_pool`

| Spalte | Typ | Beschreibung |
|--------|-----|--------------|
| id | int | PK |
| name | string | z. B. „Rurbad“ |
| slug | string | `rurbad` |
| sort_order | int | Anzeige |
| is_active | bool | |

### `fisch_course`

| Spalte | Typ | Beschreibung |
|--------|-----|--------------|
| id | int | PK |
| pool_id | FK | Schwimmbad |
| start_time | time | z. B. 08:30 |
| age_group | enum | `5_6` \| `7_12` |
| max_capacity | int | Default 12 |
| season_year | int | z. B. 2026 |
| is_active | bool | |

Unique: `(pool_id, start_time, age_group, season_year)`.

### `fisch_registration`

Kind + Eltern + FK `course_id` + Timestamps + optional `verified_at` (falls Bestätigungslink).

### `fisch_waitlist_entry`

Kind-Daten + Präferenzen (Pools, Zeiten JSON) + `created_at`.

### `fisch_bulk_registration` / `fisch_bulk_registration_link`

Reservierte Plätze, Institution, generierte Tokens, Ablauf.

---

## Wiederverwendung aus dem bestehenden Projekt

| Baustein | Vorbild im Projekt | Anmerkung |
|----------|-------------------|-----------|
| Warteliste + Claim | `AppointmentWaitlistService`, BZ-Warteliste | FIFO, `--dry-run`-Commands |
| E-Mail-Versand | Symfony Mailer + Template-Entity | eigene `FISCH_*`-Typen |
| Admin-System-Switch | `AdminSystemController`, `admin_base.html.twig` | bereits `fisch` |
| Hub-Card | `public_booking_hub.html.twig` | Link auf `fisch_booking_landing` |
| Kapazität / Lock | Wartelisten-Automatisierung 2026-07-20 | pessimistische Sperre |
| Excel-Export | BZ/Swim-Export-Patterns | PhpSpreadsheet o. ä. |
| Asset-Pfade | `asset('css/fisch-…')` | **nie** hardcoded `/css/` |

**Bewusst nicht teilen:** Kurs-Entities des BZ, Availability/Appointment des Schwimmcontainers.

---

## E-Mail-Typen (Vorschlag)

| Typ | Auslöser |
|-----|----------|
| `FISCH_REGISTRATION_CONFIRM` | Anmeldung abgeschickt |
| `FISCH_REGISTRATION_VERIFY` | optional: Link bestätigen |
| `FISCH_WAITLIST_CONFIRM` | Wartelisten-Eintrag |
| `FISCH_WAITLIST_OFFER` | Platz frei → Angebot |
| `FISCH_COURSE_REMINDER` | ca. 1 Woche vor Start (+ PDF) |
| `FISCH_INFO_BROADCAST` | Admin-Elternbrief (gefiltert) |
| `FISCH_BULK_REGISTRATION` | Kita-Links |

Admin-UI: `/admin/fisch/email-templates/` — **nicht** in Termin- oder Event-Center-Templates mischen.

---

## Offene Klärungspunkte

1. **Bestätigungslink in E-Mail** — beibehalten (Double-Opt-In) oder nur Info-Mail?
2. **Saison / Jahr** — ein Anmeldezeitraum pro Kalenderjahr oder festes Datum?
3. **Sponsoren-Logos** — fest im Template oder im Admin uploadbar?
4. **Migration Bestandsdaten** — Import aus altem `fit-fisch.de`-System nötig?
5. **Krankmeldung** — in v1 enthalten oder Backlog?

---

## Umsetzungsphasen (Empfehlung)

### Phase 1 — MVP Anmeldung

- Entities + Migration
- Landing + Anmeldemaske + Kapazitätslogik
- Bestätigungsmail
- Admin: Kursübersicht + Teilnehmerliste + Export

### Phase 2 — Warteliste & Verschieben

- Warteliste öffentlich + Admin
- TN bearbeiten / Kurs wechseln

### Phase 3 — Sammelanmeldung & Elternbriefe

- Kita-Links, Reservierungen
- Gefilterter Mailversand mit Anhang

### Phase 4 — Feinschliff

- Editierbarer Landing-Text
- Kursarten-Anpassung im laufenden Betrieb
- optional Krankmeldung

---

## Referenzen im Repository

| Datei | Relevanz |
|-------|----------|
| `docs/Anforderungen Buchungstool Fit wie ein Fisch.docx` | Original-PDF/Word mit Screenshots |
| `templates/public_booking_hub.html.twig` | Hub-Card anpassen |
| `templates/admin/systems/fisch.html.twig` | Platzhalter ersetzen |
| `src/Controller/Admin/AdminSystemController.php` | System `fisch` |
| `templates/admin_base.html.twig` | Admin-Navigation |
| `docs/WARTELISTEN_TESTMATRIX.md` | Testmuster Warteliste |
| `docs/CRONJOBS.md` | Cron für Erinnerungsmails / Warteliste |

---

## Checkliste vor Go-Live

- [ ] Hub `/buchung` → interner Link statt `fit-fisch.de`
- [ ] Überbuchungstest (parallele Anmeldungen, Lasttest)
- [ ] Excel-Export mit/ohne Adresse geprüft
- [ ] E-Mail-Templates in Admin pflegbar
- [ ] `php bin/console cache:clear` nach Deploy
- [ ] Datenschutz: Einwilligung / Hinweise auf Startseite
