6.2 KiB
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:
ADMIN_USER_CODES=42 DEV_MOCK=1 JWT_SECRET=devsecret npm --prefix ./transit_api start
Database Schema (Production)
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
- Admin Dashboard: ScheduleMaker appears at the bottom of Admin Control Center
- Public API: Available via public
/schedulesendpoints without authentication - Flutter App: TimetableViewer can be embedded or used as reference for mobile implementation
- Frontend Flexibility: TimetableViewer component is reusable for any public-facing website
Example Usage
Create a schedule (Admin)
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)
curl https://transit.xtransit.testinstance.nl/schedules?date=$(date +%Y-%m-%d)
Get schedules for specific line (Public)
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