Changelog
Recent updates and changes to the Sanctum platform.
February 21, 2026โ
๐ Blizzard API Localizationโ
Multi-locale support for journal game data (expansions, instances, encounters).
Backendโ
- โ
Added
JournalExpansionLocale,JournalInstanceLocale,JournalEncounterLocalePrisma models with composite(entityId, locale)keys - โ
Prisma migration:
add_journal_locale_tables - โ
BattleNetAdapterโ addedlocaleparameter to journal methods + text-only fetch methods (getJournalInstanceText,getJournalEncounterText) - โ
JournalInstanceSyncServiceโ fetches all 6 Blizzard locales during sync (5 non-English locales fetched in parallel viaPromise.all, ~70s for locale phase) - โ
GameDataServiceโ locale-aware queries with English fallback; cache keys include locale - โ
GameDataControllerโ optional?locale=query parameter on all endpoints - โ
JournalInstanceSyncProcessorโ cache invalidation clears all locale-scoped keys - โ
Shared locale utilities (
apps/api/src/common/locale.ts)
Frontendโ
- โ
useBlizzardLocale()hook โ maps i18next language to Blizzard locale code - โ
appLocaleToBlizzard()utility (shared between API and web) - โ
RTK Query endpoints (
gameDataApi) accept and passlocaleparameter - โ
All call sites updated:
EventCard,EventDetail,EventActivityDetailsSection,useEventFormState
Testsโ
- โ
locale.spec.tsโ backend locale utilities - โ
game-data.service.spec.tsโ locale-aware data retrieval and cache keys - โ
locale.test.tsโ frontend locale mapping
๐ Mobile Nav i18nโ
- โ
DrawerGuildSectionโ replaced 14 hardcoded strings witht()calls using existingguild:nav.*,guild:settingsNav.*, andguild:memberskeys - โ
MobileNavDrawerโ replaced "Menu", "Admin", and aria-label strings witht()calls - โ
Added
navigation.menuandnavigation.mainNavigationkeys to all 7 locale files
๐ฆ Dependency Updatesโ
- dotenv v17 โ bumped from v16. Only behavioral change: startup log now shows by default (
[dotenv] injecting env (N) from .env). Suppress withDOTENV_CONFIG_QUIET=trueif needed. - ESLint v10 โ bumped from v9. Already on flat config so migration was minimal. Wrapped
eslint-plugin-reactwith@eslint/compat'sfixupPluginRules()to bridge the removedcontext.getFilename()API. Added@eslint/compatto root devDependencies. - cache-manager-redis-yet โ @keyv/redis โ replaced the old Redis store adapter with
@keyv/redis(Keyv-native).CacheModulefactory is now synchronous; usesstores: [createKeyv(options)]instead of the oldstore+ asyncredisStore(). Cache invalidation handler updated to accessstores[0].store.clientfor pattern-based key deletion. - Tailwind CSS v4 โ upgraded from v3. Switched from PostCSS plugin to
@tailwindcss/vite(faster Vite-native processing). Removedautoprefixer(v4 handles vendor prefixes natively).index.cssupdated from@tailwinddirectives to@import "tailwindcss"+@configto keep the existing HeroUI theme config in place.
February 20, 2026โ
โก Session Check Performance Fixโ
Fixed redundant GET /api/v1/auth/get-session calls on every client-side navigation.
- Problem:
requireAuth()in TanStack RouterbeforeLoadguards calledauthClient.getSession()(a direct fetch) on every navigation to a protected route (~15 routes). This was independent of theauthClient.useSession()nanostores atom used in components, resulting in unnecessary server round-trips on every page change. - Fix: Added a 60-second TTL cache and request deduplication to
auth.getSession()inapps/web/src/lib/auth.ts. Subsequent navigations within the window return the cached session.signOut()andinvalidateSession()clear the cache immediately.
February 16, 2026โ
๐ Events Calendar UI Improvementsโ
Event Card Layoutโ
- โ
Two-row layout โ Event cards restructured for better readability
- Row 1: Status icons + Title + Time
- Row 2: Event type icon + Recurring icon + Signup count
- โ Accessibility โ Changed raid event color from red to primary blue for better contrast
- โ Today button โ Moved between month navigation arrows for better UX (< Today >)
Week Overview on Guild Overview Pageโ
- โ Next 7 Days grid โ Shows upcoming events in 7-day grid view
- โ Responsive layout โ Single column on mobile, single row on desktop
- โ Quick navigation โ "View calendar" button links to full events page
- โ Event details โ Each day shows up to 3 events with time, "+X more" indicator
๐ Events UI Enhancementsโ
View Modes & Filtersโ
- โ Month / Week / List โ ButtonGroup to switch between calendar month, week (current week grid), and list views
- โ Search โ Filter events by title or creator name (client-side on loaded data)
- โ Event type filters โ Toggle raid, dungeon, social, pvp chips to show/hide types
- โ
Date range โ Calendar and week views use
startDate/endDateonGET /guilds/:guildId/eventsfor efficient loading; list view uses pagination
Calendar UXโ
- โ Week view โ Current week grid with day cells; same event cards and date selection as month
- โ Today โ "Today" button resets month/year and clears selected date
- โ
Prev/Next month โ Icon buttons with
aria-label="Previous month"/"Next month" - โ Date selection โ Click day to filter events to that date; click again to clear
Event Cards & Navigationโ
- โ Prefetch โ Event detail route prefetched on card hover/focus for faster navigation
- โ
Child route โ Events page renders
<Outlet />when on/events/$eventIdso list/calendar donโt flash during navigation
Accessibilityโ
- โ
EventSlotsSection โ
Select(role) andInput(max count) havearia-labelper slot (e.g. "Role for slot 1", "Max count for slot 1") for screen readers
๐ง Organization Detail API Fixesโ
Roster Members in Organization Detail Responseโ
- โ
GET /organizations/:idnow acceptspage,pageSize,sortBy,sortOrderquery params - โ
Returns
rosterMembers(full guild roster from Blizzard sync) withclaimedByCharacterrelations - โ
Returns
rosterPagination(page, pageSize, total, totalPages) for infinite scroll - โ
Previously only returned
memberships(user's own synced characters), now returns the full guild roster
CASL Ability Rules & Permission Fixโ
- โ
GetOrganizationDetailUseCasenow generates real CASL ability rules viaAbilityFactory - โ
Membership lookup uses
orderBy: { role: { wowRank: 'asc' } }to pick highest-ranked character - โ
Fixed "Guild Roster is Private" showing for guild masters due to empty
abilityRules: []
WowGuild Data in Organization Responsesโ
- โ Organization detail and list endpoints now include WowGuild fields (realm, faction, emblemData, logoUrl, etc.)
- โ
currentLogoUrlcomputed fromuseCustomLogopreference - โ
rolesarray included in organization detail response
Guild Text Content Endpointsโ
- โ
GET /organizations/:id/text-contentโ fetch all text content types (motd, rules, loot_rules, etc.) - โ
PATCH /organizations/:id/text-contentโ update text content with version history tracking
๐ Last Login & Character Sync UXโ
Last Login Persistenceโ
- โ
Character.lastLoginAtโ when character was last played (from Blizzard profile) - โ
GuildMember.lastLoginAtโ persisted during roster sync avatar fetch - โ
Character enrichment processor persists
lastLoginAtfromlast_login_timestamp - โ
Avatar fetch processor parses and persists
lastLoginAtfor roster members - โ
When claimed, roster sync also updates linked Character's
lastLoginAt
Display & Sortโ
- โ
Guild roster "Last seen" โ uses
lastLoginAtwhen available, else N/A - โ Character cards show both "Last synced" and "Last login"
- โ Characters page sort by "Last login" (most recent first, nulls last)
- โ
Guild detail sort by last seen uses
lastLoginAtwith fallback tolastSeenInRoster
Role & Cache Fixesโ
- โ Role endpoints resolve guild by ID or alias (fixes 404 when using alias in URL)
- โ Role updates (create, update, delete, permissions) bust guild cache
- โ Guild cache invalidation by both ID and alias
Character Sync UXโ
- โ Dismiss button on sync progress when complete or failed (desktop + mobile)
- โ
HeroUI
onPressreplaces deprecatedonClickon Button components
๐ Recurring Events & Event Scopeโ
Recurring Event Seriesโ
- โ
Create multiple events at once with
recurringDatesarray - โ
Events share
recurringSeriesIdfor batch operations - โ
POST /events/:id/cancel-seriesโ cancel all events in series - โ
DELETE /events/:id/delete-seriesโ delete all events in series - โ Use cases: CancelRecurringSeriesUseCase, DeleteRecurringSeriesUseCase
Event Scope (guild vs group)โ
- โ
scope: guildโ full guild event, officers only can create - โ
scope: groupโ member event, any guild member can create - โ
Default:
group - โ CASL ability checks enforce scope on create
Event Enhancementsโ
- โ
imageUrlโ custom or journal instance image - โ
POST /events/:id/imageโ upload event image (5MB max, moderation) - โ
journalInstanceIdโ link to Blizzard instance for auto metadata/image - โ
statusโ draft, published, cancelled, completed
๐ก๏ธ Admin Panelโ
- โ
Admin-only routes (
/admin) โ requiresisAdmin(Manage All) - โ
User.isAdminโ platform admin flag - โ
GET /admin/adminsโ list admins - โ
GET /admin/users?q=โ search users for promotion - โ
POST /admin/admins/:userIdโ promote/demote admin - โ
GET /admin/statsโ platform usage (guilds, users, events, etc.) - โ
POST /admin/sync-instancesโ trigger journal sync - โ
GET /admin/sync-instances/activeโ active sync session - โ
GET /admin/sync-statusโ recent roster + instance syncs - โ
GET /admin/jobsโ queue health
๐ Game Data (Journal Instances)โ
- โ
JournalExpansion,JournalInstance,JournalEncounterโ Blizzard-synced raid/dungeon metadata - โ
GET /game-data/expansionsโ WoW expansions - โ
GET /game-data/instances?category=raid|dungeonโ raids and dungeons - โ
GET /game-data/encounters?journalInstanceId=โ bosses per instance - โ Public endpoints (no auth)
๐ Journal Instance Syncโ
- โ
BullMQ queue:
journal-instance-sync - โ
Processor:
JournalInstanceSyncProcessor - โ
WebSocket:
InstanceSyncGatewayโ real-time progress - โ
JournalSyncSessionโ tracks expansions, instances, encounters progress - โ
useInstanceSynchook +InstanceSyncProgresscomponent - โ Admin panel: trigger sync, view progress
๐ฆ Storage & Image Moderationโ
- โ
StorageServiceโ S3 or local filesystem for event images - โ
ImageModerationServiceโ moderation on upload - โ Event image upload with validation (5MB, JPEG/PNG/GIF/WebP)
๐ Participation Updatesโ
- โ
characterIdโ which character user brings - โ
roleKeyโ links to EventSlot - โ
Status:
waitlist,declinedadded
๐ Documentationโ
- โ Domain Schema โ updated Event, User, Participation, Journal entities
- โ API Endpoints โ admin, events, game-data, recurring series
- โ Background Jobs โ journal-instance-sync
- โ WebSocket Pattern โ instance sync example
February 15, 2026โ
๐ Guild Posts Visibility Fixโ
Fixed guild posts with visibility: guild not appearing for authenticated members.
- Cache: Added
Cache-Control: no-storeandVary: Authorizationto posts endpoints so responses are not cached by auth state (was causing 304 with stale unauthenticated data) - Facade: Added
canManageGuildtogetGuildPostsoptions type so it is passed correctly to the use case - Frontend:
skip: !guildensures posts are fetched only after guild (and auth) loads
๐ฑ Characters Mobile UX & API Fixesโ
Mobileโ
- โ Floating bottom action bar (iOS-style island) for characters page
- โ Sync progress shown inline in floating bar when syncing
- โ CharactersFilterSheet (bottom sheet) for mobile filters
- โ CharactersMobileBar with Create, Sync, Filters
APIโ
- โ
GET /characters/templatesโ Fixed to return templates (was returning[]) - โ
POST /charactersโ Added endpoint for manual character creation (was 404) - โ
DTO validation for create (uses
dto/create-manual-character.dto.ts)
๐ Guild Alias Supportโ
Guilds can now be accessed by UUID or URL-friendly alias.
Backendโ
- โ
Added
aliasfield to Guild model (optional, unique) - โ
findGuildByIdOrAliasresolves both UUID and alias across all guild endpoints - โ Alias lookup for guild detail, logo, roster, and abilities guard
- โ
aliasincluded in guild detail API responses
Frontendโ
- โ Guild alias editor in settings page
- โ
URL navigation supports
/guilds/:aliasfor clean URLs - โ Auto-generated aliases for Blizzard-synced guilds
- โ Cache invalidation for guild updates
๐ CI/CD Workflow Refactorโ
GitHub Actions test workflow updated for full E2E support.
- โ Postgres 16 service for E2E tests
- โ Redis 7 service for E2E tests (cache, BullMQ)
- โ
JWT_SECRETand OAuth env vars in CI - โ Separate jobs: unit tests (fast), E2E tests (Postgres + Redis), coverage
๐ OAuth Support in CIโ
- โ Battle.net and Discord OAuth client IDs/secrets/callbacks configured for test environment
- โ Enables E2E tests that require auth flows
๐งช E2E Test Improvementsโ
- โ Clean up e2e test configuration and data isolation
- โ Fix membership test data isolation
- โ
Fix tests after
findGuildByIdOrAliasimplementation
โก Frontend UXโ
- โ Suspense boundaries and loading states on guild routes
- โ Fix guild alias input validation
February 1, 2026โ
๐ Internationalization (i18n) System (3 pts)โ
Implemented comprehensive i18n system using i18next for multi-language support.
i18n Infrastructureโ
- โ Installed i18next, react-i18next, i18next-browser-languagedetector
- โ Created namespaced translation structure (common, guild, character, roster)
- โ TypeScript integration with type-safe translation keys
- โ Auto language detection (localStorage โ browser โ fallback to English)
Translation Files (English)โ
- โ
common.json- Shared translations (actions, errors, validation, status) - โ
guild.json- Guild management with confirmations and messages - โ
character.json- Character operations - โ
roster.json- Roster management and sync
i18n Featuresโ
- โ Zero latency (translations bundled with app, no network requests)
- โ Type-safe keys with IDE autocomplete
- โ
Interpolation for dynamic values (
{{name}},{{count}}) - โ
Built-in pluralization (
membervsmembers) - โ Language persistence in localStorage
- โ Git-based workflow (translations versioned with code)
i18n Documentationโ
- โ
Complete guide in
docs/guides/internationalization.md - โ Usage examples and best practices
- โ Migration strategy from hard-coded strings
- โ Guide for adding new languages
- โ Example component with all patterns
i18n Benefitsโ
- Frontend-only (no backend dependency)
- Reliable offline development
- Industry-standard approach (same as GitHub, Linear, Vercel)
- Ready to integrate with Lokalise/Crowdin when needed
- Follows "boring solutions" philosophy
Next Step: Gradually extract hard-coded strings to translation keys
๐ Toast Notification System (3 pts)โ
Implemented comprehensive UI toast notification system for user feedback.
Toast Infrastructureโ
- โ
Installed
@heroui/toastpackage (v2.0.20) - โ
Added
ToastProviderto app root with portal-based rendering - โ
Created
useToast()hook for simple toast API - โ
Created
useToastMutations()for RTK Query integration
Toast Featuresโ
- โ Success, error, info, warning, and loading toast variants
- โ Promise-based toasts that auto-update on resolve/reject
- โ Rich descriptions and custom timeouts
- โ Perfect integration with HeroUI theme (light/dark mode)
- โ Top-right placement with close buttons
- โ Max 3 visible toasts, 4s auto-dismiss
Toast Documentationโ
- โ
Complete guide in
docs/guides/toast-notifications.md - โ Example component with usage patterns
- โ API reference and best practices
Toast Benefitsโ
- Native HeroUI component (no external dependencies like Sonner)
- Automatic theme integration
- Ready for mutation feedback across the app
- Accessible and mobile-friendly
Next Step: Integrate toasts into existing mutations (guild create/update/delete, etc.)
๐๏ธ Archive & Delete Feature (21 pts)โ
Complete archive and delete functionality for guilds and characters with smart business rules.
Backend Changesโ
- โ
Added
activeandarchivedAtfields to Guild model - โ
Archive/restore/delete endpoints for guilds (
PATCH /archive,PATCH /restore,DELETE /:id) - โ Archive/restore/delete endpoints for characters
- โ Business rules: only standalone guilds and manual characters can be hard-deleted
- โ Proper cache invalidation on all operations
Frontend Changesโ
- โ
New
ConfirmDialogreusable component for destructive actions - โ Archive/restore/delete actions in character cards (dropdown menu)
- โ Danger Zone in guild settings with archive/delete options
- โ "Show Archived" toggle on guild list (persisted in localStorage)
- โ Archived count always visible regardless of toggle state
- โ Restore UI for archived guilds with prominent notice
- โ Visual indicators for archived items (opacity + chip badges)
Permissions & Securityโ
- โ
Fixed CASL permissions to grant Delete action to users with
canManageGuild - โ Ownership verification for character operations
- โ Only standalone guilds can be permanently deleted (not Blizzard-synced)
- โ Only manual characters can be permanently deleted (not Blizzard-synced)
Cache Managementโ
- โ Frontend: Proper query key invalidation for all guild queries
- โ Backend: Redis pattern-based cache clearing for guild lists
- โ Immediate UI updates after operations
UX Improvementsโ
- โ Persistent toggle state in localStorage
- โ Confirmation dialogs for all destructive actions (archive/restore/delete)
- โ Clear messaging about reversibility and data preservation
- โ Color-coded dialogs (warning for archive, danger for delete, primary for restore)
See Archive & Delete Documentation for full details.
๐ OAuth & Authentication Fixesโ
OpenID Connect Complianceโ
- โ
Added
openidscope to Battle.net OAuth configuration - โ Battle.net authentication now follows OIDC standards
- โ Receives signed ID token with verified user claims
- โ Enhanced security with cryptographic token verification
- โ Updated documentation with OIDC implementation details
Benefits:
- Standardized authentication flow
- Cryptographically verified identity tokens
- Interoperability with OIDC-compliant systems
- Security best practices for identity verification
Fixed OAuth callback URLs and login flowโ
- โ
Corrected backend OAuth callback URLs from port 3000 to 3001
DISCORD_CALLBACK_URL:http://localhost:3001/api/v1/auth/discord/callbackBATTLENET_CALLBACK_URL:http://localhost:3001/api/v1/auth/battlenet/callback
- โ
Fixed frontend login page to use correct API URL (
VITE_API_URL) - โ Updated settings page OAuth links to use correct port
- โ Modernized login page UI with HeroUI components
Action Requiredโ
- Update OAuth app callback URLs in Discord Developer Portal
- Update OAuth app callback URLs in Battle.net Developer Portal
๐ญ Role System Updatesโ
Added founder role protectionโ
- โ
Added
isFounderfield to Role model - โ Founder role (initial guild master) cannot be deleted
- โ Still allows editing name and permissions
- โ Frontend shows warning message for founder roles
- โ Backend enforces deletion protection
Guild creation improvementsโ
- โ Added Step 5 to guild creation: "Master Role"
- โ Users can customize the guild master role name
- โ Default: "Guild Master" (customizable to "Leader", "Admin", etc.)
- โ Shows full permissions info card
- โ Simplified standalone guild creation (one custom role instead of 5 WoW ranks)
Custom role refinementsโ
- โ
Custom roles always have
wowRank = null - โ WoW ranks (0-9) only used for Blizzard-synced guilds
- โ Removed WoW rank field from custom role creation
- โ Improved modal validation and error messages
๐ Role Management Modal Refactorโ
Component modularizationโ
- โ
Split large modal component into smaller files
index.tsx- Main containertypes.ts- Shared interfacesRoleFormFields.tsx- Form inputsPermissionsSection.tsx- Permissions togglesInfoCards.tsx- Reusable info/warning cardsuseRoleMutations.ts- API mutations hook
- โ Replaced emojis with Heroicons throughout
- โ Improved type safety and maintainability
๐ Documentation (1 pt)โ
Updated guidesโ
- โ Authentication System - OAuth flows with correct ports
- โ Network Configuration - Port reference guide
- โ Role System - Custom roles vs WoW-synced roles
- โ API Reference - Role CRUD endpoints with business rules
Development Notesโ
Port Configuration Summaryโ
| Service | Port | URL |
|---|---|---|
| API | 3001 | http://localhost:3001 |
| Web | 5173 | http://localhost:5173 |
| Docs | 3002 | http://localhost:3002 |
| PostgreSQL | 5432 | localhost:5432 |
| Redis | 6379 | localhost:6379 |
OAuth Flowโ
flowchart LR
A[User] --> B["Frontend (5173)"]
B --> C["API (3001)"]
C --> D[OAuth Provider]
D --> E["Callback (3001)"]
E --> F["Frontend (5173)"]
Role Typesโ
| Type | wowRank | isFounder | Deletable? |
|---|---|---|---|
| WoW-synced | 0-9 | false | โ No (synced) |
| Founder role | null | true | โ No (founder) |
| Custom role | null | false | โ Yes (if no members) |
Testingโ
All changes include:
- โ Unit tests (guild service: 6/6, role service: 17/17)
- โ Zero linting errors
- โ Migration tested on dev database
- โ OAuth flow tested with actual providers
Future Improvementsโ
Plannedโ
- Token refresh for longer sessions
- Multi-factor authentication
- Session management (view/revoke)
Role Systemโ
- Bulk role assignment
- Role templates
- Permission presets
- Role hierarchy visualization
UI/UXโ
- Dark mode improvements
- Mobile responsive design
- Loading states
- Error boundaries