diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md
index 50c0f3c..7af3e30 100644
--- a/docs/IMPLEMENTATION_PLAN.md
+++ b/docs/IMPLEMENTATION_PLAN.md
@@ -1709,7 +1709,7 @@ public enum CashBookEntryType { Income = 0, Expense = 1 }
| ✓ | K8 | Application | Service Implementations | 4 |
| ✓ | K9 | Application | Category Seeder | 1 |
| ✓ | K10 | Application | Day Close Integration | 1 |
-| ☐ | K11 | Web | Fluxor CategoryState | 4 |
+| ✓ | K11 | Web | Fluxor CategoryState | 4 |
| ☐ | K12 | Web | Fluxor CashBookState | 4 |
| ☐ | K13 | Web | CashBook UI | 3 |
| ☐ | K14 | Web | Categories UI | 2 |
diff --git a/src/Koogle.Web/Store/CategoryState/CategoryActions.cs b/src/Koogle.Web/Store/CategoryState/CategoryActions.cs
new file mode 100644
index 0000000..c53fd5b
--- /dev/null
+++ b/src/Koogle.Web/Store/CategoryState/CategoryActions.cs
@@ -0,0 +1,73 @@
+using Koogle.Application.DTOs;
+
+namespace Koogle.Web.Store.CategoryState;
+
+///
+/// Action to load all booking categories for the current club.
+///
+public record LoadCategoriesAction(bool IncludeInactive = false);
+
+///
+/// Action dispatched when categories are loaded successfully.
+///
+public record LoadCategoriesSuccessAction(IReadOnlyList Categories);
+
+///
+/// Action dispatched when loading categories fails.
+///
+public record LoadCategoriesFailureAction(string Error);
+
+///
+/// Action to create a new booking category.
+///
+public record CreateCategoryAction(CreateBookingCategoryDto Dto);
+
+///
+/// Action dispatched when category is created successfully.
+///
+public record CreateCategorySuccessAction(BookingCategoryDto Category);
+
+///
+/// Action dispatched when creating category fails.
+///
+public record CreateCategoryFailureAction(string Error);
+
+///
+/// Action to update an existing booking category.
+///
+public record UpdateCategoryAction(UpdateBookingCategoryDto Dto);
+
+///
+/// Action dispatched when category is updated successfully.
+///
+public record UpdateCategorySuccessAction(BookingCategoryDto Category);
+
+///
+/// Action dispatched when updating category fails.
+///
+public record UpdateCategoryFailureAction(string Error);
+
+///
+/// Action to delete a booking category.
+///
+public record DeleteCategoryAction(Guid Id);
+
+///
+/// Action dispatched when category is deleted successfully.
+///
+public record DeleteCategorySuccessAction(Guid Id);
+
+///
+/// Action dispatched when deleting category fails.
+///
+public record DeleteCategoryFailureAction(string Error);
+
+///
+/// Action to select a category for editing.
+///
+public record SelectCategoryAction(BookingCategoryDto? Category);
+
+///
+/// Action to clear category error state.
+///
+public record ClearCategoryErrorAction;
diff --git a/src/Koogle.Web/Store/CategoryState/CategoryEffects.cs b/src/Koogle.Web/Store/CategoryState/CategoryEffects.cs
new file mode 100644
index 0000000..a8175af
--- /dev/null
+++ b/src/Koogle.Web/Store/CategoryState/CategoryEffects.cs
@@ -0,0 +1,112 @@
+using Fluxor;
+using Koogle.Application.Interfaces;
+
+namespace Koogle.Web.Store.CategoryState;
+
+///
+/// Side effects for booking category state management.
+/// Handles async operations like API calls.
+///
+public class CategoryEffects
+{
+ private readonly IBookingCategoryService _categoryService;
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the CategoryEffects class.
+ ///
+ public CategoryEffects(IBookingCategoryService categoryService, ILogger logger)
+ {
+ _categoryService = categoryService;
+ _logger = logger;
+ }
+
+ ///
+ /// Handles LoadCategoriesAction - loads all categories from service.
+ ///
+ [EffectMethod]
+ public async Task HandleLoadCategories(LoadCategoriesAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Loading booking categories");
+ var categories = await _categoryService.GetAllAsync(action.IncludeInactive);
+ dispatcher.Dispatch(new LoadCategoriesSuccessAction(categories));
+ _logger.LogInformation("Loaded {Count} booking categories", categories.Count);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to load booking categories");
+ dispatcher.Dispatch(new LoadCategoriesFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles CreateCategoryAction - creates a new category.
+ ///
+ [EffectMethod]
+ public async Task HandleCreateCategory(CreateCategoryAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Creating booking category {Name}", action.Dto.Name);
+ var category = await _categoryService.CreateAsync(action.Dto);
+ dispatcher.Dispatch(new CreateCategorySuccessAction(category));
+ _logger.LogInformation("Created booking category {Name} with ID {Id}", category.Name, category.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to create booking category {Name}", action.Dto.Name);
+ dispatcher.Dispatch(new CreateCategoryFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles UpdateCategoryAction - updates an existing category.
+ ///
+ [EffectMethod]
+ public async Task HandleUpdateCategory(UpdateCategoryAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Updating booking category {Id}", action.Dto.Id);
+ var category = await _categoryService.UpdateAsync(action.Dto);
+ dispatcher.Dispatch(new UpdateCategorySuccessAction(category));
+ _logger.LogInformation("Updated booking category {Name}", category.Name);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to update booking category {Id}", action.Dto.Id);
+ dispatcher.Dispatch(new UpdateCategoryFailureAction(ex.Message));
+ }
+ }
+
+ ///
+ /// Handles DeleteCategoryAction - deletes a category.
+ ///
+ [EffectMethod]
+ public async Task HandleDeleteCategory(DeleteCategoryAction action, IDispatcher dispatcher)
+ {
+ try
+ {
+ _logger.LogDebug("Deleting booking category {Id}", action.Id);
+ var success = await _categoryService.DeleteAsync(action.Id);
+
+ if (success)
+ {
+ dispatcher.Dispatch(new DeleteCategorySuccessAction(action.Id));
+ _logger.LogInformation("Deleted booking category {Id}", action.Id);
+ }
+ else
+ {
+ dispatcher.Dispatch(new DeleteCategoryFailureAction("Kategorie konnte nicht gelöscht werden."));
+ _logger.LogWarning("Failed to delete booking category {Id} - not found or system category", action.Id);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to delete booking category {Id}", action.Id);
+ dispatcher.Dispatch(new DeleteCategoryFailureAction(ex.Message));
+ }
+ }
+}
diff --git a/src/Koogle.Web/Store/CategoryState/CategoryReducers.cs b/src/Koogle.Web/Store/CategoryState/CategoryReducers.cs
new file mode 100644
index 0000000..1107f8f
--- /dev/null
+++ b/src/Koogle.Web/Store/CategoryState/CategoryReducers.cs
@@ -0,0 +1,163 @@
+using Fluxor;
+
+namespace Koogle.Web.Store.CategoryState;
+
+///
+/// Reducers for booking category state management.
+///
+public static class CategoryReducers
+{
+ ///
+ /// Handles LoadCategoriesAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(LoadCategoriesAction))]
+ public static CategoryState OnLoadCategories(CategoryState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles LoadCategoriesSuccessAction - updates categories list.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnLoadCategoriesSuccess(CategoryState state, LoadCategoriesSuccessAction action)
+ => state with
+ {
+ Categories = action.Categories,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles LoadCategoriesFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnLoadCategoriesFailure(CategoryState state, LoadCategoriesFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles CreateCategoryAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(CreateCategoryAction))]
+ public static CategoryState OnCreateCategory(CategoryState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles CreateCategorySuccessAction - adds category to list.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnCreateCategorySuccess(CategoryState state, CreateCategorySuccessAction action)
+ => state with
+ {
+ Categories = [.. state.Categories, action.Category],
+ IsLoading = false
+ };
+
+ ///
+ /// Handles CreateCategoryFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnCreateCategoryFailure(CategoryState state, CreateCategoryFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles UpdateCategoryAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(UpdateCategoryAction))]
+ public static CategoryState OnUpdateCategory(CategoryState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles UpdateCategorySuccessAction - replaces category in list.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnUpdateCategorySuccess(CategoryState state, UpdateCategorySuccessAction action)
+ => state with
+ {
+ Categories = state.Categories.Select(c => c.Id == action.Category.Id ? action.Category : c).ToList(),
+ SelectedCategory = state.SelectedCategory?.Id == action.Category.Id ? action.Category : state.SelectedCategory,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles UpdateCategoryFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnUpdateCategoryFailure(CategoryState state, UpdateCategoryFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles DeleteCategoryAction - sets loading state.
+ ///
+ [ReducerMethod(typeof(DeleteCategoryAction))]
+ public static CategoryState OnDeleteCategory(CategoryState state)
+ => state with
+ {
+ IsLoading = true,
+ Error = null
+ };
+
+ ///
+ /// Handles DeleteCategorySuccessAction - removes category from list.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnDeleteCategorySuccess(CategoryState state, DeleteCategorySuccessAction action)
+ => state with
+ {
+ Categories = state.Categories.Where(c => c.Id != action.Id).ToList(),
+ SelectedCategory = state.SelectedCategory?.Id == action.Id ? null : state.SelectedCategory,
+ IsLoading = false
+ };
+
+ ///
+ /// Handles DeleteCategoryFailureAction - sets error state.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnDeleteCategoryFailure(CategoryState state, DeleteCategoryFailureAction action)
+ => state with
+ {
+ IsLoading = false,
+ Error = action.Error
+ };
+
+ ///
+ /// Handles SelectCategoryAction - sets selected category.
+ ///
+ [ReducerMethod]
+ public static CategoryState OnSelectCategory(CategoryState state, SelectCategoryAction action)
+ => state with
+ {
+ SelectedCategory = action.Category
+ };
+
+ ///
+ /// Handles ClearCategoryErrorAction - clears error state.
+ ///
+ [ReducerMethod(typeof(ClearCategoryErrorAction))]
+ public static CategoryState OnClearError(CategoryState state)
+ => state with
+ {
+ Error = null
+ };
+}
diff --git a/src/Koogle.Web/Store/CategoryState/CategoryState.cs b/src/Koogle.Web/Store/CategoryState/CategoryState.cs
new file mode 100644
index 0000000..30b4fb2
--- /dev/null
+++ b/src/Koogle.Web/Store/CategoryState/CategoryState.cs
@@ -0,0 +1,47 @@
+using Fluxor;
+using Koogle.Application.DTOs;
+
+namespace Koogle.Web.Store.CategoryState;
+
+///
+/// Fluxor state for booking category management.
+///
+[FeatureState]
+public record CategoryState
+{
+ ///
+ /// List of all booking categories for the current club.
+ ///
+ public IReadOnlyList Categories { get; init; } = [];
+
+ ///
+ /// Currently selected category for editing.
+ ///
+ public BookingCategoryDto? SelectedCategory { get; init; }
+
+ ///
+ /// Indicates whether a category 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 CategoryState() { }
+
+ ///
+ /// Creates the initial state.
+ ///
+ public static CategoryState Initial => new()
+ {
+ Categories = [],
+ SelectedCategory = null,
+ IsLoading = false,
+ Error = null
+ };
+}