Transit Project
This repository contains a suite of Node.js microservices, a modern React administration console, an operational monitoring dashboard, and a legacy client retained for compatibility reference.
auth_api— Authentication and token issuance (default port 5000)employee_api— Employee onboarding and management (default port 4000)transit_api— Routes, schedules, fleet, GPS, and transit administration (default port 5001)error_log_api— Centralized error logging and viewer (default port 5003)
The error API is available at https://error.xtransit.testinstance.nl.
admin_ui— React + Vite administration interface
The admin panel is available at https://admin.xtransit.testinstance.nl.
monitoring_ui— React + Vite service monitoring dashboard
The monitoring dashboard is available at host port 5175 (https://monitor.xtransit.testinstance.nl or local port 5173).
windows_xp_driver_ui/— Native Win32 driver client targeting Windows XP-era systemsdeprecated/— Legacy Flutter bus terminal, retained for reference while moving the client to a Windows XP-era build path
The repository also includes CI workflows that build Docker images and push them to GitHub Container Registry (GHCR).
See monitoring_ui/docs/DOMAINS_README.md for the central list of all public domains and their functions. The consolidated documentation hub is available in monitoring_ui/docs/README.md.
Important: this README does not contain any passwords or other sensitive information. Always store secrets outside of version control (environment variables, secret managers, Portainer secrets, etc.).
Security & Private Files
⚠️ Important: This repository excludes private documentation and setup instructions from Git and Docker builds. See monitoring_ui/docs/SECURITY_PRIVATE_FILES.md for details on:
- What files are kept private and why
- How
.gitignoreand.dockerignoreprotect sensitive information - Best practices for handling deployment documentation
- Guidelines for adding new private files
Private files are excluded (not in git/docker):
GETTING_STARTED.md- Internal setup guideADMIN_DEPLOYMENT_SUMMARY.md- Deployment statusCI_CD_PORTAINER_GUIDE.md- Infrastructure docsDEPLOYMENT.md- Deployment procedures- Custom instruction files (
.instructions.md, etc.)
Table of Contents / Directory Overview
auth_api/— Source code for the authentication serviceemployee_api/— Source code for the employee servicetransit_api/— Source code for the transit serviceerror_log_api/— Source code for centralized error collectionadmin_ui/— Source code for React admin panelmonitoring_ui/— Source code for React monitoring dashboard and documentation hubwindows_xp_driver_ui/— Native driver interfacedeprecated/— Legacy client reference.github/workflows/docker-build.yml— CI: build and push images to GHCRdocker-compose.yml— Compose file that pulls images from GHCR or builds locally and connects to an external PostgreSQL database.env.example— Example environment variablesmonitoring_ui/docs/— Consolidated documentation hub
Prerequisites
- Git
- Docker (20.10+)
- Docker Compose (v2+ or
docker compose) - (Optional) A remote environment running Portainer
- (Optional) A GitHub account with permissions to publish images to GHCR
Security — Important Reminders
- Never commit secrets into git. Use a local
.envfile (kept in.gitignore) or a secret manager. - JWT secrets, database passwords, and other credentials must be supplied via environment variables or Portainer secrets.
Environment Variables (Example)
Your docker-compose.yml expects environment variables defining the database connection and JWT secret.
Create a local .env file in the project root (DO NOT commit). Use these variables as a guide:
# Database (external Postgres)
POSTGRES_HOST=your.db.host.or.ip
POSTGRES_PORT=5432
POSTGRES_DB=transit_db
# Per-service DB credentials (optional: you can also use a single DB user per DB)
POSTGRES_USER_AUTH=auth_user
POSTGRES_PASSWORD_AUTH=strong_password_auth
POSTGRES_USER_EMPLOYEE=employee_user
POSTGRES_PASSWORD_EMPLOYEE=strong_password_employee
POSTGRES_USER_TRANSIT=transit_user
POSTGRES_PASSWORD_TRANSIT=strong_password_transit
POSTGRES_USER_ERROR_LOG=error_logger
POSTGRES_PASSWORD_ERROR_LOG=strong_password_error_log
# JWT secret for services using JWT
JWT_SECRET=super_secret_jwt_key_here
# Optional: central error log endpoint for clients/services
ERROR_LOG_API_URL=https://error.xtransit.testinstance.nl/error_log
Note: The exact variables are read by docker-compose.yml. Adjust names and values according to your environment.
Local Development (Without Docker)
- Ensure you have a running PostgreSQL instance (local or remote).
- Copy a
.envfile for each API or export the required environment variables.
Example: running auth_api locally:
cd auth_api
# Install dependencies
npm install
# Export env vars (example):
export DB_HOST=your.db.host
export DB_PORT=5432
export DB_NAME=transit_db
export DB_USER=auth_user
export DB_PASSWORD=...
export JWT_SECRET=...
npm start
Repeat for employee_api, transit_api, and error_log_api with the appropriate env keys and ports.
Tip: During development, you can use a single Postgres instance and configure schemas and roles.
Docker / Portainer — Deployment (With External Postgres)
This repository includes a docker-compose.yml file that pulls images from GHCR. The compose setup is configured to use an external Postgres instance.
Before starting:
- Ensure your
.envfile with database credentials andJWT_SECRETis prepared on the server. - Ensure the host running compose has network connectivity to the Postgres host.
Deployment steps (server / Portainer host):
# 1. Place .env on the server (NOT in git)
scp .env user@server:/path/to/project/.env
# or create it directly on the server
# 2. Login to GHCR (to pull private images)
# Username = your GitHub username
# Password = PAT with 'write:packages'/'read:packages' scopes or your GITHUB_TOKEN
docker login ghcr.io
# 3. Start stack
docker-compose --env-file .env up -d
# or with compose V2:
docker compose --env-file .env up -d
If using Portainer, you can also paste docker-compose.yml as a "Stack" in the Portainer UI and deploy via the UI. Add environment variables in Portainer or reference a server-side .env.
Note on depends_on in docker-compose.yml: because you are using an external DB, compose configs sometimes reference a non-existent db service. You can safely remove or ignore those depends_on rules, as long as your database is available before the services attempt to connect.
GitHub Actions & Container Registry (CI)
The project includes a CI workflow in .github/workflows/docker-build.yml (and .gitea/workflows/docker-build.yml) that executes the following steps on push to main/dev:
- Checkout repository
- Build Docker images for each API (using BuildKit / Buildx)
- Login to the Container Registry (GHCR) and push images
- Generate tags (
latest, branch/sha, semver if present)
To use GHCR on your server:
- Create a Personal Access Token (PAT) with
read:packages(andwrite:packagesif you also wish to push). - Login on the server:
docker login ghcr.io(use PAT as password).
Example image name:
ghcr.io/<github-username>/<repo>/auth_api:latest
Health Checks, Endpoints, and Debugging
Useful endpoints (example):
GET /health— (available inemployee_api,transit_api,error_log_api) checks reachabilityPOST /login— (auth_api) authenticationGET /schedule/daily?date=YYYY-MM-DD— (transit_api) requires authentication
Viewing logs:
# Logs from a service
docker-compose logs -f auth_api
# Or via container ID
docker logs -f auth_api
Troubleshooting DB connection:
- Verify network connectivity to
POSTGRES_HOST - Check users and permissions in Postgres
- Ensure the expected schema (such as
workersortransit) exists if queries expect it
Common Tasks & Commands
# Build & run (pull images from GHCR)
docker-compose --env-file .env up -d
# Pull latest images
docker-compose pull
# Recreate containers
docker-compose up -d --force-recreate
# Stop and remove containers
docker-compose down
# Login to GHCR
docker login ghcr.io
Migrations & Database Schema
Database schemas and migrations are maintained separately. Ensure you:
- Create the necessary schemas (
workers,transit,data, etc.) - Configure users and privileges for the respective services
Error Logging Schema
For centralized error logging, create schema data and table data.errors:
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 a dedicated user with minimal privileges, e.g. error_logger:
CREATE ROLE error_logger LOGIN PASSWORD 'strong_password_error_log';
GRANT USAGE ON SCHEMA data TO error_logger;
GRANT INSERT, SELECT ON data.errors TO error_logger;
If you do not have a database yet, you can run a local PostgreSQL container for development:
docker run --name transit-db -e POSTGRES_DB=transit_db -e POSTGRES_USER=transit_user -e POSTGRES_PASSWORD=pass -p 5432:5432 -d postgres:15-alpine
For production / Portainer setups, follow your infrastructure policy and use a managed database or secured host.
Deployment Tips
- Use distinct database users per service with minimal privileges
- Use secrets in Portainer, Docker swarm, or Kubernetes in production
- Use a reverse proxy (Nginx, Traefik) for TLS/HTTPS
- Set up log aggregation and monitoring (Prometheus/Grafana, ELK, etc.)
Contributing
- Create feature branches and open pull requests
- Push to
devormaindepending on your branching policy - CI will automatically build and push images for
main/dev
Where to Find Everything
- API code:
auth_api/,employee_api/,transit_api/,error_log_api/ - Frontend UI:
admin_ui/,monitoring_ui/ - Documentation hub:
monitoring_ui/docs/ - CI workflows:
.github/workflows/docker-build.yml,.gitea/workflows/docker-build.yml
Admin Control Center
The project includes a modern React admin dashboard for fleet and schedule management.
Features
- Fleet Management: Create and manage buses with seat capacity and license plates
- Transit Lines: Define bus routes with start/end stops and duration
- Route Management: Link stops to bus lines with drag-and-drop reordering
- Schedule Maker: Create schedules by assigning vehicles and crew to bus lines with time slots
- Timetable View: 24-hour timetable showing scheduled services
- Delete Operations: Remove stops, lines, and schedules with confirmation modals
Admin UI Location
admin_ui/
├── src/
│ ├── components/
│ │ ├── StopsManager.jsx # Create and manage transit stops
│ │ ├── BusLinesManager.jsx # Manage bus lines and routes
│ │ ├── FleetManager.jsx # Manage fleet vehicles
│ │ ├── LinkStop.jsx # Drag-drop route stop assignment
│ │ ├── ScheduleMaker.jsx # Create and manage schedules
│ │ ├── TimetableViewer.jsx # Public timetable (reusable)
│ │ └── Login.jsx # Admin authentication
│ ├── App.jsx # Main app component
│ ├── api.js # API client with runtime config
│ └── styles.css # Responsive UI styling
├── docker-entrypoint.sh # Runtime env config
└── Dockerfile # Multi-stage build
Building the Admin UI
cd admin_ui
npm install
npm run build # Production build
npm run dev # Development (Vite)
Docker Deployment
The admin UI is included in docker-compose.yml as service admin_ui on port 5174.
docker-compose up admin_ui
# Access at http://localhost:5174
Public Schedule API
The Transit API exposes public (unauthenticated) schedule endpoints:
Endpoints:
GET /schedules?date=YYYY-MM-DD&lineId=ID— Get schedules for a date/lineGET /schedules/:scheduleId— Get schedule detailsGET /schedules/:scheduleId/stops— Get stops on a schedule's line
Example:
curl https://transit.xtransit.testinstance.nl/schedules?date=2026-05-06
TimetableViewer Component:
import TimetableViewer from "./components/TimetableViewer";
<TimetableViewer apiBaseUrl="http://api.transit.local:5001" />;
Schedule Maker Documentation
See monitoring_ui/docs/admin_ui/SCHEDULE_API.md for detailed API documentation, usage examples, and UI features.
Authentication
Admin dashboard uses simple JWT-based authentication:
- Login with user code (e.g.,
42) - Receive JWT token from
auth_api - Use token for admin operations (
/admin/*endpoints)
Admin authorization is controlled by ADMIN_USER_CODES environment variable configured in the auth_api service:
# Set admin user codes for the auth service (comma-separated)
ADMIN_USER_CODES=42,101,205
Development vs Production
Development Mode
Use DEV_MOCK=1 to work without a database (in-memory mock storage):
# For local development set admin codes on the auth_api and start services
ADMIN_USER_CODES=42 DEV_MOCK=1 JWT_SECRET=devsecret npm --prefix ./auth_api start
Production Mode
Set up real PostgreSQL database and provide credentials via environment variables.