24 KiB
Koogle App - Analyse & Vorschlag für Bereiche und Pages
Zweck der Anwendung (abgeleitet aus Datenmodell)
Koogle ist eine Vereinsverwaltung für Kegelvereine mit Schwerpunkt auf:
Kernfunktionen
- Vereinsverwaltung: Multi-Mandanten-System, jeder Verein = eigener Scope
- Mitglieder & Gäste: Verwaltung von Personen mit Status (Member/Guest)
- Spieltagsorganisation: Planung und Durchführung von Kegeltagen (Days)
- Status-Workflow: New → Started → Closed (oder Postponed)
- Zuordnung von Teilnehmern pro Spieltag
- Spielverwaltung: Mehrere Games pro Day möglich
- JSON-basierte Spielstände (GameData)
- Teilnehmerzuordnung pro Game
- Kostenmanagement:
- Vordefinierte Kosten/Strafen (Expenses) pro Verein
- Automatische Trigger (z.B. Pudel, Pumpe, Aus, Kranz, etc.)
- Variable/Fixe Preise, Inverse Kosten (alle außer einem zahlen)
- One-Click Kosten für schnelle Erfassung
- Abrechnung:
- Pro Person, pro Tag, pro Spiel
- Berechnungsmethoden: None, Average, Maximum (für fehlende Personen)
- Status: Open/Done für PersonExpenses
- Benutzer & Berechtigungen:
- ASP.NET Identity mit Custom UserProfile
- Rollen pro Verein: Viewer, Editor, Admin
- SuperAdmin für vereinsübergreifende Verwaltung
- Multi-Club Zugehörigkeit möglich
Bestehende Implementierung
Vollständig implementiert
- ✅ Authentication/Authorization Framework
- ✅ Login mit Vereinsauswahl
- ✅ Fluxor State Management (AuthState)
- ✅ Rollenbasierte Berechtigungen
- ✅ MudBlazor UI Framework
- ✅ Dual DbContext (Domain + Identity)
- ✅ Clean Architecture Struktur
- ✅ Seeders (SuperAdmin, Roles)
Teilweise implementiert
- ⚠️ DayService (vorhanden, aber auskommentiert)
- ⚠️ Navigation (Skelett vorhanden, kaum Menüpunkte)
Nicht implementiert
- ❌ UI für Clubs, Days, Games, Persons, Expenses
- ❌ Services für Person, Game, Expense
- ❌ DTOs für die meisten Domain Entities
- ❌ Fluxor States für Domain-Daten
- ❌ Reporting/Export-Funktionalität
Vorgeschlagene Bereiche & Pages
1. DASHBOARD-BEREICH (Startseite)
Route: / oder /dashboard
Zweck: Übersicht über aktuelle Aktivitäten im ausgewählten Verein
Pages:
- Dashboard.razor:
- Nächste geplante Spieltage
- Aktuelle offene Kosten
- Quick-Actions (neuer Spieltag, neue Person)
- Statistiken (Anzahl Mitglieder, Gäste, offene Abrechnungen)
2. SPIELTAG-BEREICH (Day Management)
Route: /days
Pages:
-
DayList.razor (
/days):- Tabelle: PostDate, Status, Teilnehmeranzahl
- Filter: Jahr, Monat, Status
- Actions: Neu, Bearbeiten, Löschen, Schließen
-
DayDetail.razor (
/days/{id}):- Spieltag-Info (Datum, Status)
- Teilnehmerliste mit Anwesenheit
- Games des Tages
- PersonExpenses des Tages (Übersicht)
- Actions: Teilnehmer hinzufügen, Spiel hinzufügen, Status ändern
-
DayCreate.razor (
/days/new):- Formular: Datum, Vorauswahl Teilnehmer aus Mitgliedern
-
DayEdit.razor (
/days/{id}/edit):- Datum ändern, Teilnehmer hinzufügen/entfernen
3. SPIEL-BEREICH (Game Management)
Route: /days/{dayId}/games
Pages:
-
GameList.razor (
/days/{dayId}/games):- Liste der Spiele eines Spieltags
- Actions: Neues Spiel, Bearbeiten, Löschen
-
GameDetail.razor (
/days/{dayId}/games/{gameId}):- GameData anzeigen/bearbeiten (JSON-Editor oder strukturierte Eingabe)
- Teilnehmer des Spiels
- Kosten des Spiels (PersonExpenses mit GameId)
- Trigger-Events erfassen (z.B. "Pudel" → Expense zuweisen)
-
GameCreate.razor (
/days/{dayId}/games/new):- Teilnehmer auswählen (aus DayPersons)
- Optionale GameData-Initialisierung
4. KOSTEN-BEREICH (Expense Management)
Route: /expenses
Pages:
-
ExpenseList.razor (
/expenses):- Vordefinierte Expenses des Vereins
- Spalten: Name, Preis, Typ, IsOneClick, IsInverse, IsVariable
- Actions: Neu, Bearbeiten, Löschen
-
ExpenseCreate.razor (
/expenses/new):- Formular für neue Expense-Vorlage
- Trigger-Zuordnung optional
-
PersonExpenseList.razor (
/expenses/assigned):- Alle zugewiesenen Kosten (PersonExpenses)
- Filter: Person, Tag, Status (Open/Done), Datum
- Bulk-Actions: Als bezahlt markieren, Löschen
-
ExpenseTriggerConfig.razor (
/expenses/triggers):- Trigger-Typen anzeigen
- Zuordnung Trigger → Expense
5. PERSONEN-BEREICH (Person Management)
Route: /people
Pages:
-
PersonList.razor (
/people):- Tabelle: Name, Status (Member/Guest), Actions
- Filter: Status
- Actions: Neu, Bearbeiten, Löschen
-
PersonCreate.razor (
/people/new):- Name, Status
-
PersonDetail.razor (
/people/{id}):- Personen-Info
- Teilnahme-Historie (DayPersons)
- Kosten-Historie (PersonExpenses)
- Statistiken (Gesamtkosten, Anzahl Teilnahmen)
6. AUSWERTUNGEN-BEREICH (Reports/Evaluations)
Route: /reports
Pages:
-
ReportOverview.razor (
/reports):- Auswahl: Pro Person, Pro Tag, Pro Spiel
-
PersonReport.razor (
/reports/person/{id}):- Alle Kosten einer Person
- Summen pro Tag, pro Spiel
- Zeitraum-Filter
-
DayReport.razor (
/reports/day/{id}):- Alle Kosten eines Spieltags
- Aufschlüsselung pro Person
- Export-Option (PDF, CSV)
-
PeriodReport.razor (
/reports/period):- Zeitraum wählen (von-bis)
- Aggregierte Statistiken
- Top-Spieler, teuerste Tage, etc.
7. STAMMDATEN-BEREICH (Master Data - Vereins-spezifisch)
Route: /masterdata
Pages:
-
ClubSettings.razor (
/masterdata/club):- Vereins-Name
- ExpenseCalculation-Methode
- Weitere Einstellungen
-
ExpenseTemplates.razor (
/masterdata/expenses):- Siehe Expense-Bereich (evtl. Duplikat)
-
TriggerConfig.razor (
/masterdata/triggers):- Siehe ExpenseTriggerConfig
8. ADMIN-BEREICH (SuperAdmin - Vereinsübergreifend)
Route: /admin
Pages:
-
ClubList.razor (
/admin/clubs):- Alle Vereine (SuperAdmin only)
- Actions: Neu, Bearbeiten, Löschen
-
ClubCreate.razor (
/admin/clubs/new):- Name, ExpenseCalculation
-
UserManagement.razor (
/admin/users):- Alle UserProfiles
- Vereinszuordnung (UserProfileClub)
- Rollen-Zuordnung pro Verein
-
SystemSettings.razor (
/admin/system):- Globale Einstellungen
9. PROFIL-BEREICH (User Profile)
Route: /profile
Pages:
- UserProfile.razor (
/profile):- DisplayName, Locale, TimeZone ändern
- Passwort ändern
- Standard-Verein festlegen (UserProfileClub.IsDefault)
- Vereins-Mitgliedschaften anzeigen
Vorgeschlagene Navigation-Struktur
NavMenu.razor:
├── 🏠 Dashboard (/)
├── 📅 Spieltage (/days)
├── 👥 Personen (/people)
├── 💰 Kosten
│ ├── Vorlagen (/expenses)
│ ├── Zugewiesen (/expenses/assigned)
│ └── Trigger (/expenses/triggers)
├── 📊 Auswertungen (/reports)
│ ├── Pro Person
│ ├── Pro Tag
│ └── Zeitraum
├── ⚙️ Stammdaten (IsClubEditor+)
│ ├── Verein (/masterdata/club)
│ └── Kosten-Vorlagen
├── 🔧 Admin (IsSuperAdmin)
│ ├── Vereine (/admin/clubs)
│ ├── Benutzer (/admin/users)
│ └── System (/admin/system)
└── 👤 Profil (/profile)
Prioritäts-Vorschlag (Phasen) - basierend auf User-Feedback
Phase 1: MVP - Basis-Verwaltung (DIESE PLANUNG)
Scope: User/Account-Mgmt, Club, Personen (Teilnehmer), Tage, Strafen
-
User/Account-Verwaltung
- User-Registrierung (self-service oder Admin)
- Passwort zurücksetzen
- User-zu-Club Zuordnung (UserProfileClub)
- Rollen pro Club zuweisen (UserProfileClubRoleAssignment)
- User-Profil (DisplayName, Locale, TimeZone)
-
Club-Verwaltung (SuperAdmin)
- Liste, Create, Edit, Delete
- ExpenseCalculation-Methode
-
Person-Verwaltung (Club-Teilnehmer: Members + Guests)
- Liste, Create, Edit, Delete
- Status (Member/Guest)
- KEINE Login - reine Stammdaten für Kegelclub
-
Day-Verwaltung
- Liste, Create, Edit, Delete
- Datum, Status (New, Started, Closed, Postponed)
- Teilnehmer zuordnen (DayPerson)
-
PersonExpense - Strafen manuell erfassen
- Pro Teilnehmer pro Tag Strafen hinzufügen
- Expense-Vorlagen (Name, Preis)
- Status: Open/Done
-
Dashboard
- Übersicht: Nächste Tage, offene Kosten
- Quick-Actions
-
Einfache Auswertung
- Pro Tag: Wer schuldet was
- Pro Person: Summe offener Kosten
Phase 2: Detaillierte Spielverwaltung (SEPARATE PLANUNG SPÄTER)
NICHT in dieser Planung:
- Wurf-für-Wurf Eingabe
- Undo-Funktion
- Plugin-System für verschiedene Kegelspiele
- GameData strukturiert (JSON für jetzt)
- Automatische Trigger (Pudel, Pumpe, etc.)
- Expense-Trigger-Engine
Phase 3: Advanced Features (SPÄTER)
- Export (PDF, CSV)
- Benutzer-Rollen verwalten
- Erweiterte Reports
IMPLEMENTIERUNGSPLAN - Phase 1 MVP
Umsetzungsreihenfolge - Übersicht
| ✓ | Phase | Bereich | Beschreibung | Dateien |
|---|---|---|---|---|
| ✓ | A1 | Foundation | Repository Interfaces | 5 Interface-Dateien |
| ✓ | A2 | Foundation | Repository Implementations | 5 Repository-Dateien |
| ✓ | A3 | Foundation | DTOs | 5 DTO-Dateien |
| ✓ | A4 | Foundation | Service Interfaces | 5 Service-Interface-Dateien |
| ✓ | A5 | Foundation | Service Implementations | 5 Service-Dateien |
| ✓ | A6 | Foundation | AutoMapper Profiles | 5 Mapping-Dateien |
| ✓ | A7 | Foundation | DI Registration | 2 DI-Dateien ändern |
| ✓ | B1 | User/Account | UserService erweitern | 1 Service, 1 Interface, 1 DTO |
| ✓ | B2 | User/Account | Register Page | 1 Razor |
| ✓ | B3 | User/Account | Password Reset Pages | 2 Razor |
| ✓ | B4 | User/Account | Profile Page | 1 Razor |
| ✓ | B5 | User/Account | Admin Users Page | 1 Razor |
| ✓ | C1 | Clubs | ClubState Fluxor | 4 State-Dateien |
| ✓ | C2 | Clubs | Club Pages - ERSTES TESTBARES MVP | 1 Razor |
| ✓ | D1 | Personen | PersonState Fluxor | 4 State-Dateien |
| ✓ | D2 | Personen | Person Pages | 1 Razor |
| ☐ | D3 | Expenses | ExpenseState Fluxor | 4 State-Dateien |
| ☐ | D4 | Expenses | Expense Pages | 1 Razor |
| ☐ | E1 | Days | DayState Fluxor | 4 State-Dateien |
| ☐ | E2 | Days | Days List Page | 1 Razor |
| ☐ | E3 | Days | Day Details Page | 1 Razor |
| ☐ | E4 | Days | PersonExpense Management | Components in DayDetails |
| ☐ | F1 | Dashboard | Dashboard Page | 1 Razor |
| ☐ | F2 | Dashboard | Evaluation Components | 2 Shared Components |
| ☐ | F3 | Navigation | NavMenu finalisieren | 1 Razor ändern |
| ☐ | G1 | Erweiterte Reg. | MembershipStatus + UserProfileClub | 2 Dateien + Migration |
| ☐ | G2 | Erweiterte Reg. | ClubInvitation Entity | 1 Entity + Migration |
| ☐ | G3 | Erweiterte Reg. | IEmailService (Stub) | 2 Dateien |
| ☐ | G4 | Erweiterte Reg. | Services erweitern | 2 Services |
| ☐ | G5 | Erweiterte Reg. | Dashboard Pending-Widget | 1 Component |
| ☐ | G6 | Erweiterte Reg. | Admin Users Page erweitern | 1 Razor |
| ☐ | G7 | Erweiterte Reg. | Club-Beitritt UI | 1 Razor |
| ☐ | G8 | Erweiterte Reg. | Einladungslink-Handling | 2 Dateien |
Legende: ☐ = Offen | ☑ = In Arbeit | ✓ = Fertig
Geschätzte Dateien insgesamt: ~90 Dateien
Detaillierte Phasen
Phase A1: Repository Interfaces erstellen
Dateien:
src/Koogle.Domain/Interfaces/IClubRepository.cssrc/Koogle.Domain/Interfaces/IPersonRepository.cssrc/Koogle.Domain/Interfaces/IExpenseRepository.cssrc/Koogle.Domain/Interfaces/IDayRepository.cs(erweitern)src/Koogle.Domain/Interfaces/IPersonExpenseRepository.cs
Methoden pro Interface: GetAllAsync/GetByClubIdAsync, GetByIdAsync, AddAsync, UpdateAsync, DeleteAsync
Phase A2: Repository Implementations erstellen
Dateien:
src/Koogle.Infrastructure/Repositories/ClubRepository.cssrc/Koogle.Infrastructure/Repositories/PersonRepository.cssrc/Koogle.Infrastructure/Repositories/ExpenseRepository.cssrc/Koogle.Infrastructure/Repositories/DayRepository.cssrc/Koogle.Infrastructure/Repositories/PersonExpenseRepository.cs
Pattern: IDbContextFactory, ClubId-Filter, Include Navigation Properties
Phase A3: DTOs erstellen
Dateien:
src/Koogle.Application/DTOs/ClubDto.cs(ClubDto, CreateClubDto, UpdateClubDto)src/Koogle.Application/DTOs/PersonDto.cs(PersonDto, CreatePersonDto, UpdatePersonDto)src/Koogle.Application/DTOs/ExpenseDto.cs(ExpenseDto, CreateExpenseDto, UpdateExpenseDto)src/Koogle.Application/DTOs/DayDto.cserweitern (DayDto, CreateDayDto, UpdateDayDto, DayParticipantDto)src/Koogle.Application/DTOs/PersonExpenseDto.cs(PersonExpenseDto, CreatePersonExpenseDto, DayEvaluationDto, PersonDayEvaluationDto)
Phase A4: Service Interfaces erstellen
Dateien:
src/Koogle.Application/Interfaces/IClubService.cssrc/Koogle.Application/Interfaces/IPersonService.cssrc/Koogle.Application/Interfaces/IExpenseService.cssrc/Koogle.Application/Interfaces/IDayService.cs(erweitern)src/Koogle.Application/Interfaces/IPersonExpenseService.cs
Methoden: GetAllAsync, GetByIdAsync, CreateAsync, UpdateAsync, DeleteAsync + spezifische Methoden
Phase A5: Service Implementations erstellen
Dateien:
src/Koogle.Application/Services/ClubService.cssrc/Koogle.Application/Services/PersonService.cssrc/Koogle.Application/Services/ExpenseService.cssrc/Koogle.Application/Services/DayService.cs(erweitern)src/Koogle.Application/Services/PersonExpenseService.cs
Dependencies: Repository, ICurrentClubContext, ICurrentUserService, IMapper Business Logic: ClubId-Injection, Audit-Felder, Validierung (mittels FluentValidation)
Phase A6: AutoMapper Profiles erstellen
Dateien:
src/Koogle.Application/Mapping/ClubMappingProfile.cssrc/Koogle.Application/Mapping/PersonMappingProfile.cssrc/Koogle.Application/Mapping/ExpenseMappingProfile.cssrc/Koogle.Application/Mapping/DayMappingProfile.cssrc/Koogle.Application/Mapping/PersonExpenseMappingProfile.cs
Pattern: CreateMap<Entity, Dto>() bidirektional
Phase A7: DI Registration
Dateien ändern:
src/Koogle.Infrastructure/DependencyInjection.cs(5 Repositories registrieren)src/Koogle.Application/DependencyInjection.cs(5 Services registrieren)
Phase B1: UserService erweitern
Dateien:
src/Koogle.Application/Interfaces/IUserService.cserweiternsrc/Koogle.Application/Services/UserService.cserweiternsrc/Koogle.Application/DTOs/UserDto.cserweitern (RegisterUserDto, ResetPasswordDto, UpdateUserProfileDto)
Neue Methoden:
- RegisterUserAsync
- RequestPasswordResetAsync
- ResetPasswordAsync
- UpdateProfileAsync
- AssignUserToClubAsync, RemoveUserFromClubAsync
- AssignClubRoleAsync, RemoveClubRoleAsync
Phase B2: Register Page
Dateien:
src/Koogle.Web/Components/Pages/Account/Register.razor
Features: Email, Password, DisplayName, Optional ClubName für initiale Zuordnung
Phase B3: Password Reset Pages
Dateien:
src/Koogle.Web/Components/Pages/Account/ForgotPassword.razorsrc/Koogle.Web/Components/Pages/Account/ResetPassword.razor
Flow: Email eingeben → Token per Email → Passwort zurücksetzen
Phase B4: Profile Page
Dateien:
src/Koogle.Web/Components/Pages/Account/Profile.razor
Features: DisplayName, Locale, TimeZone, Club-Memberships anzeigen, Standard-Club setzen
Phase B5: Admin Users Page
Dateien:
src/Koogle.Web/Components/Pages/Admin/Users.razor
Features: User-Liste, Club-Zuordnungen, Rollen pro Club
Phase C1: ClubState (Fluxor)
Dateien:
src/Koogle.Web/Store/ClubState/ClubState.cssrc/Koogle.Web/Store/ClubState/ClubActions.cssrc/Koogle.Web/Store/ClubState/ClubReducers.cssrc/Koogle.Web/Store/ClubState/ClubEffects.cs
Actions: Load, Create, Update, Delete
Phase C2: Club Pages
Dateien:
src/Koogle.Web/Components/Pages/Admin/Clubs.razor
Features: MudTable, CRUD-Dialogs, SuperAdmin only
Phase D1: PersonState (Fluxor)
Dateien:
src/Koogle.Web/Store/PersonState/PersonState.cssrc/Koogle.Web/Store/PersonState/PersonActions.cssrc/Koogle.Web/Store/PersonState/PersonReducers.cssrc/Koogle.Web/Store/PersonState/PersonEffects.cs
Phase D2: Person Pages
Dateien:
src/Koogle.Web/Components/Pages/Persons/Persons.razor
Features: MudTable mit Filter (Member/Guest), CRUD
Phase D3: ExpenseState (Fluxor)
Dateien:
src/Koogle.Web/Store/ExpenseState/ExpenseState.cssrc/Koogle.Web/Store/ExpenseState/ExpenseActions.cssrc/Koogle.Web/Store/ExpenseState/ExpenseReducers.cssrc/Koogle.Web/Store/ExpenseState/ExpenseEffects.cs
Phase D4: Expense Pages
Dateien:
src/Koogle.Web/Components/Pages/Expenses/Expenses.razor
Features: MudTable mit Expense-Vorlagen, CRUD
Phase E1: DayState (Fluxor)
Dateien:
src/Koogle.Web/Store/DayState/DayState.cssrc/Koogle.Web/Store/DayState/DayActions.cssrc/Koogle.Web/Store/DayState/DayReducers.cssrc/Koogle.Web/Store/DayState/DayEffects.cs
State: Days, SelectedDay, SelectedDayExpenses, AvailablePersons
Phase E2: Days List Page
Dateien:
src/Koogle.Web/Components/Pages/Days/Days.razor
Features: MudTable mit Jahr-Filter, Create Day
Phase E3: Day Details Page
Dateien:
src/Koogle.Web/Components/Pages/Days/DayDetails.razor
Features:
- Day-Header (Datum, Status)
- Status-Workflow Buttons (New→Started→Closed)
- Teilnehmer-Sektion (Add/Remove)
- PersonExpense-Sektion
Phase E4: PersonExpense Management
Components in DayDetails:
- PersonExpense-Tabelle
- Add Expense Dialog (Person auswählen, Expense auswählen, Preis editierbar wenn IsVariable)
- Delete PersonExpense (nur in New/Started)
- IsInverse Logic: 1 Person auswählen → alle anderen bekommen Expense
Phase F1: Dashboard Page
Dateien:
src/Koogle.Web/Components/Pages/Dashboard.razor
Features: Summary Cards, Recent Days, Top Penalty Recipients
Phase F2: Evaluation Components
Dateien:
src/Koogle.Web/Components/Shared/DayEvaluationComponent.razorsrc/Koogle.Web/Components/Shared/PersonEvaluationComponent.razor
Phase F3: Navigation finalisieren
Dateien ändern:
src/Koogle.Web/Components/Layout/NavMenu.razor
Features: Dashboard, Spieltage, Stammdaten, Admin, Profil
Phase G1: MembershipStatus + UserProfileClub erweitern
Dateien:
-
src/Koogle.Domain/Enums/MembershipStatus.cs(neu)- Pending, Approved, Rejected
-
src/Koogle.Domain/Entities/UserProfileClub.cs(erweitern)- MembershipStatus Status (default: Pending)
- string? RejectionReason
- DateTime? ApprovedAt, Guid? ApprovedById
- DateTime? RejectedAt, Guid? RejectedById
-
Migration erstellen
Phase G2: ClubInvitation Entity
Dateien:
-
src/Koogle.Domain/Entities/ClubInvitation.cs(neu)- Guid Id, Guid ClubId
- string Token (unique, für URL)
- DateTime ExpiresAt, DateTime CreatedAt, Guid CreatedById
- int? MaxUses (null = unbegrenzt), int UsedCount
-
src/Koogle.Infrastructure/Data/AppDbContext.cs- DbSet hinzufügen -
Migration erstellen
Phase G3: IEmailService (Stub)
Dateien:
-
src/Koogle.Application/Interfaces/IEmailService.cs(neu)- SendMembershipRequestNotificationAsync
- SendMembershipApprovedAsync
- SendMembershipRejectedAsync
-
src/Koogle.Infrastructure/Services/StubEmailService.cs(neu)- Logging statt echtem Versand
- TODO-Kommentare für SMTP
-
DI Registration
Phase G4: Services erweitern (Membership-Logik)
UserService erweitern:
- RequestClubMembershipAsync(userProfileId, clubId)
- RequestClubMembershipByNameAsync(userProfileId, clubName)
- RequestClubMembershipByInviteAsync(userProfileId, inviteToken)
- ApproveMembershipAsync(userProfileId, clubId, approvedById)
- RejectMembershipAsync(userProfileId, clubId, rejectedById, reason)
- GetPendingMembershipsAsync(clubId)
ClubService erweitern:
- CreateInvitationAsync(clubId, createdById, expiresAt, maxUses)
- GetInvitationByTokenAsync(token)
- ValidateInvitationAsync(token)
Phase G5: Dashboard Pending-Widget
Dateien:
-
src/Koogle.Web/Components/Shared/PendingMembershipsWidget.razor(neu)- Anzahl ausstehender Anträge für Club-Admins
- Link zur Admin Users Page
-
Dashboard.razor erweitern - Widget für Admins einbinden
Phase G6: Admin Users Page erweitern
Dateien:
src/Koogle.Web/Components/Pages/Admin/Users.razor(ändern)- Tab/Filter für "Ausstehende Anträge"
- Approve/Reject Buttons
- Reject-Dialog mit Begründungsfeld
Phase G7: Club-Beitritt UI
Dateien:
-
src/Koogle.Web/Components/Pages/Account/JoinClub.razor(neu)- Eingabefeld für Club-Name
- Suche/Validierung
- Beitrittsantrag senden
- Erfolgsmeldung "Antrag gestellt"
-
Dashboard.razor erweitern
- "Keinem Club zugeordnet" Meldung mit Link zu JoinClub
Phase G8: Einladungslink-Handling
Dateien:
-
src/Koogle.Web/Components/Pages/Club/JoinByInvite.razor(neu)- Route:
/club/join/{token} - Token validieren
- Wenn eingeloggt: direkt Beitritt (Pending)
- Wenn nicht eingeloggt: Redirect zu Register mit Token
- Route:
-
src/Koogle.Web/Controllers/AuthController.cs(erweitern)- InviteToken als optionalen Parameter bei Register
Zentrale Anforderungen (User-Feedback)
Business Rules
- PersonExpense.Price: Bei IsVariable=true editierbar, aber vorbelegt aus Expense
- Day Status-Workflow: Strikt New→Started→Closed, keine Sprünge
- User-Registrierung: Self-Service (öffentlich)
- Passwort-Reset: Email-basiert mit Token
- Day-Create: Alle Members vorbelegt, Gäste manuell
- PersonExpense löschen: Nur in Status New/Started
- Expense.IsInverse: Automatisch - 1 Person auswählen, alle anderen bekommen Expense
- Dashboard Zeitraum: Aktuelles Jahr
Code-Patterns & Konventionen
Repository Pattern
- Interface in Domain/Interfaces
- Implementation in Infrastructure/Repositories
- Standard-Methoden: GetAllAsync, GetByIdAsync, AddAsync, UpdateAsync, DeleteAsync
- ClubId-Filter via ICurrentClubContext
- IDbContextFactory für Scoping
Service Pattern
- Interface in Application/Interfaces
- Implementation in Application/Services
- Dependencies: Repository, ICurrentClubContext, ICurrentUserService, IMapper
- ClubService: IsSuperAdmin Check
- Audit-Felder auto-setzen (CreatedById, CreatedAt, ModifiedById, ModifiedAt)
Fluxor Pattern (Redux)
- State: Record mit Collections + IsLoading + Error
- Actions: Record per Operation (Load, LoadSuccess, LoadFailure, Create, Update, Delete)
- Reducers: Pure functions, State transformieren
- Effects: Async Operations, Service-Calls, Dispatcher
UI Pattern (Blazor + MudBlazor)
- @inherits FluxorComponent
- @attribute [Authorize(Policy = "...")]
- MudTable für Listen
- MudDialog für Create/Edit
- MudForm mit Validation
Referenzdateien für Patterns
Service-Pattern:
src/Koogle.Application/Services/UserService.cs
Fluxor-Pattern:
src/Koogle.Web/Store/AuthState/AuthState.cssrc/Koogle.Web/Store/AuthState/AuthActions.cssrc/Koogle.Web/Store/AuthState/AuthReducers.cssrc/Koogle.Web/Store/AuthState/AuthEffects.cs
AutoMapper:
src/Koogle.Application/Mapping/UserProfile.cs
DI:
src/Koogle.Infrastructure/DependencyInjection.cssrc/Koogle.Application/DependencyInjection.cs
Domain:
src/Koogle.Domain/Entities/BaseEntity.cs
Berechtigungen pro Feature
- Club-Verwaltung: SuperAdmin only
- Person/Expense/Day CRUD: ClubEditor+
- Dashboard/Auswertungen: ClubViewer+
Policy: @attribute [Authorize(Policy = "ClubViewer|ClubEditor|ClubAdmin")]
Zusammenfassung
23 feine Phasen → ~75 Dateien → MVP Phase 1 komplett
Bereit für Implementierung Phase A1