Frontend (Unit 2 completion): dual dev-server tooling (pnpm dev:slave, pnpm dev:all), per-instance browser tab titles, and a backend capability check (SystemController + useSystemCapabilities + ModuleGuard) so a Master-only page is hidden on a slave instance instead of assuming every backend has every module. Master/slave protocol fixes surfaced by actually running master and slave side by side locally: - Deactivating a CMS instance (Inactive) now releases the slave's master gate instead of leaving it stuck on its last pushed status. - The periodic integrity check now also re-pushes status to every reachable slave (previously URL-verification only) and runs once immediately on startup. - Added the originally-specified (but never implemented) slave-pull path: a slave now periodically polls its own status from the master (GET /api/v1/SlaveStatus) and fails open to Available if the master is unreachable for too long, complementing the existing push. - The slave's own Settings page can no longer "successfully" change local availability while the master controls it; it's now locked with an explanatory banner and the backend rejects the write with 409 instead of silently no-op'ing it. - CMS instance status badges now match the dashboard's color/icon styling instead of a plain grey badge. Also corrected the master-cms-module design docs to match this as-built behavior, and flagged (without a full rewrite) a larger, pre-existing divergence between its inception-stage application design and what construction actually built. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.7 KiB
3.7 KiB
Fix — CMS Page Was Visible on Slave (No Backend Capability Check)
Problem
The /cms page (managing registered CMS instances — an Owner-only feature backed by SlpModularCms.Modules.Master) was gated purely by role (Owner), with no awareness of whether the connected backend actually has the Master module loaded. Before this feature, this was never an issue — every deployed instance always had Modules.Master loaded. Now that a Master-less slave instance exists, an Owner using the frontend against the slave could still see the nav link and open /cms, where its data calls (GET /api/v1/CmsInstances) would 404 against a backend that has no such controller.
Fix
Backend
SlpModularCms.Core.Hosting.ModuleOrchestrator— addedModuleNames(publicIReadOnlyList<string>), listing the names of modules actually discovered on this instance.- New
SlpModularCms.Core.Hosting.SystemController—GET /api/v1/System/capabilitiesreturns{ "modules": [...] }for whichever instance is asked. SlpModularCms.Api/Program.csandSlpModularCms.Api.Slave/Program.cs— registered theModuleOrchestratorinstance itself as a DI singleton (builder.Services.AddSingleton(orchestrator)) so the new controller can inject it.
Frontend
src/api/types.ts— addedSystemCapabilities { modules: string[] }.src/api/useSystemCapabilities.ts— new React Query hook (staleTime: Infinity— a backend's module set never changes mid-session), calling/api/v1/System/capabilities.src/components/auth/ModuleGuard.tsx— new guard component (mirrorsRoleGuard), hides its children and shows a "not available on this instance" message when the required module isn't in the backend's capability list.src/router.tsx—/cmsroute now wraps its page in<ModuleGuard requiredModule="Master">(inside the existing<RoleGuard allowedRoles={['Owner']}>).src/components/layout/Sidebar.tsx— the CMS nav item now also requirescapabilities.modules.includes('Master')before rendering.src/i18n/locales/{nl,en}/translation.json— addederrors.featureUnavailableTitle/errors.featureUnavailable.src/mocks/system/handlers.ts— new MSW handler for*/System/capabilities, defaulting to['Availability', 'Identity', 'Master']so existing CMS-related tests keep passing unchanged; registered insrc/mocks/index.ts.src/components/layout/Sidebar.test.tsx— updated the "Owner sees ... CMS" assertion tofindByTestId(now async, since nav-cms visibility depends on the capabilities fetch), and added a new regression test: "Owner does not see CMS when the backend has no Master module (slave instance)".
Verification Performed
dotnet build/dotnet test— succeed; all 193 backend tests still pass (module relocation from the earlier fix is untouched; this only adds new code).pnpm build— succeeds, no type errors.pnpm test— 210/210 pass in isolation (209/210 in the full parallel run; the 1 failure is the same pre-existing flakyAddCmsInstanceDialog.test.tsxtimeout seen earlier in this feature's Build and Test, unrelated to this change — confirmed passing 5/5 when re-run alone).- Live verification against real running instances: started both
SlpModularCms.Api(master) andSlpModularCms.Api.Slaveagainst the local SQL Server and curled the new endpoint directly:- Master:
curl https://localhost:7221/api/v1/System/capabilities→{"modules":["Availability","Identity","Master"]} - Slave:
curl https://localhost:7222/api/v1/System/capabilities→{"modules":["Availability","Identity"]} - Confirms the capability check reflects each instance's actual loaded modules, not just a hardcoded assumption.
- Master: