OSS/BSS Field Dispatch — Architecture
Overview
Field service dispatch & scheduling PWA integrated with ERPNext (Frappe) on PostgreSQL.
Manages technicians, work orders, route optimization, and team scheduling.
Stack
| Layer |
Technology |
Notes |
| Frontend |
Vue 3 + Quasar (PWA) |
<script setup>, Composition API, custom dark UI |
| State |
Pinia |
Single dispatch store |
| Backend |
ERPNext / Frappe |
REST API, Server Scripts, Doctypes |
| Database |
PostgreSQL |
Native (no MariaDB), pg_trgm + unaccent for address search |
| Maps |
Mapbox GL JS |
Route directions, optimization API, dark style |
| Deploy |
Docker |
Frappe containers, PWA served as static assets |
| Git |
Gitea |
git.targo.ca/louis/OSS-BSS-Field-Dispatch |
Directory Structure
src/
├── api/ # ERPNext REST calls
│ ├── dispatch.js # Jobs, techs, tags CRUD + createTag
│ ├── auth.js # Login, CSRF token
│ ├── service-request.js # Open service requests
│ ├── booking.js # Booking API
│ ├── contractor.js # Contractor API
│ └── settings.js # Dispatch Settings (single doctype)
│
├── components/ # Reusable UI widgets
│ └── TagInput.vue # Auto-suggest tag input with inline creation
│
├── composables/ # Shared logic (no UI)
│ ├── useHelpers.js # Pure utils: dates, formatting, icons, colors
│ ├── useScheduler.js # Timeline algorithm: pinned anchors + auto-flow
│ ├── useMap.js # Mapbox: init, markers, routes, geo-fix, drag
│ ├── useBottomPanel.js # Unassigned list: grouping, multi-select, criteria
│ └── useUndo.js # Undo stack (30 actions max)
│
├── modules/
│ └── dispatch/
│ └── components/ # Dispatch-specific components
│ ├── TimelineRow.vue # Single tech row with job blocks
│ ├── BottomPanel.vue # Unassigned jobs table (date-grouped)
│ ├── JobEditModal.vue # Edit job modal (double-click)
│ └── WoCreateModal.vue # Create work order modal
│
├── pages/ # Route-level pages
│ ├── DispatchV2Page.vue # Main dispatch board (active)
│ ├── DispatchPage.vue # Legacy v1 (deprecated)
│ ├── MobilePage.vue # Mobile tech view
│ ├── AdminPage.vue # Admin settings
│ ├── BookingPage.vue # Customer booking
│ ├── TechBidPage.vue # Tech bidding
│ └── ContractorPage.vue # Contractor view
│
├── stores/
│ ├── dispatch.js # Jobs, technicians, tags state
│ └── auth.js # Auth state
│
├── config/
│ └── erpnext.js # MAPBOX_TOKEN, TECH_COLORS, BASE_URL
│
└── router/index.js # Vue Router (hash mode)
Routes
| Path |
Page |
Description |
/#/dispatch2 |
DispatchV2Page |
Main app — scheduling board |
/#/ |
DispatchPage |
Legacy v1 |
/#/mobile |
MobilePage |
Mobile tech interface |
/#/admin |
AdminPage |
Settings |
/#/booking |
BookingPage |
Customer booking |
/#/bid |
TechBidPage |
Tech bidding |
/#/contractor |
ContractorPage |
Contractor portal |
ERPNext Doctypes
| Doctype |
Type |
Fields |
| Dispatch Job |
Document |
subject, address, lat/lng, priority, duration_h, status, assigned_tech, scheduled_date, start_time, end_date, note |
| Dispatch Technician |
Document |
technician_id, full_name, status, user, lat/lng |
| Dispatch Tag |
Document |
label, color, category (Skill/Service/Region/Equipment/Custom) |
| Dispatch Job Assistant |
Child Table (of Job) |
tech_id, tech_name, duration_h, note, pinned |
| Dispatch Tag Link |
Child Table |
tag (Link → Dispatch Tag) |
| Dispatch Settings |
Single |
API keys, Mapbox token |
PostgreSQL Extensions
| Extension |
Usage |
pg_trgm |
Trigram fuzzy search on rqa_addresses.search_text |
unaccent |
Accent-insensitive search (riviere = rivière) |
Address table: rqa_addresses — 5.2M Quebec civic addresses with pre-computed search_text column, GIN trigram index.
Key Features
Scheduling
- Day view: Timeline with pinned time anchors + auto-flow for unpinned jobs
- Week view: Calendar grid with job chips, lasso multi-select
- Month view: Overview with tech avatars per day
- Travel time: Mapbox Directions API, displayed between job blocks
Dispatch
- Auto-distribute: Ordered criteria (urgency → load balance → proximity → skills)
- Multi-drag: Select multiple jobs in bottom panel, drag to tech or batch-assign
- Route optimization: Nearest-neighbor + Mapbox Optimization API (TSP)
Job Management
- Assistants: Multi-tech jobs with floating/pinned modes
- Tags/Skills: Auto-suggest input with inline tag creation
- Address autocomplete: Server Script → PostgreSQL with pg_trgm
- Undo: Ctrl+Z for assign/unassign/optimize/distribute (30-deep stack)
UI
- Sidebar: Icon strip with flyout panels on hover
- Single click: Right panel with job details
- Double click: Edit modal (title, address, note, duration, priority, tags)
- Context menu: Right-click on jobs and techs
- Lasso: Rectangle selection in day and week views
- Map: Mapbox dark style, route visualization, geo-fix by click
Component Communication
DispatchV2Page (orchestrator)
│
├── provide/inject ──→ shared state (store, colors, functions)
│
├── TimelineRow ←──── events (job-click, drag, resize, ctx)
├── BottomPanel ←──── events (select, batch-assign, drag)
├── JobEditModal ←─── v-model + confirm event
├── WoCreateModal ←── v-model + confirm event
└── TagInput ←──────── v-model + create event
Planned Modules
| Module |
Directory |
Status |
| Dispatch |
modules/dispatch/ |
Active |
| Timesheet |
modules/timesheet/ |
Planned |
| HRMS |
modules/hrms/ |
Planned |
| ERP |
modules/erp/ |
Planned |
| OSS/BSS |
modules/oss-bss/ |
Planned |
Deploy
# Build + deploy to ERPNext Docker
./deploy.sh
# Dev server (hot reload, proxies API to ERPNext)
npx @quasar/cli dev -m pwa
# → http://localhost:9000/#/dispatch2