OSS-BSS-Field-Dispatch/ARCHITECTURE.md
louispaulb fd66c21c2e Add ARCHITECTURE.md — full project documentation
Covers: stack, directory structure, routes, ERPNext doctypes,
PostgreSQL extensions, features, component communication,
planned modules, and deploy instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:10:06 -04:00

162 lines
6.8 KiB
Markdown

# 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
```bash
# 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
```