feat: tablet-first UX overhaul with wizard improvements

- Tablet-first responsive scoreboard: whole player card is tap target
- Per-step wizard backgrounds and live summary panel
- Larger touch targets, safe-area handling, reduced-motion support
- German UI error strings in App.tsx
- Updated SOUL.md and README.md for current architecture
- Cleanup: removed legacy components, .cursor/, UI_IMPROVEMENTS.md
- Renamed package to bscscore, fixed TOTAL_WIZARD_STEPS
This commit is contained in:
Frank Schwenk
2026-09-21 17:59:31 +02:00
parent 3327f6e19e
commit 678977ab23
92 changed files with 3359 additions and 3063 deletions
+163
View File
@@ -0,0 +1,163 @@
# SOUL — BSC Score
> Diese Datei ist das Herzstück des Projekts: **wofür** die App existiert und **wie** wir daran arbeiten.
> Für Menschen, für zukünftige Agents, für Frank-in-6-Monaten-der-vergessen-hat-warum-Tap-to-Score.
---
## Was diese App ist
**BSC Score** ist eine **PWA zum Live-Scoring von Pool-/Billardpartien** — gebaut für den Einsatz **am Tisch**, nicht als Statistik-Portal oder Social App.
**Tagline:** *Schnell punkten, nicht nachdenken.*
**Der 3-Sekunden-Test:** Jemand startet ein neues Spiel und trägt den ersten Punkt ein — ohne Tutorial, ohne Login, ohne Netzwerk.
**Nicht:** *„Wo war nochmal der Plus-Button?"*
**Eine Rolle, klar:**
- **Scorekeeper am Tisch** — Partie anlegen, Punkte tippen, Undo, fertig. Alles andere ist Nebenrolle.
**Kontext:** App für den **Billard Sports Club** (BSC), produktiv unter [`score.bsc-gp.de`](https://score.bsc-gp.de). Lokale Daten bleiben auf dem Gerät (IndexedDB).
---
## Stimme & Ton
- **Sprache:** Deutsch in UI, Labels und Fehlermeldungen. Billard-Standardbegriffe bleiben Englisch, wo sie am Tisch so gesagt werden: *Race to*, *Break*, *Rematch*, *Winnerbreak*, *Wechselbreak*, *8-Ball* / *9-Ball* / *10-Ball*.
- **Formality:** Direkt und sachlich. Formelles *Sie* nur in Bestätigungsdialogen (z. B. Löschen). Sonst neutral-kurz — kein Smalltalk, kein Marketing.
- **Fehlermeldungen:** Ehrlich, konkret, ohne Schuldzuweisung. Was fehlt, was zu tun ist.
- **Kein App-Store-Sprech.** Kein „Erlebnis optimieren", kein „Synergien", kein Gamification-Buzz.
**Werte sind funktional, nicht dekorativ:** Schnelligkeit am Tisch schlägt Feature-Reichtum. Ein Tipp = ein Punkt. Undo statt Minus-Buttons.
### Wording-Beispiele
| Kontext | Gut | Schlecht |
|---------|-----|----------|
| Erfolg | „Alex hat gewonnen!" | „Glückwunsch! Dein Match wurde erfolgreich abgeschlossen." |
| Fehler | „Spielername ist erforderlich" | „Ungültige Eingabe. Bitte prüfen Sie Ihre Daten." |
| Leer | „Keine Spiele vorhanden" | „Starte jetzt deine Billard-Reise!" |
| Aktion | „+ Neues Spiel" / „Spiel beenden" | „Match initialisieren" / „Session terminieren" |
| Bestätigung | „Möchten Sie das Spiel wirklich löschen?" | „Bist du sicher???" |
---
## Visuelle & technische DNA
| Element | Ja | Nö |
|---------|----|----|
| Dark Mode (`#1a1a1a` Hintergrund, `#222` Surfaces) | ✓ | |
| Akzent Orange `#ff9800` | ✓ | |
| Große Touch-Targets (44–56 px, Tablet-first) | ✓ | |
| Vollbild-PWA (`display: fullscreen`) | ✓ | |
| Tap auf Spieler-Karte = +1, Undo zum Zurücknehmen | ✓ | |
| +/- Buttons am Scoreboard | | ✓ (entfernt, Issue #29) |
| Toast-Spam bei jedem Punkt | | ✓ |
| Helles Theme als Default | | ✓ |
| Kleine Buttons, Desktop-only Layout | | ✓ |
| Login, Accounts, Onboarding-Wizard | | ✓ |
**Technik-Philosophie (2026):** Astro 5 (Islands) + Preact + TypeScript strict. Offline-first mit Service Worker und IndexedDB. Modular unter `src/lib` — Domain → Data → State → Features → Astro-Shell. Playwright-Recordings für wiederholbare Flows. Qualität heißt: **am Tablet im Querformat bedienbar, schnell hydratisierend, ohne Netz** — nicht Feature-Bloat.
**Architektur-Regel (nicht verhandelbar):**
```
domain → data → state → features → app shell
```
Untere Schichten importieren nie aus höheren. Neue Logik zuerst in `@lib/domain`, dann nach oben.
**Signature-Features (Teil der Identität):**
- **Neues-Spiel-Wizard** (7 Schritte) — Spieler 1–3 (3 optional) → Spielart → Race-to / Endlos → Break-Regel → Break-Reihenfolge; **WizardSummary** zeigt bisherige Auswahl mit; jeder Schritt hat eigene Hintergrundfarbe (`step-player1` … `step-breakOrder`)
- **Spieler-Historie** — Schnellauswahl bekannter Namen
- **Break-Anzeige** — Weißer Punkt beim aktuellen Breaker
- **Rematch** — Direkt neue Partie mit gleichen Spielern
- **Vollbild-Toggle** — Fixiert oben rechts (Scoreboard-Steuerung unten frei)
Cloud-Sync-Felder existieren im Domain-Modell, sind aber **noch nicht Produktfeature**.
---
## Was die App können muss
**Spielarten:** 8-Ball, 9-Ball, 10-Ball — jeweils Race-to oder **Endlos** (14/1).
**Kernflows:**
1. Neues Spiel anlegen (Wizard, max. wenige Schritte)
2. Live-Scoring (Score antippen → +1)
3. Undo (letzter Stand zurück)
4. Spiel beenden → Gewinner/Rematch
5. Spiele filtern (Alle / Aktiv / Abgeschlossen), löschen
**Geräte-Priorität:** Android-Tablet / iPad **quer**, am Billardtisch. Virtual Keyboard darf Layout nicht zerlegen: `App.tsx` setzt `--app-height` und `--keyboard-offset` aus `visualViewport` (auch bei Orientierungswechsel). Mobile Portrait ist zweite Priorität, Desktop dritte.
**Daten:** Alles lokal in `BSCScoreDB` (IndexedDB). Kein Server-State, keine Analytics, kein Tracking.
---
## Wie wir zusammenarbeiten
### Fränky liefert, Agent bindet ein
| Datei | Zweck |
|-------|-------|
| [`NOTES.md`](NOTES.md) | Scratchpad — frei, chaotisch erlaubt |
| [`SOUL.md`](SOUL.md) | Vision, Ton, Arbeitsweise |
| [`.gitea`](.gitea) | Aktuelles Gitea-Issue für Traceability |
**Regel:** Issue-getriebene Arbeit — Code-Änderungen gehören zu einem Gitea-Issue. Commits referenzieren die Issue-Nummer (`Refs #N` / `Fixes #N`).
### Arbeitsmodus Agent
1. **Scope eng halten** — nur anfassen, was die Aufgabe verlangt. Kein Refactor „nebenbei".
2. **Domain first** — Logik in `@lib/domain`, UI bleibt dünn.
3. **Tablet testen** — Landscape, Touch, Vollbild. Playwright-Recordings unter `tests/recordings/` als Referenz-Flows.
4. **`npm run build`** vor „fertig" — bei Permission-Problemen Docker wie in [`README.md`](README.md).
5. **Keine Commits**, unless Fränky explizit will.
6. **Englische Fehlertexte in `App.tsx`** sind Tech-Debt — neue UI-Texte immer Deutsch (siehe `VALIDATION_MESSAGES` in `@lib/domain/constants`).
### Prioritäten bei Konflikten
```
Bedienbarkeit am Tisch (80%) > Architektur-Schönheit (20%)
Offline-Zuverlässigkeit > Cloud-Features
Weniger Taps > mehr Optionen
Deutsch + Billard-Jargon > eingedeutschte Fachbegriffe
Barrierefreiheit (ARIA, Touch) > Animationen
```
---
## Anti-Manifest (bitte nicht)
- Statistik-Dashboard, Ranglisten, Social Sharing
- User-Accounts, Login, Multiplayer-Sync (solange nicht explizit geplant)
- Gamification (Badges, Streaks, XP)
- i18n-Overhead — UI bleibt Deutsch
- Feature-Creep im Wizard (jeder Schritt kostet Zeit am Tisch)
- Monolithische Komponenten — der Refactor nach `src/lib` war bewusst, nicht rückgängig machen
- Plus/Minus-Buttons am Score — Tap + Undo ist der Flow
---
## Für Agents: Quick Start
1. [`SOUL.md`](SOUL.md) lesen (du bist hier)
2. [`src/lib/docs/architecture.md`](src/lib/docs/architecture.md) — Modul-Layout und Import-Regeln
3. [`src/lib/domain/constants.ts`](src/lib/domain/constants.ts) — UI-Texte, Validierung, Design-Tokens
4. `npm run dev` → `http://localhost:3000` — Tablet-Viewport testen
5. Änderungen am **Ton** gegen SOUL abgleichen; am **Scoring-Flow** gegen Playwright-Recordings
6. Vor „fertig": `npm run build` + mindestens ein Kernflow manuell (Neues Spiel → Score → Undo → Beenden)
---
## Project-Specific Rules
- Tap auf die ganze Spieler-Karte erhöht um 1 — kein separates Plus-UI — `Refs #29`
- Wizard und Features leben unter `@lib/features/*`, Astro-`src/components` ist nur Shell
- Deploy: `astro build` → `dist/` → nginx via [`compose.yml`](compose.yml) auf `score.bsc-gp.de`
- PRD-Referenz in Cursor-Rules (`docs/prd.md`) — Datei fehlt im Repo; bei Widersprüchen SOUL + Code als führend behandeln und nachfragen
---
## Ein Satz zum Mitnehmen
**BSC Score** ist der digitale Schiedsrichter-Zettel am Billardtisch — dunkel, orange, große Finger, ein Tipp pro Punkt, funktioniert auch ohne WLAN.