Align docs with StyleGuide and add CLAUDE.md
- Rename 16 kebab-case docs to PascalCase per StyleGuide - Move per-language client design docs from docs/ to clients/<lang>/ alongside their READMEs - Add ## Related Documentation sections to 15 docs that lacked one - Fix sentence-case violations in H3 headings (StyleGuide rule) - Update cross-references in gateway.md, client READMEs, scripts, and generate-proto.ps1 helpers to follow the new paths - Add CLAUDE.md with build/test commands, the source-update verification matrix, the parity-first contract, and pointers to MXAccess and Galaxy Repository analysis sources Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,402 @@
|
||||
# Gateway Dashboard Detailed Design
|
||||
|
||||
## Purpose
|
||||
|
||||
The gateway should host a basic web dashboard for operators and developers. The
|
||||
dashboard is diagnostic and operational visibility only for v1. It should show
|
||||
gateway health, active MXAccess worker instances, session state, and basic
|
||||
statistics in real time.
|
||||
|
||||
## Technology Choice
|
||||
|
||||
Decision: Blazor Server with Bootstrap CSS/JS.
|
||||
|
||||
Allowed UI stack:
|
||||
|
||||
- ASP.NET Core Blazor Server,
|
||||
- Bootstrap CSS,
|
||||
- Bootstrap JavaScript,
|
||||
- small local CSS for layout and status styling,
|
||||
- built-in Blazor components.
|
||||
|
||||
Not allowed for v1:
|
||||
|
||||
- MudBlazor,
|
||||
- Radzen,
|
||||
- Syncfusion,
|
||||
- Telerik,
|
||||
- other Blazor UI component libraries,
|
||||
- client-side SPA framework replacement.
|
||||
|
||||
Rationale: Blazor Server keeps the dashboard in the gateway process, avoids a
|
||||
separate frontend build, and gives real-time UI updates through the Blazor
|
||||
SignalR circuit. Bootstrap is sufficient for a basic dashboard.
|
||||
|
||||
## Hosting Model
|
||||
|
||||
The dashboard is hosted by `MxGateway.Server` alongside the gRPC API. When
|
||||
`MxGateway:Dashboard:Enabled` is `true`, `MapGatewayDashboard()` maps the
|
||||
configured `Dashboard:PathBase` to the Blazor Server app and maps the login,
|
||||
logout, and access-denied HTTP endpoints beside it. When dashboard hosting is
|
||||
disabled, those routes are not mapped.
|
||||
|
||||
Endpoint layout:
|
||||
|
||||
```text
|
||||
/dashboard
|
||||
/dashboard/sessions
|
||||
/dashboard/sessions/{sessionId}
|
||||
/dashboard/workers
|
||||
/dashboard/events
|
||||
/dashboard/galaxy
|
||||
/dashboard/settings
|
||||
/dashboard/_blazor
|
||||
```
|
||||
|
||||
The `/dashboard/galaxy` page surfaces the Galaxy Repository browse summary
|
||||
(deployed object hierarchy size, last deploy timestamp, attribute totals,
|
||||
template usage, and connectivity sync info). The summary is fed by
|
||||
`GalaxySummaryCache`, which is refreshed off the request path by
|
||||
`GalaxySummaryRefreshService` on the
|
||||
`MxGateway:Galaxy:DashboardRefreshIntervalSeconds` cadence so the dashboard
|
||||
never blocks on SQL. See [Galaxy Repository Browse](./GalaxyRepository.md) for
|
||||
the underlying gRPC service.
|
||||
|
||||
The app should redirect `/` to `/dashboard` only if the deployment wants the
|
||||
dashboard as the default web page. Otherwise leave gRPC/API hosting unaffected.
|
||||
|
||||
## High-Level Components
|
||||
|
||||
```text
|
||||
MxGateway.Server
|
||||
Dashboard/
|
||||
Components/
|
||||
App.razor
|
||||
Routes.razor
|
||||
DashboardPageBase.cs
|
||||
DashboardDisplay.cs
|
||||
Layout/
|
||||
DashboardLayout.razor
|
||||
Pages/
|
||||
DashboardHome.razor
|
||||
SessionsPage.razor
|
||||
SessionDetailsPage.razor
|
||||
WorkersPage.razor
|
||||
EventsPage.razor
|
||||
SettingsPage.razor
|
||||
Shared/
|
||||
MetricCard.razor
|
||||
StatusBadge.razor
|
||||
FaultList.razor
|
||||
DashboardSnapshotService.cs
|
||||
DashboardAuthorizationHandler.cs
|
||||
DashboardAuthenticator.cs
|
||||
DashboardSnapshot.cs
|
||||
DashboardSessionSummary.cs
|
||||
DashboardWorkerSummary.cs
|
||||
DashboardMetricSummary.cs
|
||||
```
|
||||
|
||||
Blazor Server provides the SignalR circuit for UI updates. The implementation
|
||||
does not add a separate public dashboard hub.
|
||||
|
||||
## Dashboard Data Source
|
||||
|
||||
The dashboard should consume read-only snapshots from gateway services:
|
||||
|
||||
- `SessionRegistry`,
|
||||
- `SessionManager`,
|
||||
- `WorkerClient`,
|
||||
- `GatewayMetrics`,
|
||||
- health checks,
|
||||
- structured fault/event counters.
|
||||
|
||||
Do not let Razor components directly mutate gateway session or worker objects.
|
||||
Create a small read-only dashboard service that projects gateway state into
|
||||
plain DTOs.
|
||||
|
||||
`GatewayMetrics.GetSnapshot()` is the metrics input for the first dashboard
|
||||
projection. It carries current session and worker gauges, command and event
|
||||
counters, queue depth, and fault totals. The dashboard reads that snapshot
|
||||
instead of reading raw `Meter` instruments because exporter configuration is an
|
||||
operations concern, not a UI dependency.
|
||||
|
||||
Suggested service:
|
||||
|
||||
```csharp
|
||||
public interface IDashboardSnapshotService
|
||||
{
|
||||
DashboardSnapshot GetSnapshot();
|
||||
IAsyncEnumerable<DashboardSnapshot> WatchSnapshotsAsync(
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
Snapshot updates can be driven by:
|
||||
|
||||
- periodic timer, default every 1 second,
|
||||
- session lifecycle notifications,
|
||||
- worker heartbeat updates,
|
||||
- event counter updates,
|
||||
- fault notifications.
|
||||
|
||||
Use immutable snapshot DTOs so Razor components can render without locking
|
||||
gateway internals.
|
||||
|
||||
## Realtime Updates
|
||||
|
||||
Use Blazor Server component state updates for real-time dashboard refresh.
|
||||
|
||||
Implemented pattern:
|
||||
|
||||
1. Page/component subscribes to `WatchSnapshotsAsync`.
|
||||
2. Snapshot service emits updates from a bounded channel or timer.
|
||||
3. Component stores the latest snapshot.
|
||||
4. Component calls `InvokeAsync(StateHasChanged)`.
|
||||
5. Component cancels subscription on dispose.
|
||||
|
||||
Default update cadence:
|
||||
|
||||
- periodic metrics refresh every 1 second,
|
||||
- event counters update on the next snapshot tick.
|
||||
|
||||
Avoid pushing every MXAccess data-change event to the dashboard. Aggregate event
|
||||
counts and rates instead.
|
||||
|
||||
## Pages
|
||||
|
||||
### Dashboard home
|
||||
|
||||
Show top-level status:
|
||||
|
||||
- gateway status,
|
||||
- gateway version,
|
||||
- uptime,
|
||||
- open sessions,
|
||||
- workers running,
|
||||
- sessions faulted,
|
||||
- command rate,
|
||||
- command failure count,
|
||||
- event rate,
|
||||
- event queue depth,
|
||||
- worker restart/kill count.
|
||||
|
||||
Use Bootstrap cards for individual metric summaries. Keep the layout compact
|
||||
and operational.
|
||||
|
||||
### Sessions page
|
||||
|
||||
Show active and recent sessions in a table:
|
||||
|
||||
- session id,
|
||||
- client identity or API key display name,
|
||||
- state,
|
||||
- backend,
|
||||
- worker process id,
|
||||
- open time,
|
||||
- last client activity,
|
||||
- last worker heartbeat,
|
||||
- active event subscribers,
|
||||
- pending commands,
|
||||
- event queue depth,
|
||||
- last fault summary.
|
||||
|
||||
Rows should link to session details.
|
||||
|
||||
### Session details page
|
||||
|
||||
Show:
|
||||
|
||||
- session metadata,
|
||||
- worker metadata,
|
||||
- command counters by method,
|
||||
- event counters by family,
|
||||
- active server handles and item counts if gateway shadow state has them,
|
||||
- latest faults,
|
||||
- last heartbeat payload,
|
||||
- close/kill controls only if admin actions are later enabled.
|
||||
|
||||
For v1, details should be read-only unless an explicit admin action design is
|
||||
added.
|
||||
|
||||
### Workers page
|
||||
|
||||
Show:
|
||||
|
||||
- worker process id,
|
||||
- session id,
|
||||
- executable path/version,
|
||||
- state,
|
||||
- startup duration,
|
||||
- memory and CPU if available,
|
||||
- last heartbeat,
|
||||
- current command correlation id,
|
||||
- pending command count,
|
||||
- event queue depth,
|
||||
- restart/kill reason if terminal.
|
||||
|
||||
### Events page
|
||||
|
||||
Show aggregate event diagnostics:
|
||||
|
||||
- event rate by session,
|
||||
- event rate by event family,
|
||||
- total events since start,
|
||||
- queue overflow count,
|
||||
- stream disconnect count,
|
||||
- recent terminal faults.
|
||||
|
||||
Do not display full tag values by default. If value display is later added, make
|
||||
it opt-in and redacted.
|
||||
|
||||
### Settings page
|
||||
|
||||
Show read-only effective configuration:
|
||||
|
||||
- worker executable path,
|
||||
- configured timeouts,
|
||||
- queue capacities,
|
||||
- auth mode,
|
||||
- SQLite auth database path with sensitive parts redacted if needed,
|
||||
- dashboard enabled state,
|
||||
- protocol version.
|
||||
|
||||
Do not show API key secrets or pepper values.
|
||||
|
||||
## Authentication And Authorization
|
||||
|
||||
Dashboard access uses the same API-key authentication model as gRPC where
|
||||
practical.
|
||||
|
||||
Implemented v1 behavior:
|
||||
|
||||
- when enabled, require API key auth,
|
||||
- require `admin` scope for dashboard access,
|
||||
- accept API key through a secure cookie established by a simple login form,
|
||||
- do not put API keys in query strings,
|
||||
- validate anti-forgery tokens for login and logout posts.
|
||||
|
||||
The implementation path is:
|
||||
|
||||
1. Add `/dashboard/login`.
|
||||
2. User submits API key over HTTPS.
|
||||
3. Gateway validates key and `admin` scope.
|
||||
4. Gateway issues an HTTP-only secure auth cookie for the dashboard.
|
||||
5. Dashboard pages require that cookie.
|
||||
6. Logout clears the cookie.
|
||||
|
||||
For local development, `Dashboard:AllowAnonymousLocalhost` defaults to `true`.
|
||||
The bypass applies only to loopback requests; remote dashboard requests still
|
||||
use the API-key-backed cookie flow.
|
||||
|
||||
`DashboardAuthenticator` keeps API-key validation outside UI components. It
|
||||
formats the submitted key as a bearer authorization header for
|
||||
`IApiKeyVerifier`, rejects non-admin keys when `Dashboard:RequireAdminScope` is
|
||||
enabled, and creates the dashboard cookie principal without storing raw API key
|
||||
material. `DashboardAuthorizationHandler` enforces the cookie, admin-scope, and
|
||||
explicit loopback bypass decisions for all protected dashboard routes.
|
||||
|
||||
## Configuration
|
||||
|
||||
Suggested configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"MxGateway": {
|
||||
"Dashboard": {
|
||||
"Enabled": true,
|
||||
"PathBase": "/dashboard",
|
||||
"RequireAdminScope": true,
|
||||
"AllowAnonymousLocalhost": true,
|
||||
"SnapshotIntervalMilliseconds": 1000,
|
||||
"RecentFaultLimit": 100,
|
||||
"RecentSessionLimit": 200,
|
||||
"ShowTagValues": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Rules
|
||||
|
||||
- Do not display API key secrets.
|
||||
- Do not display credential-bearing MXAccess command values.
|
||||
- Do not display full tag values by default.
|
||||
- Do not expose worker pipe names with nonce or sensitive details.
|
||||
- Protect dashboard auth cookies with `HttpOnly`, `Secure`, and `SameSite`.
|
||||
- Require TLS for remote dashboard access.
|
||||
- Use anti-forgery protection for login/logout and any future admin actions.
|
||||
|
||||
## Styling
|
||||
|
||||
The dashboard serves Bootstrap 5.3.3 assets from
|
||||
`src/MxGateway.Server/wwwroot/lib/bootstrap/` and local layout/status styling
|
||||
from `src/MxGateway.Server/wwwroot/css/dashboard.css`.
|
||||
|
||||
Recommended visual language:
|
||||
|
||||
- compact tables,
|
||||
- status badges,
|
||||
- metric cards,
|
||||
- Bootstrap alerts for faults,
|
||||
- restrained colors,
|
||||
- no decorative hero sections,
|
||||
- no charting dependency for v1.
|
||||
|
||||
If charts are added later, prefer simple server-generated data tables first. Do
|
||||
not add a JavaScript charting dependency without a specific need.
|
||||
|
||||
The reusable visual rules for replicating this interface in other projects are
|
||||
documented in [Dashboard Interface Design](./DashboardInterfaceDesign.md).
|
||||
|
||||
## Testing
|
||||
|
||||
Dashboard unit/component tests should cover:
|
||||
|
||||
- snapshot projection,
|
||||
- dashboard auth authorization decisions,
|
||||
- login API-key validation behavior,
|
||||
- pages render with empty state,
|
||||
- pages render with active sessions,
|
||||
- pages render with faulted sessions,
|
||||
- realtime subscription disposal,
|
||||
- redaction of API keys and credential values.
|
||||
|
||||
Use bUnit if component testing is added. Otherwise keep the first tests focused
|
||||
on snapshot services and authorization logic.
|
||||
|
||||
Integration tests should verify:
|
||||
|
||||
- dashboard disabled returns not found or configured fallback,
|
||||
- dashboard requires auth when enabled,
|
||||
- admin-scoped key can access dashboard,
|
||||
- non-admin key is denied,
|
||||
- live snapshot updates when a fake session changes state.
|
||||
|
||||
## Initial Implementation Slice
|
||||
|
||||
The first dashboard slice implements:
|
||||
|
||||
1. Blazor Server hosting in `MxGateway.Server`.
|
||||
2. local Bootstrap static assets.
|
||||
3. dashboard configuration binding.
|
||||
4. dashboard auth using API key login and HTTP-only cookie.
|
||||
5. read-only `DashboardSnapshotService`.
|
||||
6. home page with metric cards.
|
||||
7. sessions page with active session table and session details.
|
||||
8. workers page with worker table.
|
||||
9. events page with aggregate counters.
|
||||
10. settings page with redacted effective configuration.
|
||||
11. periodic realtime refresh through Blazor Server.
|
||||
12. route-mapping tests, disabled-dashboard tests, auth tests, and snapshot
|
||||
projection/redaction tests.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Dashboard Interface Design](./DashboardInterfaceDesign.md)
|
||||
- [Gateway Process Detailed Design](./GatewayProcessDesign.md)
|
||||
- [Authentication](./Authentication.md)
|
||||
- [Authorization](./Authorization.md)
|
||||
- [Sessions](./Sessions.md)
|
||||
- [Metrics](./Metrics.md)
|
||||
- [Diagnostics](./Diagnostics.md)
|
||||
Reference in New Issue
Block a user