feat(MemberGroupPhoto): implement group photo management functionality
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 38s
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:
311
docs/feature_group_photo_member_crops.md
Normal file
311
docs/feature_group_photo_member_crops.md
Normal 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.
|
||||
Reference in New Issue
Block a user