- Introduced EMPLOYEE_API endpoint in api.js for employee service. - Added RequestLab component for testing API routes with a user-friendly interface. - Updated monitoring_ui documentation to reflect changes in features and authentication. - Removed unnecessary login functionality from monitoring_ui to maintain unauthenticated access. - Enhanced styles for new components and improved overall UI consistency.
11 KiB
Transit Control Room
monitoring_ui is a React + Vite operations dashboard for the XTransit service group. It gives an operator one place to answer three questions:
- Are the services reachable right now?
- What kind of data does each service provide?
- Where is the documentation for each service?
The dashboard is a browser-only application. It does not introduce a database, server-side session store, or monitoring proxy. Health requests go directly from the browser to the configured services.
Authenticated operations — the centralized error log, the request lab, and network management — live in the admin console (admin_ui, the Beheercentrum). This dashboard deliberately stays unauthenticated and read-only so a control-room wall display never needs a token.
1. What It Monitors
| Surface | Default URL | Health request | Purpose |
|---|---|---|---|
| Auth API | http://localhost:5000 |
GET /health |
Login, JWT sessions, and current-user information |
| Employee API | https://employees.xtransit.testinstance.nl |
GET /health |
Employee onboarding and employee records |
| Transit API | http://localhost:5001 |
GET /health |
Schedules, routes, GPS, fleet, and administration |
| Error Log API | http://localhost:5003 |
GET /health |
Centralized service errors and bad requests |
| Admin UI | http://localhost:5174 |
GET /health |
Availability of the deployed React administration console |
The URLs are development defaults only. For a deployed dashboard, use the Connections screen or build-time VITE_* variables.
Health semantics
healthy: the request returned a successful HTTP status.degraded: the service answered, but returned a non-success status such as401,403, or503.offline: the browser could not establish a response, usually because the service is stopped, the URL is wrong, TLS failed, or CORS blocked the request.checking: the first poll has not completed yet.
Transit health includes database reachability. Employee health currently confirms process reachability only. Auth health reads the public /health endpoint, which does not require a token. Admin UI health is supplied by the nginx configuration in admin_ui/nginx.conf and returns a small JSON document.
2. Features
Overview
The Overview tab contains one card per monitored surface. Each card shows:
- current status;
- response time for the latest poll;
- a compact latency history from recent polls;
- the returned health payload.
The top-level pulse shows how many surfaces are healthy and the average latency across completed checks. Polling can be set to 15 seconds, 30 seconds, or one minute.
Service catalog
The Service catalog is a human-readable map of the data each service serves. It is deliberately maintained as a small allowlisted catalog rather than attempting to discover every Express route at runtime. This keeps the dashboard understandable and avoids exposing internal routes or implementation details.
Docs
The Docs tab bundles the project documentation hub (monitoring_ui/docs/) into a searchable sidebar. It renders every markdown file that ships with the dashboard and resolves in-document links. This is the same documentation referenced throughout the repository.
Connections
The Connections tab edits the service base URLs used for health polling. Values are stored in localStorage under transit-monitor-urls. This makes local experimentation convenient, but it also means the URLs are readable by JavaScript running on the same origin. Use the dashboard only in a trusted browser profile.
The Connections screen intentionally does not accept tokens or passwords. Authenticated reads (error log, admin endpoints) are done from the admin console.
3. Local Development
cd monitoring_ui
npm install
npm run dev
Open the URL printed by Vite, normally http://localhost:5173.
Build and preview the production bundle:
npm run build
npm run preview
The app uses React 18 and Vite 5, matching the existing admin UI's frontend generation approach. Its main files are:
monitoring_ui/
├── index.html browser entry point
├── package.json scripts and dependencies
├── vite.config.mjs Vite React configuration
├── src/
│ ├── main.jsx React bootstrap
│ ├── App.jsx service model, polling, tabs, docs viewer
│ └── styles.css responsive control-room styling
└── README.md short navigation pointer
4. Configuration
Build-time environment variables
Create monitoring_ui/.env.local for a deployed or non-default environment:
VITE_AUTH_API=https://auth.example.test
VITE_EMPLOYEE_API=https://employees.xtransit.testinstance.nl
VITE_TRANSIT_API=https://transit.example.test
VITE_ERROR_LOG_API=https://error.example.test
VITE_ADMIN_UI=https://admin.example.test
Vite reads these variables when the app is built. They are not secrets. Do not put JWTs, database passwords, signing keys, or API credentials in .env.local values that will be shipped to the browser.
The Connections screen is useful when the same build needs to point at different environments. Its values override the initial defaults in the current browser only.
CORS requirements
Because the dashboard calls services directly, every monitored API must allow the dashboard origin. The existing Auth, Transit, and Error Log services already expose permissive CORS middleware. Employee API has matching browser CORS middleware in employee_api/index.js.
For production, replace wildcard CORS with an explicit dashboard origin where practical. At minimum, allow GET and OPTIONS.
If the browser console reports a refused connection but direct curl succeeds, check CORS before changing the dashboard code.
5. Authentication and Security
The dashboard is deliberately unauthenticated. It never stores or sends bearer tokens. All protected operations are handled by the admin console (admin_ui), which obtains a JWT through the normal Auth API login flow.
Operational safeguards:
- never commit
.env.local; - avoid putting production URLs, screenshots, or issue reports in public channels;
- use HTTPS for deployed APIs and dashboard access;
- restrict CORS to known origins in production.
6. Deployment Options
Static hosting
The dashboard can be hosted as static files from any web server that supports SPA fallback to index.html. Build it with:
npm run build
Publish monitoring_ui/dist. Configure the web server to serve index.html for unknown application paths. The current dashboard uses client-side tab state and does not require route rewrites beyond the root page, but SPA fallback remains a sensible default.
Container hosting
The repository includes a Node build stage followed by nginx in monitoring_ui/Dockerfile. Runtime configuration is written to env-config.js by monitoring_ui/docker-entrypoint.sh, so the same image can be promoted between environments without baking service URLs into the JavaScript bundle.
The root Compose stack deploys this image as monitoring_ui on host port 5175. Set these Compose variables when deploying:
AUTH_API=https://auth.xtransit.testinstance.nl
EMPLOYEE_API=https://employees.xtransit.testinstance.nl
TRANSIT_API=https://transit.xtransit.testinstance.nl
ERROR_LOG_API=https://error.xtransit.testinstance.nl
ADMIN_UI=https://admin.xtransit.testinstance.nl
The Gitea workflow detects changes under monitoring_ui/**, builds monitoring_ui/Dockerfile, and pushes the image as monitoring_ui:<branch> and monitoring_ui:<commit>. The dev branch includes the image in the Portainer redeploy dependency chain.
Reverse proxy
A reverse proxy can place the dashboard and service domains behind one TLS boundary. This is often preferable for production because it simplifies CORS and gives operators a single origin. It is not required for local development.
7. Troubleshooting
All cards show offline
- Check that the API processes are running.
- Check the URL in Connections, including protocol and port.
- Open the health URL directly in a browser or use
curl. - Inspect the browser console for CORS or TLS errors.
- Confirm that Docker port mappings match
docker-compose.yml.
Auth API shows degraded
GET /health should answer without a token. If it returns degraded, the API is reachable but responding with a non-success status. Note that /me requires a bearer token; that endpoint is only exercised from the admin console.
Employee API cannot be called from the dashboard
Check that the deployed image includes the CORS middleware from employee_api/index.js. A stale container image may still be running an earlier version.
Admin UI health fails
Rebuild the admin UI image after adding admin_ui/nginx.conf. The endpoint is:
curl -i http://localhost:5174/health
Expected body:
{ "status": "ok", "service": "admin_ui" }
Health is slow
The dashboard measures full browser request time, including DNS, TLS, network, and API processing. Compare the dashboard value with a server-side curl from the same network before diagnosing application latency.
8. Extending the Dashboard
To add a service:
- Add its base URL to
configured. - Add its metadata to
serviceMeta. - Add a health path to
healthPaths. - Add its environment variable to this document and
.env.localexamples. - Confirm the service has CORS headers and an appropriate health endpoint.
- Run
npm run buildand perform a browser smoke test.
Authenticated tooling belongs in admin_ui, not in this dashboard. If an admin-facing request lab or error viewer is needed, extend the admin console instead so this control-room surface stays unauthenticated.
Useful future extensions include:
- a time-window chart backed by a real metrics store;
- service version/build information in health payloads;
- threshold-based alerts for latency and repeated failures;
- an Admin UI card in the overview that includes deployment/build metadata.
9. Validation Checklist
Before shipping a dashboard change:
cd monitoring_ui
npm install
npm run build
Then verify in a browser:
- all five cards render;
- one healthy local service shows a payload and latency;
- an unavailable service is clearly marked offline;
- Connections persists URL changes after reload;
- no tab, control, or prompt requires a token or password;
- the layout remains usable at a narrow mobile width.