diff --git a/monitoring_ui/public/docs/auth_api/README.md b/monitoring_ui/public/docs/auth_api/README.md new file mode 100644 index 0000000..5607f01 --- /dev/null +++ b/monitoring_ui/public/docs/auth_api/README.md @@ -0,0 +1,47 @@ +# Auth API + +Authentication service for XTransit. Handles login, JWT token generation, and user verification. + +## Setup + +### Environment Variables + +```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=5000 +ADMIN_USER_CODES=1234,5678 +DEV_BYPASS=0 +ERROR_LOG_API_URL=https://error.xtransit.testinstance.nl/error_log +``` + +### Start API + +```bash +npm start +``` + +Runs at `https://auth.xtransit.testinstance.nl` + +## API Endpoints + +**POST** `/login` +- Body: `{ "userCode": 1234, "password": "secret" }` +- Returns: `{ "token": "jwt...", "user": { "id": 1, "userCode": 1234, "job": "driver", "isAdmin": false } }` + +**GET** `/me` +- Requires: `Authorization: Bearer ` +- Returns: `{ "user": { "userId": 1, "userCode": 1234, "isAdmin": false } }` + +**GET** `/health` +- Returns: `{ "status": "ok", "service": "auth_api" }` + +## Database + +Uses `workers.users` table with columns: `id`, `usercode`, `password` (bcrypt), `job` + +Admin status is determined by `ADMIN_USER_CODES` env variable (comma-separated user codes). \ No newline at end of file diff --git a/monitoring_ui/public/docs/employee_api/README.md b/monitoring_ui/public/docs/employee_api/README.md new file mode 100644 index 0000000..f49f3d4 --- /dev/null +++ b/monitoring_ui/public/docs/employee_api/README.md @@ -0,0 +1,39 @@ +# Employee API + +Employee management service for XTransit. Handles employee onboarding and records. + +## Setup + +### Environment Variables + +```env +PG_HOST=localhost +PG_PORT=5432 +PG_USER=your_user +PG_PASS=your_password +PG_DB=your_database +PORT=4000 +ERROR_LOG_API_URL=https://error.xtransit.testinstance.nl/error_log +``` + +### Start API + +```bash +npm start +``` + +Runs at `https://employees.xtransit.testinstance.nl` + +## API Endpoints + +**POST** `/createemployee` +- Body: `{ "firstname": "John", "lastname": "Doe", "job": "driver", "password": "secret" }` +- Creates employee in `workers.employees` and user in `workers.users` +- Returns: `{ "employee": "John", "code": "1234" }` + +**GET** `/health` +- Returns: `{ "endpoint": "reachable", "database": "ok" }` or 503 if DB down + +## Database + +Uses `workers.employees` (id, firstname, lastname, job) and `workers.users` (id, employee, password, usercode) \ No newline at end of file diff --git a/monitoring_ui/public/docs/error_log_api/README.md b/monitoring_ui/public/docs/error_log_api/README.md new file mode 100644 index 0000000..0184795 --- /dev/null +++ b/monitoring_ui/public/docs/error_log_api/README.md @@ -0,0 +1,45 @@ +# Error Log API + +Centralized error logging service for XTransit. Collects errors from all services. + +## Setup + +### Environment Variables + +```env +PG_HOST=localhost +PG_PORT=5432 +PG_USER=your_user +PG_PASS=your_password +PG_DB=your_database +PORT=5003 +JWT_SECRET=your_jwt_secret +``` + +### Start API + +```bash +npm start +``` + +Runs at `https://error.xtransit.testinstance.nl` + +## API Endpoints + +**POST** `/error_log` +- Body: `{ "service": "transit_api", "partofservice": "/schedule/daily", "error": "DB connection failed" }` +- Logs error to database +- Returns: `{ "ok": true }` + +**GET** `/error_log?limit=100&service=transit_api` +- Requires: `Authorization: Bearer ` +- Returns: `{ "errors": [...] }` + +**GET** `/health` +- Returns: `{ "status": "ok", "service": "error_log_api", "database": "ok" }` or 503 + +## Database + +Uses `data.errors` table (id, date, service, partofservice, error) + +Admin access controlled via JWT `isAdmin` claim from auth_api. \ No newline at end of file diff --git a/monitoring_ui/public/docs/transit_api/README.md b/monitoring_ui/public/docs/transit_api/README.md new file mode 100644 index 0000000..8c3b75e --- /dev/null +++ b/monitoring_ui/public/docs/transit_api/README.md @@ -0,0 +1,386 @@ +# Transit API + +Transit API for managing bus routes, navigation, and GPS tracking for bus drivers. + +## Project Structure + +``` +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. Install Dependencies + +```bash +npm install +``` + +### 2. Set Up Database Schema + +Execute the following in PostgreSQL: + +```bash +# Via psql command line +psql -U your_user -d your_database -f schema.sql +``` + +Or copy-paste the SQL queries directly into pgAdmin. + +### 3. Environment Variables (.env) + +```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. Start API + +```bash +npm start +``` + +The API runs at `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 [`../MONITORING_UI.md`](../MONITORING_UI.md) for health +checks, error inspection, and the controlled request tester. + +## API Endpoints + +All endpoints require an `Authorization: Bearer {token}` header. + +**GET** `/health` + +- Checks whether the deployed transit API is running and the database is reachable. +- Returns `200` with `{"status":"ok","database":"ok"}` on success. +- Returns `503` if the API is running but the database is unreachable. + +### 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` + +- Retrieve daily schedule for driver +- 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 of a specific route +- Response: `{ "route": {...} }` + +### Public Schedule Overview + +**GET** `/schedules/overview?date=2026-05-06&lineId=1` + +- Fetches a date-based overview of scheduled services +- Weekly templates are selected by `day_of_week` and driver assignments by `shifts` +- One-off / incidental services are only included on their exact date +- Filters: `driverId`/`chauffeurId`, `stopId`/`busStopId`, `lineId`, `status` +- Response: `{ "date": "2026-05-06", "summary": {...}, "schedules": [...] }` + +The legacy endpoint **GET** `/schedules` remains available for existing clients. + +Example: + +```bash +curl "https://transit.xtransit.testinstance.nl/schedules/overview?date=2026-05-06&chauffeurId=12&busStopId=3" +``` + +### Navigation + +**POST** `/navigation/route` + +- Save calculated route from 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` + +- All stops of a bus line (for navigation waypoints) +- Response: + +```json +{ + "stops": [ + { + "id": 1, + "order": 1, + "name": "Central Station", + "latitude": 52.52, + "longitude": 13.405 + } + ] +} +``` + +### GPS Tracking + +**POST** `/gps/track` + +- Save real-time position +- Body: + +```json +{ + "routeId": 1, + "latitude": 52.521, + "longitude": 13.406, + "speed": 45.5, + "heading": 180, + "accuracy": 5.0 +} +``` + +**GET** `/gps/route/:routeId` + +- All recorded position points of a 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 + +All admin endpoints require, in addition to a valid JWT token, that your `userCode` is present in `ADMIN_USER_CODES`. + +**POST** `/admin/stops` + +- Create a reusable stop +- Body: + +```json +{ + "name": "Central Station", + "latitude": 52.52, + "longitude": 13.405 +} +``` + +**POST** `/admin/bus-lines/:busLineId/stops` + +- Link an existing stop to a bus line +- 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` - Driver (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 of the 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 with 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 + +All endpoints return 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 diff --git a/monitoring_ui/src/App.jsx b/monitoring_ui/src/App.jsx index 9bc2b3e..da7118b 100644 --- a/monitoring_ui/src/App.jsx +++ b/monitoring_ui/src/App.jsx @@ -17,7 +17,7 @@ const serviceMeta = { color: "amber", data: "Login, JWT sessions, current user profile", routes: ["/login", "/me", "/health"], - docs: "https://github.com/your-org/auth_api/blob/main/README.md", + docs: "/docs/auth_api/README.md", }, employee: { label: "Employee API", @@ -25,7 +25,7 @@ const serviceMeta = { color: "teal", data: "Employee onboarding and employee records", routes: ["/health", "/createemployee"], - docs: "https://github.com/your-org/employee_api/blob/main/README.md", + docs: "/docs/employee_api/README.md", }, transit: { label: "Transit API", @@ -38,7 +38,7 @@ const serviceMeta = { "/schedule/daily?date=YYYY-MM-DD", "/admin/stops", ], - docs: "https://github.com/your-org/transit_api/blob/main/README.md", + docs: "/docs/transit_api/README.md", }, errors: { label: "Error Log API", @@ -46,7 +46,7 @@ const serviceMeta = { color: "coral", data: "Centralized bad requests and service errors", routes: ["/health", "/error_log?limit=100"], - docs: "https://github.com/your-org/error_log_api/blob/main/README.md", + docs: "/docs/error_log_api/README.md", }, };