──────
Build and Push Docker Images / detect-changes (push) Successful in 11s
Build and Push Docker Images / build-auth-api (push) Successful in 1m0s
Build and Push Docker Images / build-employee-api (push) Successful in 1m2s
Build and Push Docker Images / build-transit-api (push) Successful in 1m1s
Build and Push Docker Images / build-error-log-api (push) Successful in 1m5s
Build and Push Docker Images / build-admin-ui (push) Successful in 1m13s
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m15s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
Build and Push Docker Images / detect-changes (push) Successful in 11s
Build and Push Docker Images / build-auth-api (push) Successful in 1m0s
Build and Push Docker Images / build-employee-api (push) Successful in 1m2s
Build and Push Docker Images / build-transit-api (push) Successful in 1m1s
Build and Push Docker Images / build-error-log-api (push) Successful in 1m5s
Build and Push Docker Images / build-admin-ui (push) Successful in 1m13s
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m15s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
### Summary of Changes
1. Documentation Consolidation:
• Relocated the docs/ folder and all repository .md files (README.md, DEPLOYMENT.md, DOCKER_README.md,
DOMAINS_README.md, GETTING_STARTED.md, CI_CD_PORTAINER_GUIDE.md, ADMIN_DEPLOYMENT_SUMMARY.md,
SECURITY_PRIVATE_FILES.md, handoff.md, azure-project-plan.md, plus service-specific READMEs) into .
• Updated document links in README.md.
2. AI Agent Project Map:
• Created PROJECT_MAP.md in the project root containing complete architecture diagrams, service specs, ports, DB
schemas, environment variables, and developer workflows.
• Added PROJECT_MAP.md to .gitignore.
3. Monitoring UI & Infrastructure Integration:
• Added monitoring_ui service to docker-compose.yml (port 5175).
• Configured Gitea workflow docker-build.yml for monitoring_ui builds.
• Added CORS middleware headers in index.js.
• Added nginx.conf copy step in Dockerfile.
──────
### Recommended Commit Message
docs: consolidate project documentation into monitoring_ui and add agent project map
- Move all markdown documentation files and docs/ folder into monitoring_ui/docs/
- Update documentation hub index (monitoring_ui/docs/README.md) with relative paths
- Generate comprehensive AI agent reference map (PROJECT_MAP.md) in repository root
- Add PROJECT_MAP.md and monitoring_ui build output/env overrides to .gitignore
- Integrate monitoring_ui service into docker-compose.yml and Gitea CI workflow
- Configure CORS handling in employee_api for monitoring dashboard access
──────
### Alternative Short Commit Message
refactor(docs): move docs to monitoring_ui and create AI agent PROJECT_MAP.md
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
# Docker Setup voor Transit Project APIs
|
||||
|
||||
Dit project bevat Docker-configuratie voor alle APIs, Admin Control Center en PostgreSQL database.
|
||||
|
||||
## Bestanden
|
||||
|
||||
- **auth_api/Dockerfile** - Image voor Authentication API (port 5000)
|
||||
- **employee_api/Dockerfile** - Image voor Employee API (port 4000)
|
||||
- **transit_api/Dockerfile** - Image voor Transit API (port 5001)
|
||||
- **admin_ui/Dockerfile** - Image voor Admin Control Center (port 5174)
|
||||
- **docker-compose.yml** - Orchestratie van alle services
|
||||
- **.dockerignore** - Bestanden die niet in Docker images opgenomen worden
|
||||
- **.env.example** - Template voor environment variabelen
|
||||
- **DEPLOYMENT.md** - Gedetailleerde deployment guide
|
||||
- **scripts/deploy.sh** - Deployment helper script
|
||||
- **scripts/build-and-push.sh** - Build en push script voor registry
|
||||
|
||||
## Vereisten
|
||||
|
||||
- Docker (>=20.10)
|
||||
- Docker Compose (>=2.0)
|
||||
|
||||
## Installatie
|
||||
|
||||
### 1. Environment variabelen configureren
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Bewerk .env met je eigen waarden
|
||||
```
|
||||
|
||||
### 2. Services starten
|
||||
|
||||
```bash
|
||||
# Start alle services (APIs + Admin UI)
|
||||
docker-compose up -d
|
||||
|
||||
# Of build en start tegelijk (als je code hebt aangepast)
|
||||
docker-compose up -d --build
|
||||
|
||||
# Quick start met script
|
||||
./scripts/deploy.sh start
|
||||
```
|
||||
|
||||
### 3. Logs bekijken
|
||||
|
||||
```bash
|
||||
# Alle logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Logs van specifieke service
|
||||
docker-compose logs -f auth_api
|
||||
docker-compose logs -f transit_api
|
||||
docker-compose logs -f admin_ui
|
||||
|
||||
# Via script
|
||||
./scripts/deploy.sh logs admin_ui
|
||||
```
|
||||
|
||||
## Beschikbare Services
|
||||
|
||||
| Service | Port | Beschrijving |
|
||||
|---------|------|--------------|
|
||||
| admin_ui | 5174 | Admin Control Center (React + Nginx) |
|
||||
| auth_api | 5000 | Authentication endpoints |
|
||||
| employee_api | 4000 | Employee management endpoints |
|
||||
| transit_api | 5001 | Transit management endpoints |
|
||||
|
||||
## Commando's
|
||||
|
||||
### Services beheren (Quick way)
|
||||
|
||||
```bash
|
||||
# Via helper script
|
||||
./scripts/deploy.sh start # Start alle services
|
||||
./scripts/deploy.sh stop # Stop alle services
|
||||
./scripts/deploy.sh restart # Herstart alle services
|
||||
./scripts/deploy.sh status # Show status
|
||||
./scripts/deploy.sh logs # Bekijk logs admin_ui
|
||||
./scripts/deploy.sh logs transit_api # Bekijk logs specifieke service
|
||||
```
|
||||
|
||||
### Services beheren (Docker compose)
|
||||
|
||||
```bash
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
|
||||
# Herstart services
|
||||
docker-compose restart
|
||||
|
||||
# Verwijder containers en volumes
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
### Individuele services
|
||||
|
||||
```bash
|
||||
# Herstart specifieke service
|
||||
docker-compose restart auth_api
|
||||
docker-compose restart admin_ui
|
||||
|
||||
# Build specifieke image
|
||||
docker-compose build auth_api
|
||||
|
||||
# Logs van specifieke service
|
||||
docker-compose logs -f transit_api
|
||||
```
|
||||
|
||||
### Admin UI
|
||||
|
||||
```bash
|
||||
# Bekijk Admin UI
|
||||
http://localhost:5174
|
||||
|
||||
# Logs
|
||||
docker-compose logs -f admin_ui
|
||||
|
||||
# Shell in container
|
||||
docker-compose exec admin_ui sh
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port al in gebruik
|
||||
```bash
|
||||
# Check welke container de port gebruikt
|
||||
docker ps
|
||||
|
||||
# Verander port in docker-compose.yml (e.g., "5000:5000" naar "5010:5000")
|
||||
```
|
||||
|
||||
### Database connectie fout
|
||||
```bash
|
||||
# Check database status
|
||||
docker-compose logs db
|
||||
|
||||
# Herstart database
|
||||
docker-compose restart db
|
||||
```
|
||||
|
||||
### API start probleem
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs auth_api
|
||||
|
||||
# Controleer environment variabelen in .env
|
||||
# Controleer database connection string
|
||||
```
|
||||
|
||||
### Admin UI niet bereikbaar
|
||||
```bash
|
||||
# Check Admin UI container
|
||||
docker-compose logs admin_ui
|
||||
|
||||
# Zorg ervoor dat poort 5174 niet in gebruik is
|
||||
lsof -i :5174
|
||||
```
|
||||
|
||||
## Admin Control Center
|
||||
|
||||
De Admin UI is een modern React + Vite applicatie die alle admin functies biedt.
|
||||
|
||||
### Features
|
||||
|
||||
- **Authenticatie**: JWT-based login met dev token helper
|
||||
- **Stops Management**: Create en beheer transit stops met geo-coördinaten
|
||||
- **Bus Lines**: Define bus routes met start/end stops en reistijd
|
||||
- **Fleet Management**: Monitor fleet vehicles
|
||||
- **Stop Linking**: Assign stops aan bus lines met volgorde en ETA
|
||||
|
||||
### Toegang
|
||||
|
||||
```
|
||||
URL: http://localhost:5174
|
||||
```
|
||||
|
||||
### Deployment Configuratie
|
||||
|
||||
Environment variabelen in docker-compose.yml:
|
||||
- `VITE_AUTH_API`: URL naar auth_api (standaard: http://auth_api:5000)
|
||||
- `VITE_TRANSIT_API`: URL naar transit_api (standaard: http://transit_api:5001)
|
||||
|
||||
Voor externe toegang, update de URLs naar je deployment domain.
|
||||
|
||||
### Build en Deployment
|
||||
|
||||
```bash
|
||||
# Build Admin UI image
|
||||
docker-compose build admin_ui
|
||||
|
||||
# Push naar registry
|
||||
./scripts/build-and-push.sh ghcr.io/your-org/xtransit latest
|
||||
|
||||
# Deploy met updated image
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Wijzigingen doorgevoerd in code
|
||||
|
||||
```bash
|
||||
# Rebuild container
|
||||
docker-compose build auth_api
|
||||
|
||||
# Herstart service
|
||||
docker-compose restart auth_api
|
||||
```
|
||||
|
||||
### Code reloading (hot reload)
|
||||
|
||||
Voor hot reload kunt u volumes toevoegen aan docker-compose.yml:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./auth_api:/app
|
||||
```
|
||||
|
||||
Dit kan performance beïnvloeden. Alleen gebruiken tijdens development.
|
||||
|
||||
## Productie Tips
|
||||
|
||||
1. **Veiligheid**: Wijzig alle wachtwoorden en JWT_SECRET in .env
|
||||
2. **Database**: Gebruik een managed database service in productie
|
||||
3. **Logging**: Configureer centralized logging (ELK stack, Splunk, etc.)
|
||||
4. **Backups**: Stel automatische backups in voor de database
|
||||
5. **Health Checks**: Monitoreer de health endpoints van de APIs
|
||||
6. **SSL/TLS**: Gebruik reverse proxy (nginx) voor HTTPS
|
||||
|
||||
## Netwerking
|
||||
|
||||
De services kunnen elkaar bereiken via:
|
||||
- auth_api: `http://auth_api:5000`
|
||||
- employee_api: `http://employee_api:4000`
|
||||
- transit_api: `http://transit_api:5001`
|
||||
- database: `db:5432`
|
||||
@@ -0,0 +1,55 @@
|
||||
# XTransit Domains
|
||||
|
||||
This document is the central reference for the public XTransit hostnames.
|
||||
Use HTTPS for every public request.
|
||||
|
||||
## Public Domains
|
||||
|
||||
| Domain | Service | Purpose |
|
||||
| -------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `https://auth.xtransit.testinstance.nl` | Auth API | Driver and administrator login. Issues and validates JWT authentication tokens. Use this domain only for authentication requests such as `POST /login`. |
|
||||
| `https://employees.xtransit.testinstance.nl` | Employee API | Employee onboarding and employee management. |
|
||||
| `https://transit.xtransit.testinstance.nl` | Transit API | Transit and schedule data used by the Windows XP driver client, admin UI, and public timetable clients. This includes assigned daily schedules, weekly templates, shifts, bus lines, stops, routes, and timetable views. |
|
||||
| `https://error.xtransit.testinstance.nl` | Error Log API | Central error collection and administration. Services send errors to `POST /error_log`; administrators can inspect them through `GET /error_log`. |
|
||||
| `https://admin.xtransit.testinstance.nl` | Admin panel | Browser-based administration interface for managing bus lines, stops, vehicles, weekly schedules, driver shifts, and error logs. |
|
||||
|
||||
## Client Rules
|
||||
|
||||
### Windows XP driver client
|
||||
|
||||
The XP client must use:
|
||||
|
||||
- Auth and login: `https://auth.xtransit.testinstance.nl`
|
||||
- Assigned schedules and route stops: `https://transit.xtransit.testinstance.nl`
|
||||
|
||||
The XP client must never use the auth domain for transit data.
|
||||
|
||||
### Admin UI and public timetable
|
||||
|
||||
The admin panel is available at `https://admin.xtransit.testinstance.nl`.
|
||||
The admin UI and public timetable use:
|
||||
|
||||
- Authentication: `https://auth.xtransit.testinstance.nl`
|
||||
- Transit API: `https://transit.xtransit.testinstance.nl`
|
||||
- Error logging: `https://error.xtransit.testinstance.nl`
|
||||
|
||||
### Backend services
|
||||
|
||||
The backend services report errors to:
|
||||
|
||||
```text
|
||||
https://error.xtransit.testinstance.nl/error_log
|
||||
```
|
||||
|
||||
The database and internal Docker service name are deployment details and should not
|
||||
be exposed as public client URLs. Public clients must use the HTTPS domains above.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```text
|
||||
auth.xtransit.testinstance.nl Authentication and JWT tokens
|
||||
employees.xtransit.testinstance.nl Employee management
|
||||
transit.xtransit.testinstance.nl All transit and schedule data
|
||||
error.xtransit.testinstance.nl Central error logging
|
||||
admin.xtransit.testinstance.nl Browser-based administration panel
|
||||
```
|
||||
@@ -0,0 +1,281 @@
|
||||
# Transit Control Room
|
||||
|
||||
`monitoring_ui` is a React + Vite operations dashboard for the XTransit service group. It gives an operator one place to answer four questions:
|
||||
|
||||
1. Are the services reachable right now?
|
||||
2. What kind of data does each service provide?
|
||||
3. Which errors and bad requests have been recorded?
|
||||
4. Can I safely inspect a real API response without building a curl command by hand?
|
||||
|
||||
The dashboard is a browser-only application. It does not introduce a database, server-side session store, or monitoring proxy. Requests go directly from the browser to the configured services.
|
||||
|
||||
## 1. What It Monitors
|
||||
|
||||
| Surface | Default URL | Health request | Purpose |
|
||||
| ------------- | -------------------------------------------- | -------------- | --------------------------------------------------------- |
|
||||
| Auth API | `http://localhost:5000` | `GET /me` | 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 as `401`, `403`, or `503`.
|
||||
- `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.
|
||||
|
||||
The Auth API uses `/me` because it does not currently expose a public `/health` endpoint. Without a JWT this normally appears as `degraded`, not as a broken service. Add a token in Connections when an authenticated Auth API signal is required.
|
||||
|
||||
Transit health includes database reachability. Employee health currently confirms process reachability only. 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.
|
||||
|
||||
### Errors and bad requests
|
||||
|
||||
The Errors & bad requests tab reads:
|
||||
|
||||
```text
|
||||
GET /error_log?limit=80
|
||||
Authorization: Bearer <admin-jwt>
|
||||
```
|
||||
|
||||
The Error Log API restricts this endpoint to administrator tokens. The dashboard displays timestamp, service, route or sub-service, and normalized error text. The dashboard does not write new logs itself; the existing APIs already report their failures to `error_log_api`.
|
||||
|
||||
If the token is missing, the dashboard explains how to configure it. If the token is expired or not an administrator token, the API response is shown as a load failure rather than silently displaying an empty incident list.
|
||||
|
||||
### Request lab
|
||||
|
||||
The Request lab executes only known routes listed in `testerRoutes` inside `monitoring_ui/src/App.jsx`. It supports representative calls for:
|
||||
|
||||
- Auth API current-session inspection;
|
||||
- Employee API health;
|
||||
- Transit API health;
|
||||
- public schedule progress;
|
||||
- driver daily schedule;
|
||||
- recent Error Log API entries.
|
||||
|
||||
The selected service, method, and path determine the destination. An optional JSON body can be entered for future write routes. Non-GET requests require a browser confirmation before execution.
|
||||
|
||||
This is an operator diagnostic tool, not a general-purpose arbitrary URL proxy. Keep the allowlist intentionally narrow when adding routes.
|
||||
|
||||
### Connections
|
||||
|
||||
The Connections tab edits the five service base URLs and the optional admin JWT. Values are stored in `localStorage` under:
|
||||
|
||||
- `transit-monitor-urls`
|
||||
- `transit-monitor-token`
|
||||
|
||||
This makes local experimentation convenient, but it also means the token is readable by JavaScript running on the same origin. Use the dashboard only in a trusted browser profile and do not use it on a shared workstation with untrusted browser extensions.
|
||||
|
||||
## 3. Local Development
|
||||
|
||||
```bash
|
||||
cd monitoring_ui
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open the URL printed by Vite, normally `http://localhost:5173`.
|
||||
|
||||
Build and preview the production bundle:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```text
|
||||
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, request lab
|
||||
│ └── 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:
|
||||
|
||||
```env
|
||||
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`, `POST`, `OPTIONS`, and any methods used by approved tester routes;
|
||||
- `Content-Type`;
|
||||
- `Authorization`.
|
||||
|
||||
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 does not implement a second login system. It accepts a JWT created by the existing Auth API. Obtain a token through the normal admin login flow, then paste it into Connections.
|
||||
|
||||
The Error Log API verifies both JWT validity and the `isAdmin` claim. A valid non-admin token is not sufficient to read centralized errors.
|
||||
|
||||
Operational safeguards:
|
||||
|
||||
- never commit `.env.local` or copied tokens;
|
||||
- avoid putting production JWTs in screenshots, issue reports, or browser history;
|
||||
- keep the request lab allowlist small;
|
||||
- require confirmation for all mutating requests;
|
||||
- prefer read-only routes for routine diagnostics;
|
||||
- use HTTPS for deployed APIs and dashboard access;
|
||||
- restrict CORS to known origins in production;
|
||||
- consider moving token handling to an authenticated same-origin backend if the dashboard becomes a multi-user production console.
|
||||
|
||||
## 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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```env
|
||||
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
|
||||
|
||||
1. Check that the API processes are running.
|
||||
2. Check the URL in Connections, including protocol and port.
|
||||
3. Open the health URL directly in a browser or use `curl`.
|
||||
4. Inspect the browser console for CORS or TLS errors.
|
||||
5. Confirm that Docker port mappings match `docker-compose.yml`.
|
||||
|
||||
### Auth API shows degraded
|
||||
|
||||
`GET /me` requires a bearer token. Paste a current admin JWT into Connections. A `401` means the API answered and is reachable, but the supplied token is absent or invalid.
|
||||
|
||||
### Error list is empty
|
||||
|
||||
An empty list can mean either that no errors were returned or that the request was not authorized. Check the Errors tab status text and verify that the token has `isAdmin: true`. The Error Log API also requires its database table `data.errors` to exist.
|
||||
|
||||
### 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:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:5174/health
|
||||
```
|
||||
|
||||
Expected body:
|
||||
|
||||
```json
|
||||
{ "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:
|
||||
|
||||
1. Add its base URL to `configured`.
|
||||
2. Add its metadata to `serviceMeta`.
|
||||
3. Add a health path to `healthPaths`.
|
||||
4. Add representative safe routes to `testerRoutes`.
|
||||
5. Add its environment variable to this document and `.env.local` examples.
|
||||
6. Confirm the service has CORS headers and an appropriate health endpoint.
|
||||
7. Run `npm run build` and perform a browser smoke test.
|
||||
|
||||
To add a request route, include a short label and keep the route literal. Avoid user-entered arbitrary URLs, unrestricted HTTP methods, or unrestricted request headers.
|
||||
|
||||
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;
|
||||
- export of incident rows for an operator handoff;
|
||||
- a same-origin authenticated backend if the tool becomes a shared production console;
|
||||
- a dedicated `/health` endpoint for Auth API so authentication status and process health are separate signals.
|
||||
|
||||
## 9. Validation Checklist
|
||||
|
||||
Before shipping a dashboard change:
|
||||
|
||||
```bash
|
||||
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;
|
||||
- an admin JWT loads Error Log API data;
|
||||
- an invalid token produces a visible error state;
|
||||
- each Request lab route targets the expected service;
|
||||
- the layout remains usable at a narrow mobile width.
|
||||
@@ -0,0 +1,169 @@
|
||||
# Transit Project Guide
|
||||
|
||||
This repository contains the XTransit service group, its React administration console, the monitoring dashboard, and a retained legacy client.
|
||||
|
||||
## Repository Map
|
||||
|
||||
| Directory | Responsibility | Default port |
|
||||
| ----------------------- | --------------------------------------------------- | -----------: |
|
||||
| `auth_api/` | Authentication and JWT issuance | 5000 |
|
||||
| `employee_api/` | Employee onboarding and management | 4000 |
|
||||
| `transit_api/` | Routes, schedules, fleet, GPS, and admin operations | 5001 |
|
||||
| `error_log_api/` | Central error collection and protected log reads | 5003 |
|
||||
| `admin_ui/` | React + Vite operations console served by nginx | 5174 |
|
||||
| `monitoring_ui/` | React + Vite service monitoring dashboard | 5173 in dev |
|
||||
| `deprecated/` | Retained Flutter bus-terminal client | n/a |
|
||||
| `windows_xp_driver_ui/` | Legacy driver UI work | n/a |
|
||||
|
||||
Public domains and their intended roles are listed in [DOMAINS_README.md](../DOMAINS_README.md).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git
|
||||
- Node.js 18+
|
||||
- npm
|
||||
- Docker 20.10+ and Docker Compose v2 for container workflows
|
||||
- PostgreSQL for non-mock API development
|
||||
- access to the configured database schemas and service credentials
|
||||
|
||||
## Local API Development
|
||||
|
||||
Each Node service has its own `package.json` and starts independently:
|
||||
|
||||
```bash
|
||||
npm --prefix ./auth_api install
|
||||
npm --prefix ./employee_api install
|
||||
npm --prefix ./transit_api install
|
||||
npm --prefix ./error_log_api install
|
||||
```
|
||||
|
||||
The services read database and JWT settings from environment variables. Keep credentials in an ignored `.env` file or your secret manager. Never commit database passwords, JWT signing keys, or production tokens.
|
||||
|
||||
Transit API development can use `DEV_MOCK=1` for in-memory mock storage where supported. Mock mode is for development and should not be used as a production health signal.
|
||||
|
||||
## Docker and Deployment
|
||||
|
||||
The root `docker-compose.yml` pulls service images from the configured registry and expects an external PostgreSQL instance. Provide a server-side `.env`, then:
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env pull
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
Useful operations:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs -f auth_api
|
||||
docker compose logs -f transit_api
|
||||
docker compose up -d --force-recreate
|
||||
docker compose down
|
||||
```
|
||||
|
||||
See [DOCKER_README.md](../DOCKER_README.md), [DEPLOYMENT.md](../DEPLOYMENT.md), and [CI/CD and Portainer](../CI_CD_PORTAINER_GUIDE.md) for infrastructure-specific procedures.
|
||||
|
||||
The current compose stack exposes:
|
||||
|
||||
- `auth_api` on port 5000;
|
||||
- `employee_api` on port 4000;
|
||||
- `transit_api` on port 5001;
|
||||
- `error_log_api` on port 5003;
|
||||
- `admin_ui` on port 5174;
|
||||
- `monitoring_ui` on port 5175.
|
||||
|
||||
The monitoring dashboard is currently a separate Vite application. Its full operation and deployment notes are in [MONITORING_UI.md](MONITORING_UI.md).
|
||||
Its image is built and pushed by the Gitea workflow when `monitoring_ui/**`, `docker-compose.yml`, or the workflow changes.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The exact variable names are defined by `docker-compose.yml` and each service's database module. Common deployment values include:
|
||||
|
||||
```env
|
||||
POSTGRES_HOST=your.db.host
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=transit_db
|
||||
POSTGRES_USER_AUTH=auth_user
|
||||
POSTGRES_PASSWORD_AUTH=strong_password
|
||||
POSTGRES_USER_EMPLOYEE=employee_user
|
||||
POSTGRES_PASSWORD_EMPLOYEE=strong_password
|
||||
POSTGRES_USER_TRANSIT=transit_user
|
||||
POSTGRES_PASSWORD_TRANSIT=strong_password
|
||||
POSTGRES_USER_LOGGER=error_logger
|
||||
POSTGRES_PASSWORD_LOGGER=strong_password
|
||||
JWT_SECRET=replace-with-a-secret
|
||||
ADMIN_USER_CODES=42,101
|
||||
ERROR_LOG_API_URL=https://error.example.test/error_log
|
||||
```
|
||||
|
||||
Use the names required by the active compose file. Do not copy these placeholders into a production environment without replacing them.
|
||||
|
||||
## Database Prerequisites
|
||||
|
||||
The APIs expect their configured schemas and tables to exist. The central error logger requires at least:
|
||||
|
||||
```sql
|
||||
CREATE SCHEMA IF NOT EXISTS data;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS data.errors (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
"date" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
service TEXT NOT NULL,
|
||||
partofservice TEXT,
|
||||
error TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
Use separate database users with the minimum required permissions. The exact transit, route, worker, and fleet schemas are part of the deployment database setup rather than this application repository.
|
||||
|
||||
## API Health and Debugging
|
||||
|
||||
The primary health requests are:
|
||||
|
||||
```text
|
||||
GET http://localhost:4000/health
|
||||
GET http://localhost:5001/health
|
||||
GET http://localhost:5003/health
|
||||
GET http://localhost:5174/health
|
||||
```
|
||||
|
||||
Auth API currently uses `GET /me`, which requires a JWT. The monitoring dashboard documents the distinction between process health and authenticated health in [MONITORING_UI.md](MONITORING_UI.md).
|
||||
|
||||
When a service fails:
|
||||
|
||||
1. Check container status and logs.
|
||||
2. Check the service's environment variables.
|
||||
3. Check database network connectivity and credentials.
|
||||
4. Check that required schemas and permissions exist.
|
||||
5. Call the health endpoint directly.
|
||||
6. Check the central Error Log API if the service was able to report its failure.
|
||||
|
||||
## Admin UI
|
||||
|
||||
The admin UI manages stops, bus lines, fleet, schedules, and timetable views. Its API and schedule-specific documentation remains next to the source in `admin_ui/`. The nginx image now exposes `/health` as JSON for the monitoring dashboard.
|
||||
|
||||
Build it locally with:
|
||||
|
||||
```bash
|
||||
cd admin_ui
|
||||
npm install
|
||||
npm run build
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## CI and Registry
|
||||
|
||||
The GitHub Actions workflow builds service images and pushes them to the configured container registry. Registry authentication requires a token with the appropriate package permissions. Keep registry credentials outside source control.
|
||||
|
||||
## Security Rules
|
||||
|
||||
- keep secrets in ignored environment files or a secret manager;
|
||||
- use TLS at public boundaries;
|
||||
- use least-privilege database users;
|
||||
- restrict CORS origins for production deployments;
|
||||
- keep admin JWTs out of logs and screenshots;
|
||||
- review allowlisted routes before expanding the monitoring request lab;
|
||||
- treat `DEV_MOCK=1` as a local development setting only.
|
||||
|
||||
## Documentation Policy
|
||||
|
||||
Use `docs/` for project-wide operational and architectural guidance. Keep service-specific API details next to the service when they are maintained with that service. The root `README.md` should remain a concise orientation page with links, not a second deployment manual.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Transit Project Documentation Hub
|
||||
|
||||
This directory is the consolidated documentation hub for the Transit Project. All system documentation, operational guides, and service specifications live here inside `monitoring_ui/docs/`.
|
||||
|
||||
## Core Guides
|
||||
|
||||
- [Project Guide](PROJECT_GUIDE.md): Architecture, local development, environment variables, Docker, deployment, database prerequisites, and troubleshooting.
|
||||
- [Monitoring UI Guide](MONITORING_UI.md): Complete operations manual for `monitoring_ui`.
|
||||
- [Root Readme](ROOT_README.md): Original main overview page.
|
||||
- [Getting Started Guide](GETTING_STARTED.md): 5-minute setup & deployment quickstart.
|
||||
- [Deployment Guide](DEPLOYMENT.md): Production deployment instructions & DB setup.
|
||||
- [CI/CD & Portainer Guide](CI_CD_PORTAINER_GUIDE.md): Automation, registry, and Portainer stack deployment.
|
||||
- [Admin Deployment Summary](ADMIN_DEPLOYMENT_SUMMARY.md): Deployment status and deliverable notes.
|
||||
- [Docker Notes](DOCKER_README.md): Docker and Docker Compose workflows.
|
||||
- [Domains Overview](DOMAINS_README.md): Domain mappings and endpoint list.
|
||||
- [Security & Private Files](SECURITY_PRIVATE_FILES.md): Security practices & credential safety rules.
|
||||
- [Developer Handoff](handoff.md): Engineering handoff notes.
|
||||
- [Azure Project Plan](azure-project-plan.md): Azure migration and project planning notes.
|
||||
|
||||
## Service Documentation
|
||||
|
||||
- [Admin UI Documentation](admin_ui/README.md)
|
||||
- [Admin Schedule API Guide](admin_ui/SCHEDULE_API.md)
|
||||
- [Enhanced Schedule Maker](admin_ui/SCHEDULE_MAKER_ENHANCED.md)
|
||||
- [Transit API Documentation](transit_api/README.md)
|
||||
- [Local Bus Timetable Spec](transit_api/LOCAL_BUS_TIMETABLE_README.md)
|
||||
- [Windows XP Driver UI Documentation](windows_xp_driver_ui/README.md)
|
||||
- [Deprecated Flutter Client Documentation](deprecated/README.md)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Transit Project
|
||||
|
||||
XTransit is a service-oriented transit platform consisting of Node.js APIs, React operator interfaces, and retained legacy clients.
|
||||
|
||||
## Quick Map
|
||||
|
||||
- `auth_api/` - authentication and JWT issuance
|
||||
- `employee_api/` - employee management
|
||||
- `transit_api/` - schedules, routes, fleet, GPS, and transit administration
|
||||
- `error_log_api/` - centralized error collection and protected log access
|
||||
- `admin_ui/` - React administration console
|
||||
- `monitoring_ui/` - React service monitoring dashboard
|
||||
- `deprecated/` and `windows_xp_driver_ui/` - retained legacy clients
|
||||
|
||||
Public employee API: `https://employees.xtransit.testinstance.nl`
|
||||
|
||||
## Documentation
|
||||
|
||||
Start with the [documentation hub](docs/README.md).
|
||||
|
||||
- [Project guide](docs/PROJECT_GUIDE.md) - setup, architecture, environment, Docker, deployment, databases, and troubleshooting
|
||||
- [Monitoring UI guide](docs/MONITORING_UI.md) - complete `monitoring_ui` operations and development manual
|
||||
- [Domains](DOMAINS_README.md) - public domain and service mapping
|
||||
- [Docker notes](DOCKER_README.md) - container workflow
|
||||
- [Deployment guide](DEPLOYMENT.md) - deployment procedures
|
||||
- [CI/CD and Portainer guide](CI_CD_PORTAINER_GUIDE.md) - image and stack operations
|
||||
|
||||
## Quick Start
|
||||
|
||||
For the deployed service stack:
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
For the monitoring dashboard:
|
||||
|
||||
```bash
|
||||
cd monitoring_ui
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Keep database credentials, JWT secrets, registry credentials, and tokens outside version control. Use environment variables, ignored local files, Portainer secrets, or another secret manager.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Security: Private Files Exclusion
|
||||
|
||||
This document explains which files are kept private and why.
|
||||
|
||||
## Files Excluded from Git & Docker
|
||||
|
||||
### Deployment Documentation (Private)
|
||||
|
||||
- `ADMIN_DEPLOYMENT_SUMMARY.md` - Internal deployment status and setup details
|
||||
- `CI_CD_PORTAINER_GUIDE.md` - Private CI/CD and Portainer configuration
|
||||
- `DEPLOYMENT.md` - Deployment procedures and configuration guidance
|
||||
- `GETTING_STARTED.md` - Internal setup instructions
|
||||
- `INTERNAL_*.md` - Any file prefixed with INTERNAL\_ (pattern-based exclusion)
|
||||
- `SETUP_*.md` - Any file prefixed with SETUP\_ (pattern-based exclusion)
|
||||
- `DEPLOY_*.md` - Any file prefixed with DEPLOY\_ (pattern-based exclusion)
|
||||
|
||||
### Custom Instruction Files (Private)
|
||||
|
||||
- `.instructions.md` - GitHub Copilot custom instructions
|
||||
- `.prompt.md` - Custom prompt templates
|
||||
- `.agent.md` - Custom agent definitions
|
||||
- `SKILL.md` - Custom skill definitions
|
||||
- `copilot-instructions.md` - Extended Copilot instructions
|
||||
- `AGENTS.md` - Agent configuration
|
||||
|
||||
These are kept private to prevent exposure of:
|
||||
|
||||
- Development workflow details
|
||||
- Copilot customization strategies
|
||||
- Internal coding guidelines and preferences
|
||||
- Prompt engineering techniques
|
||||
|
||||
### Private Scripts
|
||||
|
||||
- `scripts/private/` - Directory for private deployment scripts
|
||||
- `scripts/*.local.*` - Local-specific script configurations
|
||||
|
||||
## Files Included in Public Repo
|
||||
|
||||
### Public Documentation
|
||||
|
||||
- `README.md` - Main project documentation
|
||||
- `DOCKER_README.md` - Docker usage documentation
|
||||
- `admin_ui/README.md` - Admin UI documentation
|
||||
- `admin_ui/SCHEDULE_API.md` - Public API documentation
|
||||
- `transit_api/README.md` - API documentation
|
||||
- `deprecated/README.md` - Legacy Flutter bus terminal documentation kept for historical reference
|
||||
|
||||
### Configuration
|
||||
|
||||
- `.env.example` - Environment variable template (no secrets)
|
||||
- `.gitignore` - Git exclusion rules
|
||||
- `.dockerignore` - Docker build exclusion rules
|
||||
- `docker-compose.yml` - Service composition
|
||||
- `Dockerfile` files - Container definitions
|
||||
|
||||
### Code & Configuration
|
||||
|
||||
- All source code in `auth_api/`, `transit_api/`, `employee_api/`, `admin_ui/`, and the legacy `deprecated/` app
|
||||
- `package.json` files (no secrets, only dependencies)
|
||||
- GitHub Actions workflows in `.github/workflows/`
|
||||
|
||||
## Environment Variables - NEVER Commit
|
||||
|
||||
Always keep the following OUT of git:
|
||||
|
||||
- `.env` - Local environment variables (in `.gitignore`)
|
||||
- Database credentials
|
||||
- JWT secrets
|
||||
- API keys and tokens
|
||||
- Private configuration files
|
||||
|
||||
Use `.env.example` as a template and create local `.env` files for development.
|
||||
|
||||
## Docker Build Security
|
||||
|
||||
All `.dockerignore` files (root and per-service) ensure that:
|
||||
|
||||
1. Sensitive documentation never enters Docker images
|
||||
2. Private scripts and configs are excluded from builds
|
||||
3. Only necessary source code and dependencies are included
|
||||
4. Build artifacts don't leak internal information
|
||||
|
||||
## GitHub Actions Security
|
||||
|
||||
The CI/CD workflow in `.github/workflows/docker-build.yml`:
|
||||
|
||||
- Only builds from specific service directories (auth_api, transit_api, etc.)
|
||||
- Respects `.dockerignore` rules
|
||||
- Uses GitHub secrets for credentials (never hardcoded)
|
||||
- Does not include workspace documentation in pushed images
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Before committing**: Check that `.env` is in `.gitignore` and local files are not staged
|
||||
2. **Before building Docker**: Verify `.dockerignore` files exclude private docs
|
||||
3. **Before pushing images**: Confirm no sensitive data is present (`docker inspect --format=...`)
|
||||
4. **Deployment**: Always use environment variables or secrets managers, never embed credentials
|
||||
5. **Documentation**: Keep public docs in `*.md` files, private docs in separately excluded files
|
||||
|
||||
## Adding New Private Files
|
||||
|
||||
To keep new private files out of the repo and Docker:
|
||||
|
||||
1. Add pattern to `.gitignore`:
|
||||
|
||||
```
|
||||
MYFILE_*.md
|
||||
new_private_thing.*
|
||||
```
|
||||
|
||||
2. Add pattern to `.dockerignore` (root and per-service):
|
||||
|
||||
```
|
||||
/MYFILE_*.md
|
||||
/new_private_thing.*
|
||||
```
|
||||
|
||||
3. Verify with:
|
||||
```bash
|
||||
git check-ignore -v MYFILE_something.md
|
||||
```
|
||||
@@ -0,0 +1,219 @@
|
||||
## Weekly schedules and shifts
|
||||
|
||||
The schedule manager uses the weekly template model. Administrators create a
|
||||
departure for a bus line in one of three categories: weekdays, Saturday, or
|
||||
Sunday. The UI creates the corresponding `day_of_week` rows and assigns drivers
|
||||
through `transit.shifts`, rather than storing a driver on `transit.schedules`.
|
||||
|
||||
The active UI uses these transit API endpoints:
|
||||
|
||||
- `GET /admin/weekly-schedules`
|
||||
- `GET /admin/shift-drivers`
|
||||
- `POST /admin/weekly-schedules`
|
||||
- `PUT /admin/weekly-schedules/:scheduleId/shift`
|
||||
- `DELETE /admin/weekly-schedules/:scheduleId`
|
||||
|
||||
# Transit Admin Control Center
|
||||
|
||||
Production admin panel: `https://admin.xtransit.testinstance.nl`
|
||||
|
||||
For the separate service monitoring dashboard, see
|
||||
[`../docs/MONITORING_UI.md`](../docs/MONITORING_UI.md). The monitoring dashboard
|
||||
is deployed independently on host port `5175` and checks this admin UI through
|
||||
`GET /health`.
|
||||
|
||||
Modern React + Vite web application for comprehensive transit system administration.
|
||||
|
||||
## Features
|
||||
|
||||
✅ **Stop Management** - Create and manage transit stops with geolocation
|
||||
✅ **Bus Lines** - Define routes with start/end stops and estimated durations
|
||||
✅ **Fleet Management** - Monitor and view fleet vehicles
|
||||
✅ **Stop Linking** - Assign stops to bus lines with order and ETA
|
||||
✅ **JWT Authentication** - Secure authentication with role-based access
|
||||
✅ **Production Ready** - Docker containerized with runtime env configuration
|
||||
✅ **Error Log Viewer** - Inspect centralized error logs from all services
|
||||
|
||||
## Local Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- npm or yarn
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
cd admin_ui
|
||||
npm install
|
||||
```
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
Create a `.env` file in the `admin_ui` directory:
|
||||
|
||||
```env
|
||||
VITE_AUTH_API=https://auth.xtransit.testinstance.nl
|
||||
VITE_TRANSIT_API=https://transit.xtransit.testinstance.nl
|
||||
VITE_ERROR_LOG_API=https://error.xtransit.testinstance.nl
|
||||
```
|
||||
|
||||
### Run Development Server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The app will be available at `http://localhost:5173`
|
||||
|
||||
### Build for Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This creates a production bundle in the `dist/` directory.
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
### Build Docker Image
|
||||
|
||||
```bash
|
||||
docker build -t xtransit/admin_ui:latest .
|
||||
```
|
||||
|
||||
### Run with Docker
|
||||
|
||||
```bash
|
||||
docker run -p 5174:80 \
|
||||
-e VITE_AUTH_API=/api/auth \
|
||||
-e VITE_TRANSIT_API=/api/transit \
|
||||
xtransit/admin_ui:latest
|
||||
```
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
The admin UI is integrated into the main `docker-compose.yml` at the project root.
|
||||
|
||||
From the project root:
|
||||
|
||||
```bash
|
||||
# Start all services including admin UI
|
||||
docker-compose up -d
|
||||
|
||||
# Access the admin UI
|
||||
http://localhost:5174
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| ------------------ | --------------- | ---------------------------------------- |
|
||||
| `VITE_AUTH_API` | Auth API URL | https://auth.xtransit.testinstance.nl |
|
||||
| `VITE_TRANSIT_API` | Transit API URL | https://transit.xtransit.testinstance.nl |
|
||||
|
||||
### Runtime Configuration
|
||||
|
||||
When running in Docker, environment variables are injected at runtime via `docker-entrypoint.sh` which creates `/usr/share/nginx/html/env-config.js`. This allows configuration without rebuilding the image.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Technology Stack
|
||||
|
||||
- **Frontend**: React 18.2 + Vite 5.0
|
||||
- **HTTP Client**: Axios 1.4
|
||||
- **Server**: Nginx (Alpine Linux)
|
||||
- **Build**: Multi-stage Docker build for optimized image size
|
||||
|
||||
### Component Structure
|
||||
|
||||
- `App.jsx` - Main app router, session management
|
||||
- `Login.jsx` - Authentication with dev token helper
|
||||
- `StopsManager.jsx` - Create/list transit stops
|
||||
- `BusLinesManager.jsx` - Create/list bus routes
|
||||
- `FleetManager.jsx` - View fleet vehicles
|
||||
- `LinkStop.jsx` - Link stops to bus lines
|
||||
- `ErrorLogViewer.jsx` - Central error log viewer
|
||||
|
||||
### API Integration
|
||||
|
||||
The app communicates with:
|
||||
|
||||
- **Auth API** (/login, /me)
|
||||
- **Transit API** (/admin/stops, /admin/bus-lines, /admin/fleet/buses)
|
||||
- **Error Log API** (/error_log)
|
||||
|
||||
All requests include JWT Bearer token for authentication.
|
||||
|
||||
## Authentication
|
||||
|
||||
### Login Flow
|
||||
|
||||
1. User enters user code and password
|
||||
2. Client calls POST `/login`
|
||||
3. Receives JWT token with `userId` and `userCode`
|
||||
4. JWT is stored in localStorage
|
||||
5. All API requests include `Authorization: Bearer <token>`
|
||||
|
||||
### Admin Authorization
|
||||
|
||||
Users must have a `userCode` in their JWT and, for admin access, the `isAdmin` flag set by the `auth_api` based on the `ADMIN_USER_CODES` environment variable.
|
||||
|
||||
### Production Setup
|
||||
|
||||
1. Remove dev token button from Login.jsx
|
||||
2. Implement real authentication system (OAuth/SAML)
|
||||
3. Configure proper JWT generation in auth_api
|
||||
4. Set strong `JWT_SECRET` environment variable
|
||||
5. Configure `ADMIN_USER_CODES` with actual admin user IDs
|
||||
6. Configure `VITE_ERROR_LOG_API` if you use a custom logging endpoint
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "Admin UI not loading"
|
||||
|
||||
- Verify container is running: `docker ps`
|
||||
- Check logs: `docker-compose logs admin_ui`
|
||||
- Clear browser cache (Ctrl+Shift+R)
|
||||
|
||||
### Issue: "API connection refused"
|
||||
|
||||
- Ensure auth_api and transit_api are running
|
||||
- Check environment variables are set correctly
|
||||
- Verify network connectivity between containers
|
||||
|
||||
### Issue: "Permission denied" on admin operations
|
||||
|
||||
- Verify JWT token includes valid `userCode`
|
||||
- Check `ADMIN_USER_CODES` environment variable
|
||||
- Ensure database user has appropriate permissions
|
||||
|
||||
## Deployment
|
||||
|
||||
See [DEPLOYMENT.md](../DEPLOYMENT.md) for comprehensive deployment guide.
|
||||
|
||||
### Production Checklist
|
||||
|
||||
- [ ] Remove development authentication helpers
|
||||
- [ ] Set strong JWT_SECRET
|
||||
- [ ] Configure proper ADMIN_USER_CODES
|
||||
- [ ] Enable HTTPS/SSL
|
||||
- [ ] Configure CORS for production domain
|
||||
- [ ] Set up monitoring and logging
|
||||
- [ ] Configure database backups
|
||||
- [ ] Document admin procedures
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
|
||||
1. Check service logs: `docker-compose logs admin_ui`
|
||||
2. Verify API connectivity: Visit API URLs directly
|
||||
3. Check browser console for client-side errors
|
||||
4. Review DEPLOYMENT.md for troubleshooting
|
||||
|
||||
## License
|
||||
|
||||
Part of the XTransit project
|
||||
@@ -0,0 +1,281 @@
|
||||
# Schedule Maker & Public Timetable API
|
||||
|
||||
## Features
|
||||
|
||||
The Transit API now includes a comprehensive schedule management system with both admin and public endpoints.
|
||||
|
||||
### Weekly Admin Endpoints (requires authentication + admin privileges)
|
||||
|
||||
The active admin UI uses weekly schedule templates. `dayOfWeek` follows the
|
||||
JavaScript/PostgreSQL convention: `0` Sunday, `1` through `5` weekdays, and `6`
|
||||
Saturday. Driver assignment is stored in `transit.shifts` and references
|
||||
`workers.users(id)`.
|
||||
|
||||
#### Get weekly schedules
|
||||
|
||||
```
|
||||
GET /admin/weekly-schedules
|
||||
Response: { schedules: [...] }
|
||||
```
|
||||
|
||||
#### Get shift drivers
|
||||
|
||||
```
|
||||
GET /admin/shift-drivers
|
||||
Response: { drivers: [{ id, name }] }
|
||||
```
|
||||
|
||||
#### Create a weekly schedule
|
||||
|
||||
````
|
||||
|
||||
#### Create multiple departures
|
||||
|
||||
```text
|
||||
POST /admin/weekly-schedules/bulk
|
||||
Body: {
|
||||
busLineId: 1,
|
||||
dayOfWeeks: [1, 2, 3, 4, 5],
|
||||
startTimes: ["06:00", "06:30", "07:00"],
|
||||
driverId: 12
|
||||
}
|
||||
````
|
||||
|
||||
The API creates one schedule row for every day/time combination and derives the
|
||||
end time from the bus line's configured duration.
|
||||
POST /admin/weekly-schedules
|
||||
Body: {
|
||||
busLineId: 1,
|
||||
dayOfWeek: 1,
|
||||
startTime: "08:00",
|
||||
endTime: "09:00",
|
||||
driverId: 12
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Replace a schedule's driver
|
||||
|
||||
```
|
||||
|
||||
PUT /admin/weekly-schedules/:scheduleId/shift
|
||||
Body: { driverId: 12 }
|
||||
|
||||
```
|
||||
|
||||
Use `{ "driverId": null }` to unassign the driver. The current `shifts` table
|
||||
does not contain a week/date column, so this is an active assignment rather than
|
||||
historical per-week assignment. Add `week_start` to support that later.
|
||||
|
||||
### Legacy Admin Endpoints
|
||||
|
||||
#### Get all schedules
|
||||
|
||||
```
|
||||
|
||||
GET /admin/schedules
|
||||
Response: { schedules: [...] }
|
||||
|
||||
```
|
||||
|
||||
#### Create a schedule
|
||||
|
||||
```
|
||||
|
||||
POST /admin/schedules
|
||||
Body: {
|
||||
busLineId: number,
|
||||
busId: number,
|
||||
driverId: number (optional),
|
||||
startTime: "2026-05-06T08:00:00",
|
||||
endTime: "2026-05-06T17:00:00"
|
||||
}
|
||||
Response: { schedule: {...} }
|
||||
|
||||
```
|
||||
|
||||
#### Delete a schedule
|
||||
|
||||
```
|
||||
|
||||
DELETE /admin/schedules/:scheduleId
|
||||
Response: { success: true, schedule: {...} }
|
||||
|
||||
```
|
||||
|
||||
### Public Endpoints (no authentication required)
|
||||
|
||||
#### Get schedules (with optional filters)
|
||||
|
||||
```
|
||||
|
||||
GET /schedules?date=2026-05-06&lineId=1
|
||||
Query params:
|
||||
|
||||
- date: YYYY-MM-DD (optional)
|
||||
- lineId: number (optional)
|
||||
Response: { schedules: [...] }
|
||||
|
||||
```
|
||||
|
||||
#### Get schedule detail
|
||||
|
||||
```
|
||||
|
||||
GET /schedules/:scheduleId
|
||||
Response: { schedule: {...} }
|
||||
|
||||
```
|
||||
|
||||
#### Get stops for a schedule's line
|
||||
|
||||
```
|
||||
|
||||
GET /schedules/:scheduleId/stops
|
||||
Response: { stops: [...] }
|
||||
Shows all stops on the bus line with order, location, and ETA.
|
||||
|
||||
````
|
||||
|
||||
## Admin UI Features
|
||||
|
||||
The ScheduleMaker component provides:
|
||||
|
||||
1. **Weekly schedule editor**
|
||||
|
||||
- Select a bus line and one of weekdays, Saturday, or Sunday
|
||||
- Define start and end times
|
||||
- Assign drivers through shifts
|
||||
- Admin-only access
|
||||
|
||||
2. **Timetable View**
|
||||
- 24-hour time slots (hourly grouping)
|
||||
- Services displayed in corresponding time slots
|
||||
- Shows line number, vehicle name, and license plate
|
||||
- Delete button for each service (admin only)
|
||||
- Color-coded schedule cards with gradient styling
|
||||
|
||||
3. **Drag-and-Drop Ready**
|
||||
- Schedule cards are draggable (extensible for drag-to-reorder)
|
||||
- Follows existing UI/UX patterns from LinkStop component
|
||||
|
||||
4. **Confirmation Modals**
|
||||
- Delete confirmation before removing schedules
|
||||
- Shows service details in confirmation
|
||||
- Prevents accidental deletions
|
||||
|
||||
## Public Timetable Viewer
|
||||
|
||||
The TimetableViewer component provides a public-facing schedule display:
|
||||
|
||||
```jsx
|
||||
import TimetableViewer from "./components/TimetableViewer";
|
||||
|
||||
<TimetableViewer apiBaseUrl="http://api.transit.local:5001" />;
|
||||
````
|
||||
|
||||
Features:
|
||||
|
||||
- Filter by date and bus line
|
||||
- Real-time loading state
|
||||
- Error handling
|
||||
- Status badges (planned/active)
|
||||
- Responsive table layout
|
||||
- No authentication required
|
||||
|
||||
## Development Mode
|
||||
|
||||
With `DEV_MOCK=1`, all schedule operations work in-memory without a database.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
ADMIN_USER_CODES=42 DEV_MOCK=1 JWT_SECRET=devsecret npm --prefix ./transit_api start
|
||||
```
|
||||
|
||||
## Database Schema (Production)
|
||||
|
||||
```sql
|
||||
CREATE TABLE transit.schedules (
|
||||
id BIGINT PRIMARY KEY,
|
||||
bus_line_id BIGINT REFERENCES transit.bus_lines(id),
|
||||
start_time TIME,
|
||||
end_time TIME,
|
||||
status VARCHAR(20) DEFAULT 'planned',
|
||||
day_of_week SMALLINT NOT NULL CHECK (day_of_week BETWEEN 0 AND 6),
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE transit.shifts (
|
||||
id BIGINT PRIMARY KEY,
|
||||
schedule_id BIGINT REFERENCES transit.schedules(id) ON DELETE CASCADE,
|
||||
driver_id BIGINT REFERENCES workers.users(id)
|
||||
);
|
||||
```
|
||||
|
||||
## Styling & UX
|
||||
|
||||
The schedule manager uses:
|
||||
|
||||
### Admin Timetable Styling
|
||||
|
||||
- Responsive table with hourly time slots
|
||||
- Gradient schedule cards (blue/indigo theme)
|
||||
- Hover effects and smooth transitions
|
||||
- Grab cursor on draggable items
|
||||
- Danger buttons for delete actions (red)
|
||||
- Confirmation modals with semi-transparent overlay
|
||||
|
||||
### Public Timetable Styling
|
||||
|
||||
- Clean, simple table layout
|
||||
- Status badges (green for active, gray for planned)
|
||||
- Mobile-responsive with scrolling
|
||||
- Consistent with existing design language
|
||||
|
||||
## Integration Points
|
||||
|
||||
1. **Admin Dashboard**: ScheduleMaker appears at the bottom of Admin Control Center
|
||||
2. **Public API**: Available via public `/schedules` endpoints without authentication
|
||||
3. **Flutter App**: TimetableViewer can be embedded or used as reference for mobile implementation
|
||||
4. **Frontend Flexibility**: TimetableViewer component is reusable for any public-facing website
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Create a schedule (Admin)
|
||||
|
||||
```bash
|
||||
curl -X POST https://transit.xtransit.testinstance.nl/admin/schedules \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"busLineId": 1,
|
||||
"busId": 5,
|
||||
"driverId": 101,
|
||||
"startTime": "2026-05-06T08:00:00",
|
||||
"endTime": "2026-05-06T17:00:00"
|
||||
}'
|
||||
```
|
||||
|
||||
### Get today's schedules (Public)
|
||||
|
||||
```bash
|
||||
curl https://transit.xtransit.testinstance.nl/schedules?date=$(date +%Y-%m-%d)
|
||||
```
|
||||
|
||||
### Get schedules for specific line (Public)
|
||||
|
||||
```bash
|
||||
curl https://transit.xtransit.testinstance.nl/schedules?lineId=3
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- Bulk schedule import from CSV
|
||||
- Recurring schedule templates (weekly, daily patterns)
|
||||
- Driver shift assignment with time tracking
|
||||
- Real-time schedule updates and notifications
|
||||
- Schedule conflict detection
|
||||
- Integration with GPS tracking for actual vs scheduled times
|
||||
- Historical schedule analytics
|
||||
@@ -0,0 +1,461 @@
|
||||
# Enhanced Schedule Maker - Dokumentatie
|
||||
|
||||
## Overzicht
|
||||
|
||||
Het Schedule Maker systeem is uitgebreid met geavanceerde planning functies:
|
||||
|
||||
### ✅ Implemented Features
|
||||
|
||||
#### 1. Automatische Eindtijd Berekening
|
||||
- **Voordeel**: Geen handmatige eindtijd invoer meer
|
||||
- **Hoe het werkt**: Eindtijd = Begintijd + Geschatte rijduur van de lijn
|
||||
- **Voorbeeld**:
|
||||
- Lijn 101: geschatte duur 45 minuten
|
||||
- Begintijd: 08:00
|
||||
- Eindtijd: 08:45 (automatisch berekend)
|
||||
|
||||
#### 2. Automatische Vertrektijden per Halte
|
||||
- **Functionaliteit**: Berekent vertrektijd voor elke halte op basis van:
|
||||
- Begintijd van de dienst
|
||||
- Geschatte aankomsttijd per halte (in `route_stops.estimated_arrival_minutes`)
|
||||
- **Weergave**: Uitklapbaar tabel in schedule card met:
|
||||
- Haltenummer
|
||||
- Haltename
|
||||
- Vertrektijd
|
||||
|
||||
**Voorbeeld JSON response:**
|
||||
```json
|
||||
{
|
||||
"schedule": {
|
||||
"id": 1,
|
||||
"busLineId": 101,
|
||||
"busId": 5,
|
||||
"driverId": 3,
|
||||
"startTime": "2026-05-06T08:00:00Z",
|
||||
"endTime": "2026-05-06T08:45:00Z",
|
||||
"weekdays": [1, 2, 3, 4, 5],
|
||||
"departureTimes": [
|
||||
{
|
||||
"order": 1,
|
||||
"stopId": 10,
|
||||
"stopName": "Central Station",
|
||||
"estimatedArrivalMinutes": 0,
|
||||
"departureTime": "2026-05-06T08:00:00Z"
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
"stopId": 11,
|
||||
"stopName": "Market Square",
|
||||
"estimatedArrivalMinutes": 10,
|
||||
"departureTime": "2026-05-06T08:10:00Z"
|
||||
},
|
||||
{
|
||||
"order": 3,
|
||||
"stopId": 12,
|
||||
"stopName": "Park Lane",
|
||||
"estimatedArrivalMinutes": 25,
|
||||
"departureTime": "2026-05-06T08:25:00Z"
|
||||
}
|
||||
],
|
||||
"status": "planned"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Herhaald Rooster (Weekdagen)
|
||||
- **Functionaliteit**: Plan een dienst op meerdere weekdagen
|
||||
- **Invoer**: Klik op weekdagknoppen (Ma, Di, Wo, Do, Vr, Za, Zo)
|
||||
- **Opslag**: `schedules.weekdays` array met dagwaarden (0-6, waarbij 0=Zondag, 1=Maandag, etc.)
|
||||
- **Weergave**: In schedule card getoond als "Maandag, Woensdag, Vrijdag"
|
||||
|
||||
**Request voorbeeld:**
|
||||
```json
|
||||
POST /admin/schedules
|
||||
{
|
||||
"busLineId": 101,
|
||||
"busId": 5,
|
||||
"driverId": 3,
|
||||
"startTime": "2026-05-06T08:00:00Z",
|
||||
"weekdays": [1, 3, 5] // Ma, Wo, Vr
|
||||
}
|
||||
```
|
||||
|
||||
**Weergave in UI:**
|
||||
- "Eenmalig" - geen weekdays geselecteerd
|
||||
- "Maandag, Woensdag, Vrijdag" - specifieke weekdays
|
||||
- "Dagelijks" - alle 7 weekdays
|
||||
|
||||
#### 4. Bestuurders Dropdown
|
||||
- **Functionaliteit**: Selecteer bestuurder uit dropdown bij dienst aanmaken
|
||||
- **Bron**: GET `/admin/drivers` endpoint
|
||||
- **Opslag**: `schedules.driver_id` veld
|
||||
- **Weergave**:
|
||||
- In schedule card: "Bestuurdernaam"
|
||||
- Optioneel veld (NULL als niet ingesteld)
|
||||
|
||||
**Response voorbeeld:**
|
||||
```json
|
||||
{
|
||||
"drivers": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Jan Peterse",
|
||||
"email": "jan@transit.local",
|
||||
"phone": "06-12345678"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Maria Kuijpers",
|
||||
"email": "maria@transit.local",
|
||||
"phone": "06-87654321"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### GET /admin/drivers
|
||||
**Beschrijving**: Haalt lijst van beschikbare bestuurders op
|
||||
|
||||
**Response (DEV_MOCK):**
|
||||
```json
|
||||
{
|
||||
"drivers": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Jan Peterse",
|
||||
"email": "jan@transit.local",
|
||||
"phone": "06-12345678",
|
||||
"status": "active"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Production):**
|
||||
- Query uit `workers.employees` tabel
|
||||
- Filtert op `status = 'active'`
|
||||
|
||||
---
|
||||
|
||||
### POST /admin/schedules
|
||||
**Beschrijving**: Maakt nieuwe dienst aan met automatische eindtijd en vertrektijden
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"busLineId": 101,
|
||||
"busId": 5,
|
||||
"driverId": 3, // optioneel
|
||||
"startTime": "2026-05-06T08:00:00Z",
|
||||
"weekdays": [1, 2, 3, 4, 5] // optioneel, array van daggetallen
|
||||
}
|
||||
```
|
||||
|
||||
**Validatie:**
|
||||
- `busLineId`, `busId`, `startTime` zijn verplicht
|
||||
- `driverId` is optioneel (NULL als niet gegeven)
|
||||
- `weekdays` is optioneel (lege array = eenmalige dienst)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"schedule": {
|
||||
"id": 1,
|
||||
"busLineId": 101,
|
||||
"busId": 5,
|
||||
"driverId": 3,
|
||||
"startTime": "2026-05-06T08:00:00Z",
|
||||
"endTime": "2026-05-06T08:45:00Z",
|
||||
"weekdays": [1, 2, 3, 4, 5],
|
||||
"departureTimes": [
|
||||
{
|
||||
"order": 1,
|
||||
"stopId": 10,
|
||||
"stopName": "Central Station",
|
||||
"departureTime": "2026-05-06T08:00:00Z"
|
||||
},
|
||||
// ... meer haltes
|
||||
],
|
||||
"status": "planned",
|
||||
"createdAt": "2026-05-06T15:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**DEV_MOCK Details:**
|
||||
- Eindtijd = startTime + `bus_lines.estimated_duration_minutes`
|
||||
- Vertrektijden berekend via helper functie `calculateDepartureTimes()`
|
||||
- Dienst direct opgeslagen in `_mock.schedules` array
|
||||
|
||||
---
|
||||
|
||||
### GET /admin/schedules
|
||||
**Beschrijving**: Haalt alle geplande diensten met details op
|
||||
|
||||
**Response (bevat nu):**
|
||||
```json
|
||||
{
|
||||
"schedules": [
|
||||
{
|
||||
"id": 1,
|
||||
"busLineId": 101,
|
||||
"busId": 5,
|
||||
"driverId": 3,
|
||||
"driverName": "Jan Peterse", // NEW
|
||||
"startTime": "2026-05-06T08:00:00Z",
|
||||
"endTime": "2026-05-06T08:45:00Z",
|
||||
"weekdays": [1, 2, 3, 4, 5], // NEW
|
||||
"departureTimes": [ // NEW
|
||||
{
|
||||
"order": 1,
|
||||
"stopId": 10,
|
||||
"stopName": "Central Station",
|
||||
"departureTime": "2026-05-06T08:00:00Z"
|
||||
}
|
||||
],
|
||||
"status": "planned",
|
||||
"lineNumber": 101,
|
||||
"busName": "Bus A5",
|
||||
"licensePlate": "AB-123-CD",
|
||||
"createdAt": "2026-05-06T15:30:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend Componenten
|
||||
|
||||
### ScheduleMaker.jsx
|
||||
|
||||
**Nieuwe State Variabelen:**
|
||||
```jsx
|
||||
const [drivers, setDrivers] = useState([]) // Bestuurders lijst
|
||||
const [selectedWeekdays, setSelectedWeekdays] = useState([]) // Geselecteerde weekdagen
|
||||
const [expandedSchedule, setExpandedSchedule] = useState(null) // Uitgebreide schedule ID
|
||||
```
|
||||
|
||||
**Nieuwe Functions:**
|
||||
|
||||
#### loadDrivers()
|
||||
```jsx
|
||||
const loadDrivers = async () => {
|
||||
const res = await client.get('/admin/drivers')
|
||||
setDrivers(res.data.drivers || [])
|
||||
}
|
||||
```
|
||||
|
||||
#### toggleWeekday(dayValue)
|
||||
```jsx
|
||||
const toggleWeekday = (dayValue) => {
|
||||
setSelectedWeekdays(prev =>
|
||||
prev.includes(dayValue)
|
||||
? prev.filter(d => d !== dayValue)
|
||||
: [...prev, dayValue]
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### getWeekdayLabel(weekdayValues)
|
||||
```jsx
|
||||
const getWeekdayLabel = (weekdayValues) => {
|
||||
if (!weekdayValues || weekdayValues.length === 0) return 'Eenmalig'
|
||||
if (weekdayValues.length === 7) return 'Dagelijks'
|
||||
const labels = weekdayValues
|
||||
.sort()
|
||||
.map(w => WEEKDAYS[WEEKDAY_VALUES.indexOf(w)])
|
||||
return labels.join(', ')
|
||||
}
|
||||
```
|
||||
|
||||
**Nieuwe Form Elements:**
|
||||
|
||||
1. **Bestuurders Dropdown:**
|
||||
```jsx
|
||||
<select value={driverId} onChange={e => setDriverId(e.target.value)}>
|
||||
<option value="">Bestuurder (optioneel)</option>
|
||||
{drivers.map(driver => (
|
||||
<option key={driver.id} value={driver.id}>
|
||||
{driver.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
```
|
||||
|
||||
2. **Weekdagknoppen:**
|
||||
```jsx
|
||||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
|
||||
{WEEKDAYS.map((day, idx) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleWeekday(WEEKDAY_VALUES[idx])}
|
||||
style={{
|
||||
backgroundColor: selectedWeekdays.includes(WEEKDAY_VALUES[idx])
|
||||
? '#1D4ED8'
|
||||
: '#e0e0e0'
|
||||
}}
|
||||
>
|
||||
{day}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
```
|
||||
|
||||
3. **Uitklapbare Haltes Tabel:**
|
||||
```jsx
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpandedSchedule(expandedSchedule === schedule.id ? null : schedule.id)}
|
||||
>
|
||||
{expandedSchedule === schedule.id ? '▼' : '▶'} Haltes ({schedule.departureTimes?.length || 0})
|
||||
</button>
|
||||
|
||||
{expandedSchedule === schedule.id && (
|
||||
<table style={{ width: '100%', fontSize: '0.8rem' }}>
|
||||
<tbody>
|
||||
{schedule.departureTimes.map(stop => (
|
||||
<tr key={stop.stopId}>
|
||||
<td><strong>{stop.order}.</strong></td>
|
||||
<td>{stop.stopName}</td>
|
||||
<td style={{ textAlign: 'right' }}>
|
||||
{formatTime(stop.departureTime)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backend Implementatie
|
||||
|
||||
### Helper Function: calculateDepartureTimes()
|
||||
|
||||
```javascript
|
||||
function calculateDepartureTimes(startTime, busLineId, mock) {
|
||||
const startDate = new Date(startTime);
|
||||
|
||||
// Get route stops for this bus line
|
||||
const routeStops = mock.routeStops
|
||||
.filter(rs => rs.busLineId === busLineId)
|
||||
.sort((a, b) => a.stopOrder - b.stopOrder);
|
||||
|
||||
return routeStops.map(rs => {
|
||||
const departureDate = new Date(startDate);
|
||||
departureDate.setMinutes(
|
||||
departureDate.getMinutes() + (rs.estimatedArrivalMinutes || 0)
|
||||
);
|
||||
|
||||
const stop = mock.stops.find(s => s.id === rs.stopId);
|
||||
return {
|
||||
order: rs.stopOrder,
|
||||
stopId: rs.stopId,
|
||||
stopName: stop?.name || 'Unknown Stop',
|
||||
estimatedArrivalMinutes: rs.estimatedArrivalMinutes || 0,
|
||||
departureTime: departureDate.toISOString(),
|
||||
};
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Mock Drivers Initialize
|
||||
|
||||
```javascript
|
||||
if (DEV_MOCK) {
|
||||
_mock.drivers = [
|
||||
{ id: 1, name: 'Jan Peterse', email: 'jan@transit.local', phone: '06-12345678', status: 'active' },
|
||||
{ id: 2, name: 'Maria Kuijpers', email: 'maria@transit.local', phone: '06-87654321', status: 'active' },
|
||||
{ id: 3, name: 'Robert Smits', email: 'robert@transit.local', phone: '06-55555555', status: 'active' },
|
||||
{ id: 4, name: 'Anja Voorn', email: 'anja@transit.local', phone: '06-44444444', status: 'inactive' },
|
||||
];
|
||||
_mock.nextDriverId = 5;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Production Database Support
|
||||
|
||||
Voor productie (niet DEV_MOCK) moeten deze kolommen bestaan in `transit.schedules`:
|
||||
|
||||
```sql
|
||||
ALTER TABLE transit.schedules ADD COLUMN IF NOT EXISTS weekdays JSONB;
|
||||
```
|
||||
|
||||
Queries gebruiken:
|
||||
```sql
|
||||
SELECT ... FROM transit.schedules WHERE weekdays::text LIKE '1' -- for Maandag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI/UX Verbeteringen
|
||||
|
||||
### Schedule Card Layout
|
||||
- **Bovenste rij**: Lijn nummer + Begin/Eindtijd
|
||||
- **Details**: Voertuignaam, nummerplaat, bestuurder, weekdagen
|
||||
- **Haltes knop**: Uitklapbare lijst met alle haltes en vertrektijden
|
||||
- **Delete knop**: Rood knop voor verwijderen
|
||||
|
||||
### Formulier Validatie
|
||||
- ✅ Lijn: verplicht
|
||||
- ✅ Voertuig: verplicht
|
||||
- ✅ Start-tijd: verplicht
|
||||
- ⚠️ Bestuurder: optioneel
|
||||
- ⚠️ Weekdagen: optioneel (eenmalig als niet ingesteld)
|
||||
- ❌ Eindtijd: niet meer nodig (automatisch berekend)
|
||||
|
||||
---
|
||||
|
||||
## Testing Scenario's
|
||||
|
||||
### Test 1: Eenmalige dienst
|
||||
1. Selecteer Lijn 101, Bus A5
|
||||
2. Selecteer 2026-05-08, 08:00
|
||||
3. Geen weekdagen selecteren
|
||||
4. Submit → Dienst aangemaakt met eindtijd berekend
|
||||
|
||||
### Test 2: Herhaalde dienst
|
||||
1. Selecteer Lijn 101, Bus A5
|
||||
2. Selecteer Ma, Di, Wo, Do, Vr
|
||||
3. Selecteer bestuurder
|
||||
4. Submit → Dienst gepland voor alle werkdagen
|
||||
|
||||
### Test 3: Haltes weergeven
|
||||
1. Klik op "Haltes" knop in schedule card
|
||||
2. Tabel opent met haltes en vertrektijden
|
||||
3. Klik opnieuw om in te klappen
|
||||
|
||||
---
|
||||
|
||||
## Bekende Beperkingen & TODOs
|
||||
|
||||
1. **Verkeersgegevens**: Huidige `estimatedArrivalMinutes` zijn statisch ingesteld
|
||||
- Toekomst: Integreer met verkeers-API voor dynamische berekening
|
||||
|
||||
2. **Tijdzones**: Alles in UTC
|
||||
- Toekomst: Voeg timezone support toe voor meerdere regio's
|
||||
|
||||
3. **Database Migrations**: `transit.schedules` moet `weekdays` kolom hebben
|
||||
- Status: Handmatig SQL nodig voor productie
|
||||
|
||||
4. **Bestuurders Toewijzing**: Geen conflict detectie
|
||||
- Toekomst: Waarschuwen als bestuurder al ingedeeld voor overlappende service
|
||||
|
||||
---
|
||||
|
||||
## Conclusie
|
||||
|
||||
Schedule Maker is nu een complete, production-ready planning tool met:
|
||||
- ✅ Automatische eindtijdberekening
|
||||
- ✅ Per-halte vertrektijden
|
||||
- ✅ Weekdag herhaling
|
||||
- ✅ Bestuurders selectie
|
||||
- ✅ Volle API integratie
|
||||
@@ -0,0 +1,199 @@
|
||||
# Project Plan
|
||||
|
||||
**Status**: Planning
|
||||
**Created**: 2026-09-20
|
||||
**Mode**: NEW
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Overview
|
||||
|
||||
**Goal**: Build a secure React + Vite operations console that monitors the existing XTransit APIs, summarizes service capabilities and errors, and provides a guarded live request tester. The project is designed so that every module is independently testable.
|
||||
|
||||
**App Type**: SPA + API
|
||||
|
||||
**API Login**: Yes
|
||||
|
||||
**Mode**: NEW
|
||||
|
||||
**Deployment Plan**: No deployment plan found
|
||||
|
||||
---
|
||||
|
||||
## 2. Monitoring Proxy API — backend
|
||||
|
||||
| Component | Technology |
|
||||
| ------------------- | -------------- |
|
||||
| **Language** | TypeScript |
|
||||
| **Runtime** | Node |
|
||||
| **Package Manager** | npm |
|
||||
| **Test Runner** | vitest |
|
||||
| **Mocking Library** | vi.mock |
|
||||
| **Test Command** | npm test |
|
||||
| **Orchestration** | docker-compose |
|
||||
|
||||
The proxy owns environment configuration, upstream health aggregation, the allowlisted endpoint catalog, authenticated request execution, error-log reads, response redaction, CORS, rate limiting, and normalized error responses. It must fail closed for unknown targets, unsafe methods, oversized bodies, and excessive timeouts.
|
||||
|
||||
## 3. Transit Monitor Dashboard — frontend
|
||||
|
||||
| Component | Technology |
|
||||
| ------------------- | ------------ |
|
||||
| **Language** | TypeScript |
|
||||
| **Framework** | React + Vite |
|
||||
| **Package Manager** | npm |
|
||||
| **Test Runner** | vitest |
|
||||
| **Mocking Library** | vi.mock |
|
||||
| **Test Command** | npm test |
|
||||
|
||||
The dashboard consumes only the proxy API, keeps polling and response-history state in memory, and exposes environment selection, service health, capabilities, errors, and the guarded tester as focused operator workflows.
|
||||
|
||||
## 4. Services Required
|
||||
|
||||
| Azure Service | Role in App | Environment Variable | Default Value (Local) | Classification |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------ | -------------------- | --------------------- | -------------- |
|
||||
| None | The console reads existing XTransit APIs and does not add persistence, queues, cache, or file storage. | — | — | Enhancement |
|
||||
|
||||
## 5. Prerequisites
|
||||
|
||||
### Run
|
||||
|
||||
| Tool | Service(s) | Installed | Version |
|
||||
| ---------- | ---------- | --------- | ----------------------------------- |
|
||||
| Node.js | \* | ✅ | v22.22.1 |
|
||||
| npm | \* | ✅ | 9.2.0 |
|
||||
| TypeScript | \* | ❓ | Verify through project dependencies |
|
||||
| Vitest | \* | ❓ | Verify through project dependencies |
|
||||
|
||||
### Debug
|
||||
|
||||
| Tool | Service(s) | Installed | Version |
|
||||
| ------------------------ | ----------------------------------------------- | --------- | ----------------- |
|
||||
| Docker | monitoring-proxy-api, transit-monitor-dashboard | ✅ | 29.1.3 |
|
||||
| Docker Compose | monitoring-proxy-api, transit-monitor-dashboard | ✅ | v5.5.0 |
|
||||
| VS Code Docker extension | monitoring-proxy-api, transit-monitor-dashboard | ❓ | Verify in VS Code |
|
||||
| VS Code ESLint extension | monitoring-proxy-api, transit-monitor-dashboard | ❓ | Verify in VS Code |
|
||||
|
||||
Double-check all tools marked ❓ before proceeding.
|
||||
|
||||
## 6. Design System & UI
|
||||
|
||||
**Component Library**: Fluent UI v9
|
||||
**Style Direction**: A calm, data-dense transit control room with a warm paper-white canvas, ink-black typography, cobalt actions, and signal colors reserved for service state. Use compact 4px control corners, crisp dividers, restrained elevation, and generous horizontal rhythm so operators can scan incidents without visual noise.
|
||||
**Typography**: Segoe UI Variable, Segoe UI, sans-serif
|
||||
|
||||
### Color Palette
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| --------- | --------- | --------------------------------------------------------------------------- |
|
||||
| `primary` | `#155EEF` | Operator actions, active dashboard navigation, and selected service filters |
|
||||
| `accent` | `#F59E0B` | Watch states, response-time highlights, and attention markers |
|
||||
| `surface` | `#F6F8FB` | Main console canvas and quiet page background |
|
||||
| `text` | `#172033` | Service names, route labels, and incident details |
|
||||
| `muted` | `#667085` | Polling timestamps, metadata, and supporting descriptions |
|
||||
| `border` | `#D9E0EA` | Console dividers, table rules, and input outlines |
|
||||
|
||||
### Pages
|
||||
|
||||
| Page | Route | Purpose | Layout |
|
||||
| --------------- | ------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------- |
|
||||
| Command Center | `/` | See the current health picture, polling freshness, and the most important service signals. | `header, nav, sidebar, main, hero, grid, table, actions` |
|
||||
| Service Catalog | `/services` | Inspect each upstream service's capabilities and representative route coverage. | `header, nav, sidebar, main, tabs, card-list, table, actions` |
|
||||
| Request Lab | `/requests` | Run a bounded, authenticated request against an allowlisted upstream route and inspect timing. | `header, nav, sidebar, main, form, split(form | table), action-bar` |
|
||||
| Incident Log | `/incidents` | Review normalized error-log activity and filter by service or severity. | `header, nav, sidebar, main, tabs, table, card-list` |
|
||||
|
||||
### Sample Content
|
||||
|
||||
Command Center — service health:
|
||||
| Service | Endpoint | Latency | Status |
|
||||
|---------|----------|---------|--------|
|
||||
| Transit API | `/health` | 184 ms | Operational |
|
||||
| Employee API | `/health` | 96 ms | Operational |
|
||||
| Error Log API | `/health` | 121 ms | Degraded |
|
||||
| Admin UI | `http://localhost:5173` | 42 ms | Operational |
|
||||
|
||||
Service Catalog — service capability:
|
||||
| Service | Capability | Route | Access |
|
||||
|---------|------------|-------|--------|
|
||||
| Transit API | Daily schedules | `/schedule/daily` | Authenticated |
|
||||
| Transit API | Route detail | `/routes/:routeId` | Authenticated |
|
||||
| Employee API | Create employee | `/createemployee` | Admin |
|
||||
| Error Log API | Read error log | `/error_log` | Admin |
|
||||
|
||||
Request Lab — request preset:
|
||||
| Service | Method | Path | Expected result |
|
||||
|---------|--------|------|-----------------|
|
||||
| Transit API | GET | `/schedules/overview` | Schedule summary |
|
||||
| Transit API | GET | `/admin/drivers` | Driver roster |
|
||||
| Employee API | GET | `/health` | Service health |
|
||||
|
||||
Incident Log — normalized incident:
|
||||
| Time | Service | Code | Message | Severity |
|
||||
|------|---------|------|---------|----------|
|
||||
| 09:42:18 | Error Log API | `BAD_REQUEST` | Missing route identifier | Warning |
|
||||
| 09:37:04 | Transit API | `FORBIDDEN` | Admin role required | Info |
|
||||
| 09:18:51 | Employee API | `INTERNAL_ERROR` | Employee lookup timed out | Critical |
|
||||
|
||||
## 7. Project Structure
|
||||
|
||||
```
|
||||
monitoring_dashboard/
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── vite.config.ts
|
||||
├── index.html
|
||||
├── Dockerfile
|
||||
├── docker-compose.yml
|
||||
├── src/
|
||||
│ ├── main.tsx
|
||||
│ ├── App.tsx
|
||||
│ ├── api/client.ts
|
||||
│ ├── api/types.ts
|
||||
│ ├── components/
|
||||
│ │ ├── AppShell.tsx
|
||||
│ │ ├── HealthSummary.tsx
|
||||
│ │ ├── ServiceCard.tsx
|
||||
│ │ ├── RequestForm.tsx
|
||||
│ │ └── IncidentTable.tsx
|
||||
│ ├── pages/
|
||||
│ │ ├── CommandCenter.tsx
|
||||
│ │ ├── ServiceCatalog.tsx
|
||||
│ │ ├── RequestLab.tsx
|
||||
│ │ └── IncidentLog.tsx
|
||||
│ └── styles/
|
||||
│ └── theme.css
|
||||
└── server/
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── Dockerfile
|
||||
└── src/
|
||||
├── index.ts
|
||||
├── config.ts
|
||||
├── routes/health.ts
|
||||
├── routes/catalog.ts
|
||||
├── routes/requests.ts
|
||||
├── routes/incidents.ts
|
||||
├── middleware/auth.ts
|
||||
├── middleware/rateLimit.ts
|
||||
├── services/upstreamClient.ts
|
||||
├── services/healthAggregator.ts
|
||||
└── services/redaction.ts
|
||||
```
|
||||
|
||||
## 8. Route Definitions
|
||||
|
||||
| # | Method | Path | Description | Request Body | Response Body | Status Codes |
|
||||
| --- | ------ | --------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------- |
|
||||
| 1 | GET | `/api/health` | Aggregate health for auth, employee, transit, error-log APIs, and admin UI. | — | `{ status, checkedAt, services: [{ id, status, latencyMs, endpoint }] }` | 200, 503 |
|
||||
| 2 | GET | `/api/catalog` | Return the allowlisted service and endpoint capability catalog. | — | `{ services: [{ id, label, capabilities: [{ method, path, access }] }] }` | 200, 401 |
|
||||
| 3 | GET | `/api/incidents` | Read normalized error activity from the error-log API with bounded filters. | — | `{ incidents: [{ id, occurredAt, service, code, message, severity }] }` | 200, 400, 401, 502 |
|
||||
| 4 | POST | `/api/requests/execute` | Execute one authenticated request against an allowlisted upstream route with safe limits. | `{ serviceId, method, path, query, body, timeoutMs }` | `{ requestId, status, durationMs, headers, data, redactions }` | 200, 400, 401, 403, 408, 429, 502 |
|
||||
| 5 | GET | `/api/requests/history` | Return in-memory request timing and status history for the current process. | — | `{ items: [{ requestId, serviceId, method, path, status, durationMs, executedAt }] }` | 200, 401 |
|
||||
| 6 | GET | `/api/config/environments` | List configured environment names without exposing secrets. | — | `{ environments: [{ id, label, active }] }` | 200, 401 |
|
||||
| 7 | POST | `/api/config/environments/select` | Select a configured upstream environment for the signed-in operator session. | `{ environmentId }` | `{ environmentId, label, selectedAt }` | 200, 400, 401, 404 |
|
||||
|
||||
## 9. Next Steps
|
||||
|
||||
1. Run **azure-project-scaffold** to execute this plan
|
||||
2. Run **azure-project-integrate** to wire the frontend to live data, smoke-test the backend, and create the migrations
|
||||
3. Run **azure-debug-plan** → **azure-debug-generate** for Docker emulators and VS Code debugging
|
||||
4. Run the **azure-deploy** agent when ready; it uses **azure-app-onboard** for architecture, cost estimation, IaC generation, provisioning, and health verification
|
||||
@@ -0,0 +1,29 @@
|
||||
# Deprecated: Legacy Bus Terminal
|
||||
|
||||
This Flutter application is retained as a legacy reference implementation while the transit client moves away from the Android-era setup toward a Windows XP-era compatibility target.
|
||||
|
||||
It is not part of the current monitoring or deployment path. Current service
|
||||
and dashboard documentation is maintained in
|
||||
[`../docs/PROJECT_GUIDE.md`](../docs/PROJECT_GUIDE.md) and
|
||||
[`../docs/MONITORING_UI.md`](../docs/MONITORING_UI.md).
|
||||
|
||||
## Status
|
||||
|
||||
- Deprecated: yes
|
||||
- Legacy platform target: Android-era Flutter app
|
||||
- Planned migration target: Windows XP-era desktop workflow
|
||||
- Kept in repo: for archival and reference during transition
|
||||
|
||||
## Notes
|
||||
|
||||
This project is not the active client for current operations. It remains available so the older UI, navigation logic, and service integration can be reviewed while the new target is prepared.
|
||||
|
||||
## Local development
|
||||
|
||||
```bash
|
||||
cd deprecated
|
||||
flutter pub get
|
||||
flutter run
|
||||
```
|
||||
|
||||
Use the appropriate device/desktop target when testing the legacy implementation.
|
||||
@@ -0,0 +1,386 @@
|
||||
# Transit API
|
||||
|
||||
Transit API voor het beheren van busroutes, navigatie en GPS tracking voor busbestuurders.
|
||||
|
||||
## Project Structuur
|
||||
|
||||
```
|
||||
transit_api/
|
||||
├── index.js # Main API endpoints
|
||||
├── middleware.js # JWT authentication middleware
|
||||
├── db.js # PostgreSQL connection
|
||||
├── schema.sql # Database schema setup
|
||||
├── package.json # Dependencies
|
||||
└── .env # Environment variables
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Dependencies installeren
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Database Schema opzetten
|
||||
|
||||
Voer het volgende uit in PostgreSQL:
|
||||
|
||||
```bash
|
||||
# Via psql command line
|
||||
psql -U your_user -d your_database -f schema.sql
|
||||
```
|
||||
|
||||
Of kopieer-plak de SQL queries rechtstreeks in pgAdmin.
|
||||
|
||||
### 3. Environment variabelen (.env)
|
||||
|
||||
```
|
||||
PG_HOST=localhost
|
||||
PG_PORT=5432
|
||||
PG_USER=your_user
|
||||
PG_PASS=your_password
|
||||
PG_DB=your_database
|
||||
JWT_SECRET=your_jwt_secret
|
||||
PORT=5001
|
||||
```
|
||||
|
||||
Note: `ADMIN_USER_CODES` has been moved to the `auth_api` service. Configure admin user codes in `auth_api/.env` as a comma-separated list.
|
||||
|
||||
### 4. API starten
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
API draait op `https://transit.xtransit.testinstance.nl`
|
||||
|
||||
The service group also includes the Employee API at
|
||||
`https://employees.xtransit.testinstance.nl` and the central monitoring
|
||||
dashboard. See [`../docs/MONITORING_UI.md`](../docs/MONITORING_UI.md) for health
|
||||
checks, error inspection, and the controlled request tester.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
Alle endpoints vereisen een `Authorization: Bearer {token}` header.
|
||||
|
||||
**GET** `/health`
|
||||
|
||||
- Controleert of de gedeployde transit API draait en de database bereikbaar is.
|
||||
- Geeft `200` met `{"status":"ok","database":"ok"}` bij succes.
|
||||
- Geeft `503` als de API wel draait maar de database niet bereikbaar is.
|
||||
|
||||
### Schedule
|
||||
|
||||
Schedules are weekly templates. Each row in `transit.schedules` represents one
|
||||
departure time for one bus line and one `day_of_week`:
|
||||
|
||||
- `1` to `5`: weekdays
|
||||
- `6`: Saturday
|
||||
- `0`: Sunday
|
||||
|
||||
Driver assignments are stored separately in `transit.shifts` with
|
||||
`(schedule_id, driver_id)`, where `driver_id` references `workers.users(id)`.
|
||||
The current `shifts` shape represents the active assignment. To retain different
|
||||
assignments for different calendar weeks, add a `week_start` (or assignment date
|
||||
range) column and include it in the unique key.
|
||||
|
||||
**GET** `/driver/schedules/daily?date=2026-09-18`
|
||||
|
||||
- Returns only weekly schedule templates assigned to the authenticated driver through `transit.shifts`.
|
||||
|
||||
**PATCH** `/driver/weekly-schedules/:scheduleId/status`
|
||||
|
||||
- Updates the status of an assigned weekly schedule.
|
||||
|
||||
**GET** `/admin/weekly-schedules`
|
||||
|
||||
- Lists weekly templates and their current driver assignments.
|
||||
|
||||
**GET** `/admin/shift-drivers`
|
||||
|
||||
- Lists drivers from `workers.users` for shift assignment.
|
||||
|
||||
**POST** `/admin/weekly-schedules`
|
||||
|
||||
- Creates one template. Body: `{ "busLineId": 1, "dayOfWeek": 1, "startTime": "08:00", "endTime": "09:00", "driverId": 12 }`.
|
||||
|
||||
**POST** `/admin/weekly-schedules/bulk`
|
||||
|
||||
- Creates multiple departures in one transaction. The API derives each end time
|
||||
from the selected bus line duration. Body: `{ "busLineId": 1, "dayOfWeeks": [1,2,3,4,5], "startTimes": ["06:00", "06:30", "07:00"], "driverId": 12 }`.
|
||||
|
||||
**PUT** `/admin/weekly-schedules/:scheduleId/shift`
|
||||
|
||||
- Replaces the driver assignment. Pass `{ "driverId": 12 }` or `{ "driverId": null }`.
|
||||
|
||||
The legacy `/admin/schedules` and `/schedule/daily` endpoints remain for older
|
||||
clients, but new clients must use the weekly schedule endpoints above.
|
||||
|
||||
**GET** `/schedule/daily?date=2024-05-05`
|
||||
|
||||
- Ophalen van dagplanning voor chauffeur
|
||||
- Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"date": "2024-05-05",
|
||||
"routes": [
|
||||
{
|
||||
"id": 1,
|
||||
"startTime": "2024-05-05T08:00:00Z",
|
||||
"status": "scheduled",
|
||||
"busLine": {
|
||||
"lineNumber": 1,
|
||||
"startStop": "Central Station",
|
||||
"endStop": "Airport"
|
||||
},
|
||||
"busType": {
|
||||
"name": "Standard Bus",
|
||||
"seatCapacity": 50,
|
||||
"licensePlate": "BUS-001"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**GET** `/routes/:routeId`
|
||||
|
||||
- Details van een specifieke route
|
||||
- Response: `{ "route": {...} }`
|
||||
|
||||
### Public Schedule Overview
|
||||
|
||||
**GET** `/schedules/overview?date=2026-05-06&lineId=1`
|
||||
|
||||
- Haalt een datum-gebonden overzicht op van geplande diensten
|
||||
- Weekly templates are selected by `day_of_week` and driver assignments by `shifts`
|
||||
- Incidentele diensten worden alleen meegenomen op hun exacte datum
|
||||
- Filters: `driverId`/`chauffeurId`, `stopId`/`busStopId`, `lineId`, `status`
|
||||
- Response: `{ "date": "2026-05-06", "summary": {...}, "schedules": [...] }`
|
||||
|
||||
De legacy endpoint **GET** `/schedules` blijft beschikbaar voor bestaande clients.
|
||||
|
||||
Voorbeeld:
|
||||
|
||||
```bash
|
||||
curl "https://transit.xtransit.testinstance.nl/schedules/overview?date=2026-05-06&chauffeurId=12&busStopId=3"
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
**POST** `/navigation/route`
|
||||
|
||||
- Opslaan van berekende route van OSRM
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"routeId": 1,
|
||||
"startLat": 52.5200,
|
||||
"startLon": 13.4050,
|
||||
"endLat": 52.5300,
|
||||
"endLon": 13.4150,
|
||||
"totalDistance": 15000,
|
||||
"totalDuration": 900,
|
||||
"geojson": {
|
||||
"type": "LineString",
|
||||
"coordinates": [[13.4050, 52.5200], ...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GET** `/bus-lines/:busLineId/stops`
|
||||
|
||||
- Alle stops van een buslijn (voor navigatie waypoints)
|
||||
- Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"stops": [
|
||||
{
|
||||
"id": 1,
|
||||
"order": 1,
|
||||
"name": "Central Station",
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GPS Tracking
|
||||
|
||||
**POST** `/gps/track`
|
||||
|
||||
- Real-time positie opslaan
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"routeId": 1,
|
||||
"latitude": 52.521,
|
||||
"longitude": 13.406,
|
||||
"speed": 45.5,
|
||||
"heading": 180,
|
||||
"accuracy": 5.0
|
||||
}
|
||||
```
|
||||
|
||||
**GET** `/gps/route/:routeId`
|
||||
|
||||
- Alle opgeslagen positie punten van een route
|
||||
- Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"latitude": 52.521,
|
||||
"longitude": 13.406,
|
||||
"speed": 45.5,
|
||||
"heading": 180,
|
||||
"recordedAt": "2024-05-05T08:15:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Route Status
|
||||
|
||||
**PATCH** `/routes/:routeId/status`
|
||||
|
||||
- Update route status
|
||||
- Body: `{ "status": "in_progress" }`
|
||||
- Valid statuses: `scheduled`, `in_progress`, `completed`, `cancelled`
|
||||
|
||||
### Admin
|
||||
|
||||
Alle admin-endpoints vereisen naast een geldig JWT-token ook dat je `userCode` voorkomt in `ADMIN_USER_CODES`.
|
||||
|
||||
**POST** `/admin/stops`
|
||||
|
||||
- Maak een herbruikbare stop aan
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Central Station",
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405
|
||||
}
|
||||
```
|
||||
|
||||
**POST** `/admin/bus-lines/:busLineId/stops`
|
||||
|
||||
- Koppel een bestaande stop aan een buslijn
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"stopId": 1,
|
||||
"stopOrder": 1,
|
||||
"estimatedArrivalMinutes": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
### bus_types
|
||||
|
||||
- `id` - Primary key
|
||||
- `name` - Bus type name (Standard Bus, etc.)
|
||||
- `seat_capacity` - Number of seats
|
||||
- `license_plate` - Unique license plate
|
||||
|
||||
### bus_lines
|
||||
|
||||
- `id` - Primary key
|
||||
- `line_number` - Unique line number (1, 5, 12, etc.)
|
||||
- `start_stop` - Start stop name
|
||||
- `end_stop` - End stop name
|
||||
- `estimated_duration_minutes` - Expected route duration
|
||||
|
||||
### stops
|
||||
|
||||
- `id` - Primary key
|
||||
- `name` - Stop name
|
||||
- `latitude`, `longitude` - Stop location
|
||||
|
||||
### route_stops
|
||||
|
||||
- `id` - Primary key
|
||||
- `bus_line_id` - Which bus line the stop belongs to
|
||||
- `stop_id` - Reusable stop reference
|
||||
- `stop_order` - Stop sequence on that bus line
|
||||
- `estimated_arrival_minutes` - Optional ETA per stop
|
||||
|
||||
### routes
|
||||
|
||||
- `id` - Primary key
|
||||
- `user_id` - Chauffeur (references workers.users)
|
||||
- `bus_line_id` - Which line (references bus_lines)
|
||||
- `bus_type_id` - Which bus (references bus_types)
|
||||
- `start_time` - Scheduled start
|
||||
- `status` - scheduled/in_progress/completed/cancelled
|
||||
|
||||
### navigation_routes
|
||||
|
||||
- `id` - Primary key
|
||||
- `route_id` - Link to route (unique)
|
||||
- `polyline_geojson` - GeoJSON LineString van de route
|
||||
- `total_distance_meters` - Route distance
|
||||
- `total_duration_seconds` - Estimated duration
|
||||
|
||||
### gps_tracking
|
||||
|
||||
- `id` - Primary key
|
||||
- `route_id` - Which route
|
||||
- `latitude`, `longitude` - Current position
|
||||
- `speed_kmh` - Current speed
|
||||
- `recorded_at` - Timestamp
|
||||
|
||||
## Integration met Flutter App
|
||||
|
||||
```dart
|
||||
// In schedule_service.dart
|
||||
|
||||
// Save navigation route
|
||||
await scheduleService.saveNavigationRoute(
|
||||
routeId: 1,
|
||||
navRoute: navigationRoute,
|
||||
);
|
||||
|
||||
// Track GPS
|
||||
await scheduleService.trackGPS(
|
||||
routeId: 1,
|
||||
currentPos: navigationPoint,
|
||||
speed: 45.5,
|
||||
heading: 180,
|
||||
);
|
||||
|
||||
// Update route status
|
||||
await scheduleService.updateRouteStatus(1, 'in_progress');
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Alle endpoints retourneren error responses:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "error_code",
|
||||
"details": "More information"
|
||||
}
|
||||
```
|
||||
|
||||
Common errors:
|
||||
|
||||
- `missing_token` - No Authorization header
|
||||
- `invalid_token` - Token verification failed
|
||||
- `missing_required_fields` - Required data missing
|
||||
- `invalid_status` - Invalid status value
|
||||
- `route_not_found` - Route not found
|
||||
- `unauthorized` - User doesn't own this resource
|
||||
@@ -0,0 +1,50 @@
|
||||
# Transit Driver XP
|
||||
|
||||
Native Win32 driver client targeting Windows XP-era systems.
|
||||
|
||||
Project-wide setup and service documentation is maintained in
|
||||
[`../docs/PROJECT_GUIDE.md`](../docs/PROJECT_GUIDE.md). The operational
|
||||
monitoring dashboard is documented in
|
||||
[`../docs/MONITORING_UI.md`](../docs/MONITORING_UI.md).
|
||||
|
||||
For Windows XP compatibility, the client temporarily uses the LAN services:
|
||||
|
||||
- Login: `http://192.168.68.66:5000/login`
|
||||
- Assigned schedules: `http://192.168.68.66:5001/driver/schedules/daily`
|
||||
- Route stops: `http://192.168.68.66:5001/bus-lines/:busLineId/stops`
|
||||
|
||||
This HTTP fallback avoids the TLS 1.2/certificate limitations of Windows XP.
|
||||
|
||||
Schedules are assigned through `transit.shifts`; the client does not expect a
|
||||
`driver_id`, `bus_id`, or `weekdays` column on `transit.schedules`.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
make clean && make
|
||||
```
|
||||
|
||||
## Distribution
|
||||
|
||||
Build the installer with:
|
||||
|
||||
```bash
|
||||
makensis installer.nsi
|
||||
```
|
||||
|
||||
Distribute `TransitDriverXPSetup.exe`. It detects an existing installation,
|
||||
stops the previous client, and replaces it in the same directory.
|
||||
|
||||
## Login diagnostics
|
||||
|
||||
If the app shows `Driver service unreachable`, open `driver_xp.log` in the same
|
||||
folder as the installed `driver_xp.exe` and inspect the latest entries. The log
|
||||
records the failing stage and WinHTTP or HTTP status code, but never writes the
|
||||
password or JWT token.
|
||||
|
||||
Common codes:
|
||||
|
||||
- `12007`: hostname could not be resolved (DNS)
|
||||
- `12029`: connection to the server failed
|
||||
- `12175`: HTTPS certificate or TLS validation failed
|
||||
- `401` or `403`: the server responded, but authentication was rejected
|
||||
Reference in New Issue
Block a user