Neuaufbau der Website für **HMS Licht & Ton GbR** (Hammerschmidt u. Mössle GbR), Veranstaltungstechnik aus Leipheim/Ellzee. Die bestehende WordPress-Website wird durch eine moderne, mobile-first Web-Anwendung ersetzt. Kern-Neuheit ist ein **Online-Mietkatalog** mit Rentman-Integration (Equipment-Import + Mietanfragen an Rentman).
7. Design: **Grautöne als Hauptfarbschema** + oranges Logo (SVG von bestehender Website übernehmen)
---
## 3. Funktionale Anforderungen
### [F-HMS-01] Home / Startseite
**Anforderung:** Startseite mit Hero-Bereich, Unternehmensbeschreibung (20 Jahre Erfahrung, Full Service, Alles aus einer Hand), Leistungsübersicht (Vermietung, Verkauf, Personal, Transport, Lagerung, Werkstatt, Installation, Booking), Vermietungs-Info-Bereich (großer Materialbestand, Selbstabholung/Lieferung/DryHire, Verweis auf Online-Mietkatalog), Adress-/Kontaktdaten im Footer-Bereich.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User navigiert zu '/'. Erwartet: Hero-Bereich mit Headline 'Ihr professioneller Partner für Veranstaltungstechnik' sichtbar, 'Über uns'-Sektion mit 20 Jahre Erfahrung, Full Service, Alles aus einer Hand sichtbar, Leistungsübersicht mit allen 8 Leistungen sichtbar, Link zum Mietkatalog sichtbar und klickbar.
2.**Edge Case:** User lädt Seite mit langsamer Verbindung. Erwartet: Text-Inhalte erscheinen sofort (SSR/SSG), Bilder laden lazy mit Placeholder, keine Layout-Shifts (CLS < 0.1).
3.**Mobile:** Seite auf 375px Breite (iPhone SE). Erwartet: Alle Sektionen untereinander, Hero-Text lesbar, Leistungs-Icons/Texte nicht abgeschnitten, Touch-Targets min 44x44px.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Manuelle Verifikation: Alle Inhalte der alten Home-Seite (außer 'Neu in der Vermietung') sind vorhanden
- Lighthouse Mobile Score >= 90
---
### [F-HMS-02] Referenzen / Bildergalerie
**Anforderung:** Bildergalerie-Seite mit Überschrift 'Bilder / Referenzen', 'Machen Sie sich ein Bild von unserer Arbeit', 'Impressionen vorangegangener Events'. Bilder in Grid-Anordnung, Klick öffnet Lightbox/Vollbildansicht. Bilder sind statisch (kein CMS), werden vom Backend verwaltet.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User navigiert zu '/referenzen'. Erwartet: Galerie lädt mit mindestens 8 Bildern, Grid-Layout sichtbar, Klick auf ein Bild öffnet Lightbox mit Navigation (prev/next/close).
2.**Edge Case:** Bild kann nicht geladen werden (defekte URL). Erwartet: Fallback-Placeholder wird angezeigt, keine weiße Lücke, keine JS-Fehler.
3.**Mobile:** Galerie auf 375px. Erwartet: 1-2 Spalten Grid, Bilder quadratisch oder aspect-ratio konsistent, Lightbox funktionsfähig mit Swipe-Gesten.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Lightbox öffnet/schließt korrekt
- Bilder laden mit lazy-loading
---
### [F-HMS-03] Kontaktseite mit Formular
**Anforderung:** Kontaktseite mit: Überschrift 'Planen Sie eine Veranstaltung?', Anschrift (Büro: Grockelhofen 10, 89340 Leipheim; Lager: Zur Schönhalde 8, 89352 Ellzee), Öffnungszeiten (Mon–Fr: 10:00–18:00), Google Maps Link 'Route planen', Kontaktdaten (Telefon, E-Mail), Ansprechpartner (Leopold Hammerschmidt +49 172 6264796, Andreas Mössle +49 173 9014604), Social Links (Facebook, Instagram), Kontaktformular (Name, E-Mail, Telefon, Nachricht, DSGVO-Einwilligung).
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User füllt Kontaktformular aus (Name='Test User', E-Mail='test@example.com', Nachricht='Test anfrage') und sendet ab. Erwartet: Form wird validiert, Success-Message erscheint, E-Mail wird an info@hms-licht-ton.de gesendet.
2.**Edge Case:** User sendet Formular ohne E-Mail-Adresse. Erwartet: Validierung zeigt Fehlermeldung, keine E-Mail wird gesendet, Form bleibt ausgefüllt.
3.**Edge Case:** User sendet Formular ohne DSGVO-Häkchen. Erwartet: Validierung blockiert Submit, Fehlermeldung 'Bitte akzeptieren Sie die Datenschutzerklärung'.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- E-Mail-Empfang manuell verifiziert
- DSGVO-Einwilligung Pflichtfeld
- Form-Validation serverseitig UND clientseitig
---
### [F-HMS-04] Mietkatalog – Equipment-Liste
**Anforderung:** Katalog-Seite '/mietkatalog' mit allen Equipment-Artikeln aus Rentman. Darstellung als Grid- oder Listen-Ansicht mit: Artikelname, Artikelnummer, Kategorie, Thumbnail-Bild (falls vorhanden), Kurzbeschreibung. Pagination oder Infinite-Scroll bei vielen Artikeln. Jeder Artikel ist klickbar → Detailansicht.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User navigiert zu '/mietkatalog'. Erwartet: Liste lädt mit >=10 Artikeln, jeder Artikel zeigt Name + Kategorie, Klick auf Artikel öffnet Detailseite.
2.**Edge Case:** Rentman API nicht erreichbar beim Laden. Erwartet: Cached/zwischengespeicherte Daten werden angezeigt, Warnhinweis 'Katalog wird aktuell aktualisiert' sichtbar, keine leere Seite.
3.**Performance:** Katalog mit 500+ Artikeln. Erwartet: Erste 20 Artikel in <2s geladen, Pagination/Infinite-Scroll funktional, keine Browser-Freezes.
1.**Happy Path:** User klickt auf Artikel in Katalog. Erwartet: Detailseite lädt mit Name, Beschreibung, Bild, 'Mietanfrage'-Button sichtbar und klickbar.
2.**Edge Case:** Artikel-ID existiert nicht. Erwartet: 404-Seite mit 'Artikel nicht gefunden' + Link zurück zum Katalog.
3.**Integration:** User klickt 'Mietanfrage'. Erwartet: Artikel wird zum Anfrage-Warenkorb hinzugefügt, Toast-Bestätigung sichtbar, Warenkorb-Counter aktualisiert.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Detail-Daten korrekt aus Backend/CACHE
- Mobile: Alle Informationen lesbar
---
### [F-HMS-06] Mietkatalog – Search & Filter
**Anforderung:** Such- und Filterfunktion im Mietkatalog: Freitext-Suche (Artikelname, -nummer), Kategorie-Filter (Dropdown/Tags), Sortierung (Name A-Z, Name Z-A). Filter kombinierbar. Resultat-Anzahl sichtbar. Filter-Reset-Button.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User gibt 'Lautsprecher' in Suchfeld ein. Erwartet: Liste filtert in Echtzeit auf Artikel mit 'Lautsprecher' im Namen, Resultat-Anzahl aktualisiert.
3.**Integration:** User kombiniert Suche 'PA' + Kategorie-Filter 'Ton'. Erwartet: Nur Artikel der Kategorie 'Ton' mit 'PA' im Namen werden angezeigt.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Filter kombinierbar
- Mobile: Filter in Collapse/Drawer erreichbar
- Suchergebnis <500ms
---
### [F-HMS-07] Mietkatalog – Mietanfrage-Formular
**Anforderung:** Mietanfrage-Formular '/mietanfrage' mit: ausgewählte Artikel (aus Warenkorb) mit Menge, Veranstaltungsdaten (Name, Datum von/bis, Ort, Anzahl Personen), Kontaktdaten (Name, Firma, E-Mail, Telefon, Adresse), Nachricht. Submit sendet Anfrage an Rentman via POST /projectrequests + POST /projectrequests/{id}/projectrequestequipment.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User hat 3 Artikel im Warenkorb, füllt Veranstaltungsdaten + Kontaktdaten aus, sendet ab. Erwartet: POST /projectrequests wird gesendet, Equipment wird via POST /projectrequests/{id}/projectrequestequipment hinzugefügt, Success-Page mit Anfrage-Referenz, Bestätigungs-E-Mail an User.
2.**Edge Case:** Warenkorb ist leer, User navigiert zu '/mietanfrage'. Erwartet: Hinweis 'Keine Artikel ausgewählt' + Link zum Mietkatalog.
3.**Edge Case:** Rentman API nicht erreichbar beim Submit. Erwartet: Anfrage wird lokal gespeichert (Retry-Queue), User sieht 'Anfrage eingegangen, wird verarbeitet', Admin-Benachrichtigung.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Rentman projectrequest erfolgreich erstellt (in Rentman UI sichtbar)
- Bestätigungs-E-Mail versendet
- Form-Validation vollständig
---
### [F-HMS-08] Rentman Equipment-Import (Backend)
**Anforderung:** Backend-Service der periodisch (Cron/Interval) oder manuell (Admin-Trigger) Equipment-Daten von Rentman via GET /equipment (paginiert, limit=100, offset-Iteration bis data leer) abruft und in lokaler Datenbank zwischenspeichert. Felder: id, name, number, category, description, images, specifications, rental_price. Bilder werden lokal gecacht/optimiert.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Admin triggert manuellen Import. Erwartet: GET /equipment wird paginiert aufgerufen, alle Seiten werden iteriert, Daten in DB gespeichert, Erfolgsmeldung mit Anzahl importierter Artikel.
2.**Edge Case:** Rentman API gibt leere Liste zurück. Erwartet: Bestehende Daten bleiben erhalten, Warnung 'Keine neuen Daten erhalten'.
3.**Edge Case:** Partial-Failure (Seite 3 von 10 schlägt fehl). Erwartet: Bereits importierte Seiten 1-2 bleiben erhalten, Fehler wird geloggt, Retry-Mechanismus für fehlgeschlagene Seite.
**Anforderung:** Backend-Service der Mietanfragen aus dem Frontend entgegennimmt und an Rentman sendet. Workflow: 1) POST /projectrequests mit Veranstaltungs- + Kontaktdaten, 2) POST /projectrequests/{id}/projectrequestequipment für jeden Artikel. Retry-Queue bei API-Fehlern. Admin-Notification bei fehlgeschlagenen Übermittlungen.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Frontend sendet Anfrage mit 3 Artikeln. Erwartet: POST /projectrequests -> id erhalten -> 3x POST /projectrequests/{id}/projectrequestequipment -> alle erfolgreich -> Response 200 an Frontend.
2.**Edge Case:** POST /projectrequests erfolgreich, aber Equipment-POST schlägt fehl bei Artikel 2. Erwartet: Artikel 1 erfolgreich, Artikel 2 in Retry-Queue, Artikel 3 wird trotzdem versucht, Admin wird benachrichtigt.
3.**Integration:** Rentman UI zeigt erstellte Project Request mit korrekten Daten (Name, Datum, Ort, Equipment-Liste).
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- Project Request in Rentman sichtbar
- Retry-Queue funktional
- Admin-Notification bei Fehlern
---
### [F-HMS-10] Navigation / Header
**Anforderung:** Sticky Header mit: Logo (SVG, orange), Hauptnavigation (Home, Mietkatalog, Referenzen, Kontakt), Social-Icons (Facebook, Instagram), Telefon-Link (0172 / 6264796). Auf Mobile: Burger-Menu mit Slide-in/Overlay. Header-Background in Grautönen.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User klickt 'Mietkatalog' im Header. Erwartet: Navigation zu '/mietkatalog', Header bleibt sichtbar (sticky), aktiver Nav-Punkt hervorgehoben.
2.**Mobile:** User auf 375px Breite, klickt Burger-Icon. Erwartet: Menu öffnet sich als Overlay, alle Nav-Punkte sichtbar und klickbar, Touch-Targets min 44px Höhe, Menu schließt bei Klick außerhalb.
3.**Edge Case:** User scrollt nach unten. Erwartet: Header bleibt sticky, ggf. kompaktere Höhe, Inhalt wird nicht verdeckt.
1.**Happy Path:** User navigiert zu '/datenschutz'. Erwartet: Seite lädt mit allen DSGVO-Pflichtinformationen, lesbar auf Desktop + Mobile.
2.**Edge Case:** Direktzugriff via URL. Erwartet: Seite ist öffentlich zugänglich.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 2 Tests grün
- DSGVO-konform (Rechtsabfrage empfohlen)
---
### [F-HMS-14] AGB Vermietung Seite
**Anforderung:** Statische AGB-Seite '/agb-vermietung' mit Allgemeinen Geschäftsbedingungen für Vermietung. Inhalt wird vom User bereitgestellt (bestehende AGB Vermietung übernehmen).
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User navigiert zu '/agb-vermietung'. Erwartet: Seite lädt mit AGB-Text, lesbar auf Desktop + Mobile.
2.**Edge Case:** Direktzugriff via URL. Erwartet: Seite ist öffentlich zugänglich.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 2 Tests grün
- AGB-Text korrekt übernommen
---
### [F-HMS-15] Logo & Branding Integration
**Anforderung:** Das bestehende SVG-Logo von hms-licht-ton.de wird übernommen (orange Logo auf Grau-Basis). Farbschema: Primär Grautöne (#1a1a1a bis #f5f5f5), Akzentfarbe Orange (wie im bestehenden Logo). Design-Tokens: CSS-Variablen für Farben, Typography, Spacing. Schriften: Modern, gut lesbar (z.B. Inter, Roboto oder ähnlich).
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Seite lädt. Erwartet: Logo als SVG sichtbar im Header, orange Akzentfarbe bei Buttons/Links, Grau-Abstufungen als Background.
2.**Edge Case:** Logo-SVG kann nicht geladen werden. Erwartet: Fallback-Text 'HMS Licht & Ton' sichtbar, kein broken-image.
3.**Verification:** Alle Seiten nutzen dasselbe Farbschema. Erwartet: CSS-Variablen konsistent, keine hardcoded Farben abweichend vom Design-System.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- SVG-Logo von alter Website übernommen
- Design-Tokens (CSS Custom Properties) definiert
---
### [F-HMS-16] Anfrage-Warenkorb (Mietkatalog)
**Anforderung:** Session-basierter Warenkorb für Mietanfragen (keine Auth erforderlich). Artikel hinzufügen/entfernen, Menge anpassen. Warenkorb-Icon im Header mit Counter. Warenkorb-Inhalt persistiert in localStorage (Client-side). Persistenz auch über Page-Reloads.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User fügt 2 Artikel hinzu, ändert Menge auf 3 bei einem. Erwartet: Counter zeigt 5 (2+3), Warenkorb-Seite zeigt beide Artikel mit korrekten Mengen.
2.**Edge Case:** User lädt Seite neu. Erwartet: Warenkorb-Inhalt erhalten (localStorage), Counter korrekt.
3.**Edge Case:** User entfernt alle Artikel. Erwartet: Counter=0, Warenkorb-Seite zeigt Empty-State 'Keine Artikel ausgewählt' + Link zum Katalog.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- localStorage-Persistenz funktional
- Mobile: Warenkorb als Drawer/Bottom-Sheet erreichbar
**Anforderung:** Einfacher Admin-Login (Username/Passwort, JWT-Session) für HMS-Mitarbeiter. Nach Login: Dashboard mit 'Equipment-Sync starten'-Button, Sync-Status (last sync, anzahl artikel), Sync-Log. Kein öffentlicher Zugriff auf Admin-Funktionen.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Admin loggt sich ein, klickt 'Equipment-Sync starten'. Erwartet: Sync läuft, Progress-Indicator sichtbar, nach Abschluss: Status aktualisiert mit Datum + Anzahl.
2.**Edge Case:** Nicht-Admin versucht '/admin' aufzurufen. Erwartet: Redirect zu Login-Seite, keine Admin-Funktionen sichtbar.
**Anforderung:** Custom 404-Seite mit freundlicher Nachricht + Link zur Home-Seite. 500-Error-Page mit allgemeiner Fehlermeldung. Keine raw Stack-Traces im Production-Modus.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** User navigiert zu '/nicht-existent'. Erwartet: 404-Seite mit 'Seite nicht gefunden' + Link zu Home.
2.**Edge Case:** Server-Fehler tritt auf. Erwartet: 500-Seite mit 'Etwas ist schiefgelaufen', keine Stack-Traces sichtbar.
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 2 Tests grün
- Error-Pages im Branding-Design
---
### [F-HMS-19] KI-Meta-Tags & Structured Data
**Anforderung:** Jede Seite hat: Title-Tag, Meta-Description, OpenGraph-Tags. Structured Data (JSON-LD) für LocalBusiness auf Home-Seite. Semantic HTML5 (header, nav, main, section, footer, article). KEINE Indexierung gewünscht (noindex, nofollow, noarchive, nosnippet). KEINE sitemap.xml. robots.txt mit Disallow all (oder noindex-Directive). Domain: hms.media-on.de (nicht öffentlich indexiert).
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Crawler ruft '/' auf. Erwartet: Vollständiger HTML mit Title, Meta-Description, OpenGraph-Tags, JSON-LD LocalBusiness, meta robots noindex/nofollow.
2.**Edge Case:** Crawler ruft '/mietkatalog' auf. Erwartet: Server-side gerendert mit Equipment-Liste im HTML (nicht nur client-side JS), noindex meta tag vorhanden.
3.**Verification:** '/robots.txt' existiert mit Disallow all oder noindex-Directive. KEINE sitemap.xml vorhanden. JSON-LD LocalBusiness Schema korrekt auf Home-Seite.
**Anforderung:** Backend-E-Mail-Service der zwei Typen versendet: 1) Kontaktformular-E-Mail an info@hms-licht-ton.de, 2) Bestätigungs-E-Mail an Kunde nach Mietanfrage. SMTP-Konfiguration via Environment-Variablen. E-Mail-Templates in HTML + Text.
**Test Scenarios (Pflicht, mind. 2):**
1.**Happy Path:** Kontaktformular wird abgeschickt. Erwartet: E-Mail an info@hms-licht-ton.de mit Formulardaten, Absender ist Formular-E-Mail (Reply-To).
2.**Happy Path:** Mietanfrage erfolgreich an Rentman gesendet. Erwartet: Bestätigungs-E-Mail an Kunde mit Referenz-Nummer und Artikel-Liste.
3.**Edge Case:** SMTP-Server nicht erreichbar. Erwartet: E-Mail in Retry-Queue, Admin-Benachrichtigung, keine Fehlermeldung an User (smooth fallback).
**Akzeptanzkriterium:**
- Build erfolgreich
- Alle 3 Tests grün
- E-Mail-Empfang manuell verifiziert
- SMTP via Env-Vars konfiguriert
---
## 4. Rentman-Integration-Spezifikation
### 4.1 Equipment-Import (Lese-Richtung)
| Parameter | Wert |
|-----------|-------|
| **Endpoint** | `GET /equipment` |
| **Auth** | Bearer Token (JWT) |
| **Pagination** | `limit=100`, `offset` iterieren bis `data` leer |
| **Frequenz** | Cron alle 6h + manueller Admin-Trigger |
| **Speicherung** | Lokale PostgreSQL-Tabelle `equipment_cache` |
**Datenfluss:**
```
Rentman API -> Backend (GET /equipment paginated) -> PostgreSQL (equipment_cache) -> Backend API -> Frontend
```
**Relevante Felder (zu ermitteln via GET /equipment/{id}):**
- **State:** Pinia (Vue Store) für Warenkorb + UI-State
- **Icons:** Lucide Icons oder Heroicons
- **Bildergalerie:** Eigene Lightbox-Komponente oder PhotoSwipe
**Begründung Nuxt 3:** SSR für SEO, Vue 3 für reaktive UI, eingebauter Router, SSG-Mode für statische Seiten (Home, Referenzen, Impressum, DSGVO, AGB), SSR für dynamische Seiten (Mietkatalog).