diff --git a/src/Koogle.Web/Store/ClubState/ClubActions.cs b/src/Koogle.Web/Store/ClubState/ClubActions.cs
new file mode 100644
index 0000000..83d087f
--- /dev/null
+++ b/src/Koogle.Web/Store/ClubState/ClubActions.cs
@@ -0,0 +1,73 @@
+using Koogle.Application.DTOs;
+
+namespace Koogle.Web.Store.ClubState;
+
+///
+/// Action to load all clubs.
+///
+public record LoadClubsAction;
+
+///
+/// Action dispatched when clubs are loaded successfully.
+///
+public record LoadClubsSuccessAction(IReadOnlyList Clubs);
+
+///
+/// Action dispatched when loading clubs fails.
+///
+public record LoadClubsFailureAction(string Error);
+
+///
+/// Action to create a new club.
+///
+public record CreateClubAction(CreateClubDto Dto);
+
+///
+/// Action dispatched when club is created successfully.
+///
+public record CreateClubSuccessAction(ClubDto Club);
+
+///
+/// Action dispatched when creating club fails.
+///
+public record CreateClubFailureAction(string Error);
+
+///
+/// Action to update an existing club.
+///
+public record UpdateClubAction(UpdateClubDto Dto);
+
+///
+/// Action dispatched when club is updated successfully.
+///
+public record UpdateClubSuccessAction(ClubDto Club);
+
+///
+/// Action dispatched when updating club fails.
+///
+public record UpdateClubFailureAction(string Error);
+
+///
+/// Action to delete a club.
+///
+public record DeleteClubAction(Guid Id);
+
+///
+/// Action dispatched when club is deleted successfully.
+///
+public record DeleteClubSuccessAction(Guid Id);
+
+///
+/// Action dispatched when deleting club fails.
+///
+public record DeleteClubFailureAction(string Error);
+
+///
+/// Action to select a club for editing.
+///
+public record SelectClubAction(ClubDto? Club);
+
+///
+/// Action to clear club error state.
+///
+public record ClearClubErrorAction;
diff --git a/src/Koogle.Web/Store/ClubState/ClubEffects.cs b/src/Koogle.Web/Store/ClubState/ClubEffects.cs
new file mode 100644
index 0000000..7eb3906
--- /dev/null
+++ b/src/Koogle.Web/Store/ClubState/ClubEffects.cs
@@ -0,0 +1,112 @@
+using Fluxor;
+using Koogle.Application.Interfaces;
+
+namespace Koogle.Web.Store.ClubState;
+
+///
+/// Side effects for club state management.
+/// Handles async operations like API calls.
+///
+public class ClubEffects
+{
+ private readonly IClubService _clubService;
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the ClubEffects class.
+ ///
+ public ClubEffects(IClubService clubService, ILogger logger)
+ {
+ _clubService = clubService;
+ _logger = logger;
+ }
+
+ ///
+ /// Handles LoadClubsAction - loads all clubs from service.
+ ///
+ [EffectMethod]
+ public async Task HandleLoadClubs(LoadClubsAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Loading clubs");
+ var clubs = await _clubService.GetAllAsync();
+ dispatcher.Dispatch(new LoadClubsSuccessAction(clubs));
+ _logger.LogInformation("Loaded {Count} clubs", clubs.Count);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to load clubs");
+ dispatcher.Dispatch(new LoadClubsFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles CreateClubAction - creates a new club.
+ ///
+ [EffectMethod]
+ public async Task HandleCreateClub(CreateClubAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Creating club {Name}", action.Dto.Name);
+ var club = await _clubService.CreateAsync(action.Dto);
+ dispatcher.Dispatch(new CreateClubSuccessAction(club));
+ _logger.LogInformation("Created club {Name} with ID {Id}", club.Name, club.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to create club {Name}", action.Dto.Name);
+ dispatcher.Dispatch(new CreateClubFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles UpdateClubAction - updates an existing club.
+ ///
+ [EffectMethod]
+ public async Task HandleUpdateClub(UpdateClubAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Updating club {Id}", action.Dto.Id);
+ var club = await _clubService.UpdateAsync(action.Dto);
+ dispatcher.Dispatch(new UpdateClubSuccessAction(club));
+ _logger.LogInformation("Updated club {Name}", club.Name);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to update club {Id}", action.Dto.Id);
+ dispatcher.Dispatch(new UpdateClubFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles DeleteClubAction - deletes a club.
+ ///
+ [EffectMethod]
+ public async Task HandleDeleteClub(DeleteClubAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Deleting club {Id}", action.Id);
+ var success = await _clubService.DeleteAsync(action.Id);
+
+ if (success)
+ {
+ dispatcher.Dispatch(new DeleteClubSuccessAction(action.Id));
+ _logger.LogInformation("Deleted club {Id}", action.Id);
+ }
+ else
+ {
+ dispatcher.Dispatch(new DeleteClubFailureAction("Club konnte nicht gelöscht werden."));
+ _logger.LogWarning("Failed to delete club {Id} - not found or already deleted", action.Id);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to delete club {Id}", action.Id);
+ dispatcher.Dispatch(new DeleteClubFailureAction(ex.Message));
+ }
+ }
+}
diff --git a/src/Koogle.Web/Store/ClubState/ClubReducers.cs b/src/Koogle.Web/Store/ClubState/ClubReducers.cs
new file mode 100644
index 0000000..56f69cc
--- /dev/null
+++ b/src/Koogle.Web/Store/ClubState/ClubReducers.cs
@@ -0,0 +1,163 @@
+using Fluxor;
+
+namespace Koogle.Web.Store.ClubState;
+
+///
+/// Reducers for club state management.
+///
+public static class ClubReducers
+{
+ ///
+ /// Handles LoadClubsAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(LoadClubsAction))]
+ public static ClubState OnLoadClubs(ClubState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles LoadClubsSuccessAction - updates clubs list.
+ ///
+ [ReducerMethod]
+ public static ClubState OnLoadClubsSuccess(ClubState state, LoadClubsSuccessAction action)
+ => state with
+ {
+ Clubs = action.Clubs,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles LoadClubsFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static ClubState OnLoadClubsFailure(ClubState state, LoadClubsFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles CreateClubAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(CreateClubAction))]
+ public static ClubState OnCreateClub(ClubState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles CreateClubSuccessAction - adds club to list.
+ ///
+ [ReducerMethod]
+ public static ClubState OnCreateClubSuccess(ClubState state, CreateClubSuccessAction action)
+ => state with
+ {
+ Clubs = [.. state.Clubs, action.Club],
+ IsLoading = false
+ };
+
+ ///
+ /// Handles CreateClubFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static ClubState OnCreateClubFailure(ClubState state, CreateClubFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles UpdateClubAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(UpdateClubAction))]
+ public static ClubState OnUpdateClub(ClubState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles UpdateClubSuccessAction - replaces club in list.
+ ///
+ [ReducerMethod]
+ public static ClubState OnUpdateClubSuccess(ClubState state, UpdateClubSuccessAction action)
+ => state with
+ {
+ Clubs = state.Clubs.Select(c => c.Id == action.Club.Id ? action.Club : c).ToList(),
+ SelectedClub = state.SelectedClub?.Id == action.Club.Id ? action.Club : state.SelectedClub,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles UpdateClubFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static ClubState OnUpdateClubFailure(ClubState state, UpdateClubFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles DeleteClubAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(DeleteClubAction))]
+ public static ClubState OnDeleteClub(ClubState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles DeleteClubSuccessAction - removes club from list.
+ ///
+ [ReducerMethod]
+ public static ClubState OnDeleteClubSuccess(ClubState state, DeleteClubSuccessAction action)
+ => state with
+ {
+ Clubs = state.Clubs.Where(c => c.Id != action.Id).ToList(),
+ SelectedClub = state.SelectedClub?.Id == action.Id ? null : state.SelectedClub,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles DeleteClubFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static ClubState OnDeleteClubFailure(ClubState state, DeleteClubFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles SelectClubAction - sets selected club.
+ ///
+ [ReducerMethod]
+ public static ClubState OnSelectClub(ClubState state, SelectClubAction action)
+ => state with
+ {
+ SelectedClub = action.Club
+ };
+
+ ///
+ /// Handles ClearClubErrorAction - clears error state.
+ ///
+ [ReducerMethod(typeof(ClearClubErrorAction))]
+ public static ClubState OnClearError(ClubState state)
+ => state with
+ {
+ Error = null
+ };
+}
diff --git a/src/Koogle.Web/Store/ClubState/ClubState.cs b/src/Koogle.Web/Store/ClubState/ClubState.cs
new file mode 100644
index 0000000..d8ed7fd
--- /dev/null
+++ b/src/Koogle.Web/Store/ClubState/ClubState.cs
@@ -0,0 +1,47 @@
+using Fluxor;
+using Koogle.Application.DTOs;
+
+namespace Koogle.Web.Store.ClubState;
+
+///
+/// Fluxor state for club management.
+///
+[FeatureState]
+public record ClubState
+{
+ ///
+ /// List of all clubs.
+ ///
+ public IReadOnlyList Clubs { get; init; } = [];
+
+ ///
+ /// Currently selected club for editing.
+ ///
+ public ClubDto? SelectedClub { get; init; }
+
+ ///
+ /// Indicates whether a club operation is in progress.
+ ///
+ public bool IsLoading { get; init; }
+
+ ///
+ /// Error message if operation failed.
+ ///
+ public string? Error { get; init; }
+
+ ///
+ /// Private constructor for Fluxor initialization.
+ ///
+ private ClubState() { }
+
+ ///
+ /// Creates the initial state.
+ ///
+ public static ClubState Initial => new()
+ {
+ Clubs = [],
+ SelectedClub = null,
+ IsLoading = false,
+ Error = null
+ };
+}