- Add TariffInviteServiceTest, GlobalExceptionHandlerTest, setup-test.ts - Add compose plans/specs docs - Extend .gitignore with *.xlsx, *.ps1, *.http, *.py, *.docx - Remove stale test data files and scripts from working tree
12 KiB
Plan: Admin-Übersichten erweitern — Alle Mitgliedschaften & Alle Benutzer
Task-Übersicht
| ID | Beschreibung | Abhängigkeit | Typ |
|---|---|---|---|
| T1 | User.java: createdAt-Feld hinzufügen | — | Backend |
| T2 | AuthService.register(): createdAt setzen | T1 | Backend |
| T3 | UserRepository: findAllByOrderByCreatedAtDesc() | T1 | Backend |
| T4 | MembershipRepository: findAllWithDetails() | — | Backend |
| T5 | MembershipService: getAllMemberships() | T4 | Backend |
| T6 | MembershipController: GET /admin/memberships | T5 | Backend |
| T7 | AdminIamService: getAllUsers() | T3 | Backend |
| T8 | AdminIamController: GET /api/admin/users | T7 | Backend |
| T9 | PendingMembershipResponse: validFrom/validTo erweitern | — | Backend |
| T10 | Backend-Tests schreiben | T6, T8, T9 | Test |
| T11 | OpenAPI-Spec generieren + Frontend-API-Client regenerieren | T6, T8 | Build |
| T12 | Frontend MembershipService: getAllMemberships() | T11 | Frontend |
| T13 | AdminMembershipsComponent: Tab-Navigation + Tabelle | T12, T9 | Frontend |
| T14 | AdminUserApprovalComponent: Tab-Navigation + Tabelle | T11 | Frontend |
| T15 | Integrations-Test: UI manuell prüfen | T13, T14 | Test |
T1: User.java — createdAt-Feld hinzufügen
Beschreibung: Füge der User-Entity ein createdAt-Feld vom Typ LocalDateTime hinzu.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/iam/domain/User.java
Akzeptanz:
createdAtFeld mit@Column(updatable = false)vorhanden- Kein
@GeneratedValue— wird manuell gesetzt - Kompiliert ohne Fehler
ddl-auto: updateerstellt die Spalte automatisch
Details:
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
T2: AuthService.register() — createdAt setzen
Beschreibung: Setze createdAt auf LocalDateTime.now() in der register()-Methode.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AuthService.java
Akzeptanz:
newUser.setCreatedAt(LocalDateTime.now())voruserRepository.save(newUser)- Import für
LocalDateTimevorhanden
Details:
Zeile ~77, nach newUser.setVerificationToken(token):
newUser.setCreatedAt(LocalDateTime.now());
T3: UserRepository — findAllByOrderByCreatedAtDesc()
Beschreibung: Füge eine Spring Data Query-Methode hinzu, die alle Users absteigend nach Erstellungszeitpunkt sortiert.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/iam/repository/UserRepository.java
Akzeptanz:
- Methode
List<User> findAllByOrderByCreatedAtDesc()vorhanden - Kompiliert ohne Fehler
Details:
List<User> findAllByOrderByCreatedAtDesc();
T4: MembershipRepository — findAllWithDetails()
Beschreibung: Füge eine JPQL-Query hinzu, die alle Mitgliedschaften mit JOIN FETCH für MeteringPoint und EnergyCommunity zurückgibt.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/community/repository/MembershipRepository.java
Akzeptanz:
@Querymit JOIN FETCH auf meteringPoint und energyCommunity- Kein WHERE-Clause (alle Status)
- Kompiliert ohne Fehler
Details:
@Query("SELECT m FROM Membership m JOIN FETCH m.meteringPoint mp JOIN FETCH m.energyCommunity ec")
List<Membership> findAllWithDetails();
T5: MembershipService — getAllMemberships()
Beschreibung: Neue Methode, die alle Mitgliedschaften lädt und als PendingMembershipResponse-Liste zurückgibt (mit User-Lookup).
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/community/service/MembershipService.java
Akzeptanz:
@Transactional(readOnly = true)Annotation- Nutzt
findAllWithDetails() - Gleiche User-Lookup-Logik wie
getPendingMemberships()(Batch-Fetch aller User-IDs) - Gibt
List<PendingMembershipResponse>zurück
Details:
Kopiere die User-Lookup-Logik aus getPendingMemberships(), aber entferne den WHERE-Clause auf Status. Das PendingMembershipResponse-DTO muss um validFrom/validTo erweitert werden (siehe T9).
T6: MembershipController — GET /admin/memberships
Beschreibung: Neuer Admin-Endpoint für alle Mitgliedschaften.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/community/api/MembershipController.java
Akzeptanz:
@GetMapping("/admin/memberships")mit@PreAuthorize("hasRole('ADMIN')")- Gibt
ResponseEntity<List<PendingMembershipResponse>>zurück - Swagger-Annotationen (
@Operation,@ApiResponse)
Details:
@GetMapping("/admin/memberships")
@PreAuthorize("hasRole('ADMIN')")
@Operation(summary = "Lädt alle Mitgliedschaften", description = "Zeigt alle Mitgliedschaften aller Status.")
public ResponseEntity<List<PendingMembershipResponse>> getAllMemberships() {
return ResponseEntity.ok(membershipService.getAllMemberships());
}
T7: AdminIamService — getAllUsers()
Beschreibung: Neue Methode, die alle Users sortiert nach Erstellungszeitpunkt zurückgibt.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AdminIamService.java
Akzeptanz:
@Transactional(readOnly = true)Annotation- Nutzt
userRepository.findAllByOrderByCreatedAtDesc() - Gibt
List<User>zurück
Details:
@Transactional(readOnly = true)
public List<User> getAllUsers() {
return userRepository.findAllByOrderByCreatedAtDesc();
}
T8: AdminIamController — GET /api/admin/users
Beschreibung: Neuer Admin-Endpoint für alle Benutzer.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/iam/api/AdminIamController.java
Akzeptanz:
@GetMappingauf Root-Pfad/api/admin/users- Nutzt
adminIamService.getAllUsers()+userMapper.mapToDto() - Gibt
ResponseEntity<List<UserProfileResponse>>zurück - Swagger-Annotationen
Details:
@GetMapping
@Operation(summary = "Lädt alle User", description = "Zeigt alle registrierten Benutzer.")
public ResponseEntity<List<UserProfileResponse>> getAllUsers() {
return ResponseEntity.ok(userMapper.mapToDto(adminIamService.getAllUsers()));
}
T9: PendingMembershipResponse — validFrom/validTo erweitern
Beschreibung: Erweitere das DTO-Record um validFrom und validTo für alle Mitgliedschaften.
Dateien:
eeg_backend/src/main/java/at/mueller/eeg/backend/community/api/dto/PendingMembershipResponse.java
Akzeptanz:
- Record hat neue Felder
LocalDate validFrom,LocalDate validTo getPendingMemberships()in MembershipService setzt beide Felder (null für PENDING)getAllMemberships()setzt beide Felder aus Entity
Details:
record PendingMembershipResponse(
UUID id,
String userEmail,
String firstName,
String lastName,
String atNumber,
String communityName,
Integer priorityLevel,
String status,
LocalDate validFrom,
LocalDate validTo
) {}
Achtung: Da PendingMembershipResponse ein Java record ist, müssen ALLE Aufrufstellen aktualisiert werden, die dieses DTO erstellen. Insbesondere getPendingMemberships() in MembershipService.
T10: Backend-Tests schreiben
Beschreibung: Unit-Tests für die neuen Service-Methoden und Integrationstests für die neuen Endpoints.
Dateien:
eeg_backend/src/test/java/.../community/service/MembershipServiceTest.java(neu oder erweitern)eeg_backend/src/test/java/.../iam/service/AdminIamServiceTest.java(neu oder erweitern)
Akzeptanz:
- Test für
getAllMemberships(): gibt alle Status zurück - Test für
getAllUsers(): gibt alle Users sortiert zurück - Bestehende Tests weiterhin grün
.\mvnw test -pl eeg_backenderfolgreich
T11: OpenAPI-Spec generieren + Frontend-API-Client regenerieren
Beschreibung: Generiere die OpenAPI-Spec aus dem Backend und regeneriere den Frontend-API-Client.
Befehle:
.\mvnw test -pl eeg_backend -Dtest=OpenApiGeneratorTest
cd eeg_frontend && npm run generate-api
Akzeptanz:
eeg_frontend/openapi.yamlenthält neuen Endpoint/api/community/admin/membershipseeg_frontend/openapi.yamlenthält neuen Endpoint/api/admin/users(Root)- Generierter
AdminIAMServiceenthältgetAllUsers() - Keine Type-Errors im Frontend
T12: Frontend MembershipService — getAllMemberships()
Beschreibung: Neue Methode im Frontend MembershipService.
Dateien:
eeg_frontend/src/app/services/membership.ts
Akzeptanz:
getAllMemberships(): Observable<PendingMembershipResponse[]>vorhanden- Nutzt
GET /api/community/admin/memberships
Details:
getAllMemberships(): Observable<PendingMembershipResponse[]> {
return this.http.get<PendingMembershipResponse[]>(`${this.apiUrl}/admin/memberships`);
}
T13: AdminMembershipsComponent — Tab-Navigation + Tabelle
Beschreibung: Erweitere die Admin-Mitgliedschafts-Seite mit Tab-Navigation und Tabellen-Ansicht.
Dateien:
eeg_frontend/src/app/pages/admin-memberships/admin-memberships.tseeg_frontend/src/app/pages/admin-memberships/admin-memberships.html
Akzeptanz:
- Tab-Leiste: "Ausstehende Anträge" | "Aktive Mitgliedschaften" | "Alle"
- Signal
activeTab: signal<'pending' | 'active' | 'all'>('pending') - Signal
allMemberships: signal<PendingMembershipResponse[]>([]) loadAllMemberships()lädt alle Daten beim Wechsel auf Tab "Aktive" oder "Alle"- Tab "Ausstehende": Bestehende Karten-Ansicht mit Genehmigen/Ablehnen
- Tab "Aktive" + "Alle": Tabellen-Ansicht (Name, Email, Community, Zählpunkt, Priorität, Status)
- Nur PENDING zeigt Aktions-Buttons
- Hilfsfunktion
getStatusLabel(status: string): stringfür deutsche Anzeige - Loading-Zustand für Tab-Wechsel
Details:
- Client-seitige Filterung: Beim Laden werden alle Mitgliedschaften in
allMembershipsgespeichert - Tab "Ausstehende" filtert nach
status === 'PENDING' - Tab "Aktive" filtert nach
status === 'ACTIVE' - Tab "Alle" zeigt alle
- Tabellen-Header: Benutzer | Email | Gemeinschaft | Zählpunkt | Priorität | Status
T14: AdminUserApprovalComponent — Tab-Navigation + Tabelle
Beschreibung: Erweitere die Admin-Benutzerverwaltung mit Tab-Navigation und Tabelle für alle Users.
Dateien:
eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.tseeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html
Akzeptanz:
- Tab-Leiste: "Ausstehende Anträge" | "Alle Benutzer"
- Signal
activeTab: signal<'pending' | 'all'>('pending') - Signal
allUsers: signal<UserProfileResponse[]>([]) loadAllUsers()nutzt generiertenAdminIAMService.getAllUsers()- Tab "Ausstehende": Bestehende Tabelle mit Freigeben/Ablehnen
- Tab "Alle": Tabelle mit Name, Email, Status, Rolle (keine Aktions-Buttons)
- Status-Badge: PENDING=gelb, APPROVED=grün, REJECTED=rot
- Hilfsfunktion
getStatusLabel(status: string): string - Bug fix: Doppelte "Status"-Spalten-Überschrift beheben (Zeile 32-33 in aktuellem Template)
Details:
- Tab "Ausstehende" lädt weiterhin
getPendingUsers()(nur verifizierte PENDING-User) - Tab "Alle" lädt
getAllUsers()beim ersten Wechsel - Status-Badges:
bg-yellow-100 text-yellow-800(PENDING),bg-green-100 text-green-800(APPROVED),bg-red-100 text-red-800(REJECTED)
T15: Integrations-Test — UI manuell prüfen
Beschreibung: Manuelle Überprüfung der Admin-Seiten im Browser.
Akzeptanz:
- Backend startet ohne Fehler
GET /api/community/admin/membershipsgibt alle Mitgliedschaften zurückGET /api/admin/usersgibt alle Benutzer zurück- Admin öffnet Mitgliedschaften → sieht Tabs "Ausstehende | Aktive | Alle"
- Admin öffnet Benutzerverwaltung → sieht Tabs "Ausstehende | Alle"
- Tab-Wechsel funktioniert sofort (kein Ladevorgang nötig außer beim ersten Laden)
- Genehmigen/Ablehnen funktioniert weiterhin auf dem "Ausstehende"-Tab
- Status-Badges werden korrekt angezeigt
.\mvnw test -pl eeg_backendalle Tests grün