Wahab customer request (relay #748 v3 next-wave).
3a. Fix 'Tech #N' display:
- FM dashboard's "Technician Workload" card was built from
`Tech #${t.assigned_to}`; it now reads Ticket.assigned_technician_name
(falling back to 'Unassigned', matching /tickets).
- Template sweep confirms no other `Tech #` placeholder exists.
3b. Technician performance dashboard:
- New bearer-gated GET /api/tickets/tech-performance aggregating existing
ticket columns only (no schema change): per-technician total assigned,
completed, in progress, escalated, cancelled, pending, open tasks,
completion rate, and created_at -> closed_at resolution time with explicit
counts for finished tasks lacking a timestamp. Rows key on user id so
same-name technicians stay separate; labels are real names. Fleet totals
and an unassigned-ticket count are included.
- New /dashboard/tech-performance page (FM + CEO nav and links) with sortable
table, completion bars and empty states; same-origin vendored assets only.
- Bucket map, service, schemas and tests in app/services/ticket.py,
app/schemas/ticket.py, tests/test_tech_performance.py.
Tests: 111 passed (101 existing + 10 new).