Zusammenfassung der Änderungen:
1. GameState.cs - Neue Properties hinzugefügt:
- IsGameOver - zeigt an, dass das Spiel beendet ist
- WinnerId - ID des Gewinners
2. GameReducers.cs:
- OnProcessThrowResult setzt jetzt IsGameOver und WinnerId
- OnExecuteGameActionSuccess setzt jetzt IsGameOver und WinnerId
- OnStartGameSuccess setzt IsGameOver=false
- OnEndGameSuccess setzt IsGameOver=false
3. GameEffects.cs:
- HandleRecordThrow blockiert Eingaben wenn IsGameOver=true
- HandleExecuteGameAction blockiert Eingaben wenn IsGameOver=true
- EndGameAction wird nicht automatisch dispatcht - der Benutzer muss das Spiel explizit über die UI beenden
Verhalten jetzt:
- Wenn ProcessThrow oder ExecuteAction IsGameOver=true zurückgibt, wird der State auf IsGameOver=true gesetzt
- Die Tafel bleibt sichtbar mit dem Endergebnis
- Weitere Würfe/Actions werden blockiert
- Der Benutzer muss EndGameAction explizit über einen Button in der UI auslösen
Die UI muss jetzt GameState.IsGameOver und GameState.WinnerId nutzen, um:
1. Eingaben zu deaktivieren
2. Eine "Spiel beenden"-Schaltfläche anzuzeigen
Zusammenfassung der Fixes:
1. Fix 1 (HandlePinClick und HandleNumberClick): _hasModifiedPins = true wird jetzt VOR dem Dispatch gesetzt, um zu verhindern, dass OnGameStateChanged den Before-State während der Pin-Modifikation überschreibt.
2. Fix 2 (ConfirmThrow): Nach dem Dispatch wird explizit CaptureBeforeThrowState() aufgerufen. Das ist der wichtigste Fix:
- Nach RecordThrowAction Dispatch sind alle Reducer/Effects durchgelaufen
- Der State ist bereits mit den neuen Pin-Zuständen aktualisiert
- _beforeThrowState wird mit dem NEUEN Zustand für den nächsten Wurf erfasst
Vorher wurde _beforeThrowState nie nach einem Wurf aktualisiert (weil _hasModifiedPins zum falschen Zeitpunkt gesetzt war), sodass beim zweiten Wurf der stale Before-State verwendet wurde.
- IGameHubClient: client interface for SignalR messages
- GameHub: SignalR hub with group management for games/days
- GameHubService: scoped service wrapper with auto-reconnect
- GameEffects: broadcasts game start/end/state via SignalR
- EndGameAction: extended with winner info and final scores
- Program.cs: AddSignalR + MapHub configuration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extend Game entity with GameType, Status, StartedAt, CompletedAt, RowVersion
- Add GameConfiguration with RowVersion for optimistic concurrency
- Create IGamePersistenceService interface
- Implement GamePersistenceService with CRUD operations
- Create GameStateSerializationDto for JSON serialization
- Extend GameEffects with full persistence lifecycle:
- HandleStartGame: Creates game in DB
- HandleEndGame: Updates status to Completed/Aborted
- HandleLoadActiveGame: Recovery from page reload
- HandleRecordThrow: Debounced save (500ms)
- HandleSaveGameState: Explicit save with concurrency check
- Add migration ExtendGameEntity
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add UndoButton.razor as reusable component
- Refactor GameInputPanel to use UndoButton component
- Enhance GameEffects with proper UndoThrowAction handler
- IState injection for state access in effects
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Scoped services can't be resolved from singleton (GameDefinitionRegistry).
Logic services are stateless, so transient is appropriate.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- GameBoardPanel: Dynamic board component rendering
- CompletedGamesList: Shows game history for day
- DayDetails: 3 tabs (Details/Eingabe/Tafel) + Start/End Game buttons
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- GameTypeSelector: Select game type from registry
- ParticipantSelector: Multi-select participants from day
- CommonSetupOptions: ThrowMode, ThrowsPerRound, ParticipantsMode
- GameSetupDialog: Full setup wizard with DynamicComponent
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- TrainingGameDefinition with game type metadata
- TrainingGameModel + TrainingPlayerStats for stats tracking
- TrainingGameLogicService implementing game logic
- TrainingSetup.razor for config (ThrowMode, ThrowsPerRound, ParticipantsMode)
- TrainingBoard.razor showing player stats table with totals/averages
- Game type registration in Program.cs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- IGameDefinition interface in Domain
- GameProgress.cs with throw state records
- IGameLogicService interface
- GameDefinitionRegistry for polymorphic game types
- GameModelFactory for JSON serialization
- DI registration extensions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- GameType, GameStatus, PinStatus, ThrowMode, ParticipantsMode enums
- GameState with ThrowPanelState, ParticipantsState, GameSnapshot
- GameActions for lifecycle, throws, undo, persistence, SignalR
- GameReducers for all actions
- GameEffects placeholder for later phases
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ITriggerRepository interface + TriggerRepository implementation
- ITriggerService interface + TriggerService implementation
- TriggerDto, ExpenseTriggerLinkDto, FireTriggerDto
- FireTriggerAsync creates PersonExpenses with multiplier
- DI registration for both services
- Fix test mock for IClubRepository
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- new PendingMembershipsWidget.razor shows pending membership count
- only visible to club admins/super admins
- integrated into Dashboard.razor
- click navigates to admin users page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- IEmailService in Domain/Interfaces for membership notifications
- StubEmailService in Infrastructure/Services logs instead of sending
- TODO comments for future SMTP implementation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ClubInvitation: Token, ExpiresAt, MaxUses, UsedCount
- Unique index on Token
- DbSet + EF Configuration
- Migration applied
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dashboard link (all authenticated users)
- Spieltage, Personen (club-specific, require selected club)
- Stammdaten with Kostenvorlagen (ClubEditor+)
- Administration section with Vereine/Benutzer (SuperAdmin)
- Profile link for authenticated users
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DayEvaluationComponent: shows day expense summary per person
- PersonEvaluationComponent: shows person expense summary + details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DashboardDto, IDashboardService, DashboardService
- Summary cards: members, guests, days, open expenses
- Recent days list with navigation
- Top penalty recipients list
- Home redirects to /dashboard
- Updated HomePageTests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extend DayState with SelectedDayExpenses, AvailableExpenses
- Add Fluxor actions for load/create/update/delete expenses
- Add reducers + effects for PersonExpense operations
- Create AddPersonExpenseDialog with inverse expense support
- Update DayDetails with expense table, summary, status toggle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ExpenseState.cs: state record with Expenses, SelectedExpense, IsLoading, Error
- ExpenseActions.cs: Load/Create/Update/Delete actions + Select/ClearError
- ExpenseReducers.cs: pure state transformations
- ExpenseEffects.cs: async service calls with logging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary of all fixes
3 files changed:
1. src/Koogle.Application/Services/UserService.cs:140-171
- GetByIdentityUserIdAsync now includes .Include(p => p.Clubs) and maps ClubMemberships
2. src/Koogle.Web/Store/AuthState/AuthEffects.cs:53-73
- Merges club-specific roles from ClubMemberships into AuthState roles
3. src/Koogle.Infrastructure/Security/ClubRoleRequirement.cs:17-114
- Changed ClubRoleHandler to extend AuthorizationHandler<ClubRoleRequirement> (no resource)
- Reads current_club_id from claims to determine club context
- Added ClubRoleResourceHandler for resource-based auth (explicit clubId)
4. src/Koogle.Infrastructure/DependencyInjection.cs:72
- Registered ClubRoleResourceHandler
The [Authorize(Policy = "ClubViewer")] attribute now uses current_club_id claim set during login to check club roles.
- Persons.razor: MudTable with search/filter, CRUD dialogs
- PersonEditDialog.razor: Create/Edit form for persons
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- PersonState.cs: State record with Persons, SelectedPerson, IsLoading, Error
- PersonActions.cs: Load/Create/Update/Delete actions with success/failure variants
- PersonReducers.cs: Pure reducers for all person actions
- PersonEffects.cs: Async effects calling IPersonService
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Clubs.razor: MudTable with search, create/edit/delete
- ClubEditDialog.razor: Form for club name + expense calculation
- ConfirmDialog.razor: Reusable confirmation dialog
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>