feat(MemberGroupPhoto): implement group photo management functionality
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 38s

- Added MemberGroupPhoto model and established relationships with Club and User models.
- Introduced new routes for managing group photos in the backend.
- Enhanced frontend components to support group photo cropping and member image updates.
- Updated localization files to include new terms related to group photo processing across multiple languages.
- Refactored server.js to include MemberGroupPhoto in the synchronization process.
This commit is contained in:
Torsten Schulz (local)
2026-04-15 22:45:35 +02:00
parent 5fa34637ba
commit 1dd7bb24ea
26 changed files with 1384 additions and 2 deletions

View File

@@ -0,0 +1,311 @@
# Feature-Konzept: Gruppenfoto zu Mitgliedsfotos
## Ziel
Trainer sollen ein Gruppenfoto hochladen oder mit der Kamera aufnehmen koennen und daraus per manuell gezogenem Rahmen einzelne Mitgliedsfotos erstellen. Die ausgeschnittenen Bilder werden wie normale Mitgliedsfotos gespeichert.
Zusaetzlich soll ein Gruppenfoto fuer spaetere Bearbeitung gespeichert werden koennen. So kann der Trainer im Training schnell ein Foto aufnehmen und die eigentliche Zuordnung und Bearbeitung spaeter, zum Beispiel zuhause, erledigen.
## Nutzerfluss
1. Trainer oeffnet `/members`.
2. Trainer klickt auf `Gruppenfoto verarbeiten`.
3. Ein Dialog oeffnet sich mit drei Einstiegen:
- `Foto aufnehmen`
- `Foto hochladen`
- `Gespeichertes Foto oeffnen`
4. Bei einem neuen Foto entscheidet der Trainer:
- `Nur jetzt verarbeiten`
- `Fuer spaetere Bearbeitung speichern`
5. Das Gruppenfoto wird gross angezeigt.
6. Trainer zieht einen Rahmen um eine Person oder ein Gesicht.
7. Trainer waehlt das passende Mitglied aus.
8. Trainer klickt `Als Mitgliedsfoto speichern`.
9. Der Ausschnitt wird gespeichert.
10. Trainer kann direkt den naechsten Ausschnitt aus demselben Gruppenfoto markieren.
## Erster Funktionsumfang
- Gruppenfoto hochladen.
- Gruppenfoto mobil per Kamera aufnehmen.
- Gruppenfoto optional dauerhaft fuer spaetere Bearbeitung speichern.
- Gespeicherte Gruppenfotos pro Verein auflisten.
- Gespeichertes Gruppenfoto spaeter wieder oeffnen.
- Manuelle Rahmenauswahl auf dem Gruppenfoto.
- Mitgliedsauswahl mit Suche.
- Ausschnitt-Vorschau vor dem Speichern.
- Ausschnitt als neues Mitgliedsfoto speichern.
- Optionaler Schalter `Als Hauptfoto verwenden`.
- Mehrere Ausschnitte nacheinander aus demselben Gruppenfoto erstellen.
- Gruppenfoto loeschen, ohne bereits erzeugte Mitgliedsfotos zu loeschen.
## Nicht im ersten Wurf
- Automatische Gesichtserkennung.
- Automatische Zuordnung zu Mitgliedern.
- Mehrfachrahmen gleichzeitig.
- Speichern unfertiger Crop-Rahmen als Entwurf.
- Statusverwaltung pro markiertem Ausschnitt.
- Nachtraegliche Bearbeitung bereits erzeugter Mitgliedsfotos.
Diese Punkte koennen spaeter ergaenzt werden. Fuer die erste Version bleibt das Feature bewusst manuell und kontrollierbar.
## UI-Konzept
Auf `/members` wird ein neuer Button im Aktionsbereich ergaenzt:
```text
Gruppenfoto verarbeiten
```
Der Dialog startet mit:
```text
Gruppenfoto verarbeiten
[Foto aufnehmen]
[Foto hochladen]
[Gespeichertes Foto oeffnen]
```
Nach Fotoauswahl:
```text
[ ] Fuer spaetere Bearbeitung speichern
Titel: Training 15.04.2026
Datum: 15.04.2026
Notiz: optional
```
Der Bearbeitungsdialog besteht aus:
- links: grosses Gruppenfoto mit ziehbarem Crop-Rahmen
- rechts: Ausschnitt-Vorschau
- rechts: Mitgliedersuche
- rechts: Checkbox `Als Hauptfoto verwenden`
- rechts: Button `Als Mitgliedsfoto speichern`
- rechts: Statusmeldung, zum Beispiel `Foto gespeichert fuer Max Mustermann`
Fuer mobile Ansicht:
- Bild oben
- Vorschau darunter
- Mitgliedersuche darunter
- Speichern-Aktion am unteren Rand
## Gespeicherte Gruppenfotos
Unter `Gespeichertes Foto oeffnen` wird eine Liste angezeigt:
- Titel
- Aufnahmedatum oder Erstelldatum
- optional Notiz
- Button `Oeffnen`
- Button `Loeschen`
Ein geloeschtes Gruppenfoto entfernt nur das Original-Gruppenfoto. Bereits erstellte Mitgliedsfotos bleiben erhalten.
## Crop-Verhalten
Empfehlung fuer Mitgliedsfotos:
- Standard-Seitenverhaeltnis `1:1`
- Mindestgroesse zum Beispiel `160 x 160 px`
- Exportgroesse zum Beispiel `600 x 600 px`
- JPEG-Qualitaet etwa `0.9`
- Warnung bei sehr kleinen Ausschnitten:
```text
Der Ausschnitt ist sehr klein und kann unscharf wirken.
```
Optional spaeter:
- Umschalter `Freier Ausschnitt`
- Zoom und Pan fuer grosse Gruppenfotos
- Tastatursteuerung fuer Feinkorrektur
## Technische Umsetzung
### Frontend
Neue Komponente:
```text
frontend/src/components/members/GroupPhotoCropDialog.vue
```
Einbindung in:
```text
frontend/src/views/MembersView.vue
```
Technischer Ablauf:
1. Bilddatei per Dateiinput oder Kamera laden.
2. Bild im Browser anzeigen.
3. Crop-Koordinaten erfassen.
4. Ausschnitt per Canvas in ein neues Canvas zeichnen.
5. Canvas als `Blob` exportieren.
6. Blob per `FormData` an die bestehende Mitgliedsfoto-API hochladen.
7. Optional danach das Bild als Hauptfoto setzen.
Kameraaufnahme kann pragmatisch ueber einen Dateiinput starten:
```html
<input type="file" accept="image/*" capture>
```
### Bestehender Mitgliedsfoto-Upload
Wenn moeglich wird die bestehende Route genutzt:
```text
POST /api/clubmembers/image/:clubId/:memberId
```
Falls `Als Hauptfoto verwenden` aktiv ist, wird danach die bestehende Primary-Route genutzt:
```text
POST /api/clubmembers/image/:clubId/:memberId/:imageId/primary
```
Der Blob kann als Datei `group-photo-crop.jpg` gesendet werden.
## Backend fuer gespeicherte Gruppenfotos
Fuer dauerhaft gespeicherte Gruppenfotos wird eine neue Tabelle empfohlen:
```text
member_group_photo
```
Minimal benoetigte Felder:
- `id`
- `club_id`
- `title`
- `photo_path`
- `taken_at`
- `created_by_user_id`
- `created_at`
- `updated_at`
Sinnvolle weitere Felder:
- `description`
- `original_file_name`
- `mime_type`
- `file_size`
- `width`
- `height`
- `status`, zum Beispiel `open`, `in_progress`, `done`, `archived`
- `processed_at`
- `archived_at`
## API-Vorschlag
```text
GET /api/member-group-photos/:clubId
POST /api/member-group-photos/:clubId
GET /api/member-group-photos/:clubId/:photoId/image
PUT /api/member-group-photos/:clubId/:photoId
DELETE /api/member-group-photos/:clubId/:photoId
```
Beschreibung:
- `GET /:clubId`: listet gespeicherte Gruppenfotos des Vereins.
- `POST /:clubId`: speichert ein neues Gruppenfoto.
- `GET /:clubId/:photoId/image`: liefert das Originalbild fuer spaetere Bearbeitung.
- `PUT /:clubId/:photoId`: aktualisiert Titel, Datum oder Notiz.
- `DELETE /:clubId/:photoId`: loescht das gespeicherte Gruppenfoto.
Alle Routen muessen authentifiziert sein und Vereinszugriff pruefen.
## Speicherort
Empfohlener Speicherort, getrennt von normalen Mitgliedsbildern:
```text
uploads/member-group-photos/:clubId/:photoId/original.jpg
```
Falls das Projekt bereits andere Upload-Konventionen nutzt, sollte der Pfad daran angepasst werden.
## Datenschutz und Berechtigungen
Wenn komplette Gruppenfotos gespeichert werden, koennen darauf auch Personen zu sehen sein, deren Einzelbild nicht gespeichert werden soll. Deshalb sollte im Dialog ein klarer Hinweis stehen:
```text
Dieses Gruppenfoto wird gespeichert und kann andere Personen enthalten. Bitte nur speichern, wenn die Nutzung im Verein zulaessig ist.
```
Empfehlungen:
- Gruppenfotos nur fuer berechtigte Vereinsnutzer sichtbar machen.
- Keine oeffentliche Bild-URL ohne Authentifizierung.
- Bildauslieferung nur ueber geschuetzte API.
- Loeschfunktion direkt in der Gruppenfoto-Liste anbieten.
- Das Speichern eines Gruppenfotos aendert keine bestehenden Einwilligungen, zum Beispiel `picsInInternetAllowed`.
- Die Zuordnung eines Ausschnitts zu einem Mitglied bleibt eine bewusste Trainerentscheidung.
## Spaeterer Ausbau: Crop-Entwuerfe
Wenn spaeter auch unfertige Rahmen gespeichert werden sollen, kann eine zweite Tabelle ergaenzt werden:
```text
member_group_photo_crop
```
Moegliche Felder:
- `id`
- `group_photo_id`
- `member_id`
- `x`
- `y`
- `width`
- `height`
- `status`
- `created_at`
- `updated_at`
Moegliche Statuswerte:
- `open`
- `assigned`
- `saved`
- `discarded`
Das ist nicht Teil der ersten Version, waere aber die Grundlage fuer Mehrfachrahmen und spaetere Weiterbearbeitung.
## Fehlerfaelle
- Kein Foto gewaehlt: Bearbeitung nicht moeglich.
- Kein Rahmen gezogen: Speichern deaktivieren.
- Kein Mitglied gewaehlt: Speichern deaktivieren.
- Ausschnitt zu klein: Warnung anzeigen oder Speichern deaktivieren.
- Upload schlaegt fehl: Fehlermeldung anzeigen, Auswahl beibehalten.
- Gruppenfoto kann nicht geladen werden: Fehlermeldung und Rueckkehr zur Liste.
- Gruppenfoto wurde geloescht: Liste aktualisieren.
## Akzeptanzkriterien
- Trainer kann ein Gruppenfoto hochladen.
- Trainer kann ein Gruppenfoto mobil aufnehmen.
- Trainer kann ein Gruppenfoto fuer spaetere Bearbeitung speichern.
- Gespeicherte Gruppenfotos werden pro Verein aufgelistet.
- Ein gespeichertes Gruppenfoto kann spaeter geoeffnet und bearbeitet werden.
- Trainer kann per Rahmen einen Ausschnitt markieren.
- Ausschnitt wird als Vorschau angezeigt.
- Trainer kann ein Mitglied suchen und auswaehlen.
- Ausschnitt wird als Mitgliedsfoto gespeichert.
- Optional kann der Ausschnitt als Hauptfoto gesetzt werden.
- Mehrere Mitglieder koennen nacheinander aus demselben Gruppenfoto versorgt werden.
- Gruppenfoto kann geloescht werden.
- Loeschen eines Gruppenfotos loescht keine bereits erstellten Mitgliedsfotos.
- Gruppenfoto ist nur fuer berechtigte Nutzer des Vereins abrufbar.
- Das vollstaendige Gruppenfoto wird nur gespeichert, wenn der Trainer dies bewusst auswaehlt.
- Frontend-Build laeuft ohne Fehler.