Skip to main content

Redux Toolkit Migration Status

Overview

The Sanctum frontend uses a hybrid state management approach:

  • Redux Toolkit (RTK Query) for guild-related API calls
  • TanStack Query for features not supported by RTK Query

Migration Status

✅ Completed (11 story points)

  1. Redux Toolkit Setup (2 pts)

    • Installed @reduxjs/toolkit and react-redux
    • Created base RTK Query API configuration
    • Set up Redux store with TypeScript
    • Added Redux Provider to app root
  2. Guilds API Slice (3 pts)

    • Created comprehensive guildsApi with all endpoints
    • Implemented cache invalidation with tag system
    • Added hooks for all guild operations
  3. Guild Mutations Migration (3 pts)

    • Migrated useGuildMutations to RTK Query
    • Added backward-compatible wrapper layer
    • Proper error handling and success states
  4. Guild Pages Migration (3 pts)

    • Migrated home page to use useGetGuildsQuery
    • Migrated guild detail views to RTK Query
    • Hybrid approach for infinite scroll roster

Central Store Architecture

Redux Store Structure

{
// RTK Query API reducer (auto-generated)
api: {
queries: { ... }, // All API queries and their cached data
mutations: { ... }, // All API mutations and their status
},

// Client-side state slices
ui: {
sidebarCollapsed: boolean,
activeModal: string | null,
confirmDialog: { ... },
// ... global UI state
},

guilds: {
showArchived: boolean,
activeTab: string,
selectedMemberIds: string[],
rosterSortBy: string,
// ... guild page UI state
},

characters: {
showInactive: boolean,
selectedSyncSources: string[],
sortBy: string,
// ... character page UI state
},
}

API Slices (RTK Query)

All API calls are managed through RTK Query slices:

  1. guildsApi - Guild CRUD, settings, logos, roster sync
  2. charactersApi - Character CRUD, sync, templates
  3. rolesApi - Role management, permissions
  4. membersApi - Member management, role changes, history

Redux Slices (Client State)

All UI state is managed through Redux slices:

  1. uiSlice - Global UI (modals, sidebars, notifications, loading)
  2. guildsSlice - Guild page state (filters, tabs, selections)
  3. charactersSlice - Character page state (filters, sorting)

Current Architecture

RTK Query API Slices

// All API calls use RTK Query hooks:

// Guilds
useGetGuildsQuery({ includeArchived: false });
useGetGuildQuery({ guildId, page, pageSize });
useArchiveGuildMutation();
useUpdateGuildSettingsMutation();

// Characters
useGetCharactersQuery({ includeInactive: false });
useCreateCharacterMutation();
useSyncCharactersMutation();

// Roles
useGetRolesQuery(guildId);
useCreateRoleMutation();
useUpdateRolePermissionsMutation();

// Members
useChangeMemberRoleMutation();
useRemoveMemberMutation();
useGetMemberRoleHistoryQuery();

Redux Slices for UI State

// All client state uses Redux actions:

import { useAppDispatch, useAppSelector } from './store/hooks';

// UI state
dispatch(openModal('guild-settings'));
dispatch(showConfirmDialog({ title, message, onConfirm }));
const sidebarCollapsed = useAppSelector((state) => state.ui.sidebarCollapsed);

// Guild UI state
dispatch(setShowArchived(true));
dispatch(toggleRosterSort('name'));
const activeTab = useAppSelector((state) => state.guilds.activeTab);

// Character UI state
dispatch(toggleShowInactive());
dispatch(setSortBy('level'));
const filters = useAppSelector((state) => state.characters);

Files Using Each Library

RTK Query

  • /apps/web/src/store/api/guildsApi.ts - Guild endpoints
  • /apps/web/src/hooks/useGuildMutations.ts - Guild mutations wrapper
  • /apps/web/src/routes/index.tsx - Home page guilds list
  • /apps/web/src/routes/guilds/$guildId/-hooks.ts - Guild base data

TanStack Query (Remaining)

  • /apps/web/src/routes/guilds/$guildId/-hooks.ts - Infinite scroll roster
  • /apps/web/src/routes/characters/ - Character management
  • /apps/web/src/components/MemberManagement/ - Member modals
  • /apps/web/src/routes/guilds/create.tsx - Guild creation form

Migration Guidelines

When to Use RTK Query

  • ✅ CRUD operations for core domain entities
  • ✅ Simple list/detail queries
  • ✅ Mutations with cache invalidation
  • ✅ Features requiring optimistic updates

When to Keep TanStack Query

  • ✅ Infinite scroll / cursor pagination
  • ✅ Temporary/form-specific queries
  • ✅ Features with complex query dependencies
  • ✅ Low-priority pages pending migration

Future Considerations

Phase 2 Migration (Optional, Future)

If infinite query patterns become common, consider:

  1. Custom RTK Query infinite pagination solution
  2. Migrate remaining character/member management
  3. Full TanStack Query removal

Current Decision

The hybrid approach is intentional and pragmatic:

  • Leverages strengths of both libraries
  • Minimizes migration cost
  • Provides clear boundaries (guild domain = RTK Query)
  • Keeps bundle size reasonable (~50KB for both libraries)

Testing

Both libraries are properly configured for testing:

// RTK Query tests
import { store } from './store';
import { Provider } from 'react-redux';

<Provider store={store}>
<ComponentUnderTest />
</Provider>

// TanStack Query tests (keep for hybrid features)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<ComponentUnderTest />
</QueryClientProvider>

Performance Impact

  • Bundle Size: +~50KB for both libraries (acceptable trade-off)
  • Runtime: No performance issues, both libraries are optimized
  • Cache: Separate caches work independently, no conflicts

Documentation

  • Redux Toolkit patterns: .cursor/rules/Redux-Toolkit-Standards.mdc
  • Component architecture: .cursor/rules/React-Component-Architecture.mdc
  • Project guidelines: .cursor/rules/Guild-Platform-project.mdc