Commit Graph
21 Commits
Author SHA1 Message Date
root 43800345c1 feat(dashboard): technician performance report + real technician names
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).
2026-09-10 04:00:19 +00:00
root f1b68dd1b7 no-mistakes(review): Normalize legacy emails to prevent case-based login lockout 2026-09-08 12:33:01 +00:00
root 3ae1062d65 P0 security batch: admin-only user mgmt, unified role model, login rate limiting, webhook secret, security headers, pagination caps
- Remove POST /api/auth/register (404); no sign-up UI; users are admin-managed
- Add admin-only POST/PATCH/DELETE /api/auth/users (forced canonical roles,
  self-lockout + reference guards)
- Unify role model in app/core/roles.py; reject unknown roles at creation and
  at login/JWT validation; startup normalizes unambiguous legacy aliases
- Login rate limiting ~5 fails/15 min per IP+email -> 429 (in-process, tunable)
- WhatsApp webhook requires X-Webhook-Secret; fail-closed when env unset;
  GET handshake uses constant-time verify token (403 on mismatch)
- GET /api/whatsapp/mock-log now requires auth
- Security headers middleware: X-Frame-Options DENY, nosniff, CSP on HTML,
  HSTS behind TLS
- Pagination: limit alias for page_size, hard cap enforced, both -> 422
2026-09-08 10:36:16 +00:00
Mumuni (Syslog Code Agent) 3ec09470ff fix: P0 hardening — fail-closed SECRET_KEY, locked CORS, role-safe registration (HARDENING.md P0.1/P0.2/P0.3)
P0.1 — fail-closed secrets:
- config.py: no default SECRET_KEY; refuses to boot when unset, a known
  placeholder, or <32 chars. Generate with: openssl rand -hex 32.
- docker-compose.yml: literal secrets removed; runtime env now comes from
  a git-ignored .env via env_file. .env.example added as template.
- .gitignore already covers .env (verified).

P0.2 — locked CORS:
- main.py: CORS_ORIGINS must be an explicit comma-separated allow-list.
  '*' or an empty value refuses to boot (was: silently ['*'] with
  allow_credentials=True).

P0.3 — role-safe registration:
- services/auth.py: client-supplied 'role' is IGNORED on POST
  /api/auth/register; self-registered users always get the
  least-privilege 'CS Rep' role. Unauthenticated callers can no longer
  mint Admin/Jerome, Admin/Wahab, or Director accounts.

Tests:
- conftest.py sets test SECRET_KEY/CORS_ORIGINS before app import.
- New tests/test_p0_hardening.py (8 tests): role-escalation blocked for
  Admin/Jerome and Admin/Wahab, duplicate-email 409, and subprocess
  boot-validation for placeholder/short/missing secret + wildcard CORS.
- Full suite: 44 passed.

Redeploy note (per research): seed_units/seed_categories are insert-only,
so the Aug-26 redeploy does NOT orphan historical tickets referencing
units 103E/103W/105E/105W or the legacy 34-category tree. Pending
Wahab: are 103E/103W/105E/105W real apartments dropped from the Excel
regeneration? Optional follow-up: floor-number backfill for already-
seeded units (mapping corrected floors; existing rows keep old values).

Checks per HARDENING.md acceptance:
- [x] starting without a real key fails loudly (subprocess-verified)
- [x] compose carries no literal secret; secrets come from .env
- [x] CORS_ORIGINS explicit allow-list, '*' rejected
- [x] unauthenticated register cannot mint Admin/* or Director
2026-09-02 23:59:21 +00:00
Mumuni (Hermes) f256f1a6d2 feat: Phase 1 — regenerate 134-unit mapping from Excel + add 12 categories 2026-08-26 15:27:59 +00:00
root e0a7479c3e feat: backdated reported date for old active tickets
Wahab can now enter historical tickets that keep their true reported date:

- Add nullable tickets.reported_at (DateTime) via alembic d5e0f2a1c3b4;
  backfill existing rows from created_at so nothing shows empty.
- TicketCreate.reported_at (optional) is persisted by create_ticket and
  defaults to now when omitted, so existing create behavior is unchanged.
- New-issue form gains a 'Reported Date' date picker (defaults to today,
  past dates allowed, future blocked) and sends reported_at in the payload.
- List and detail pages show 'Reported' next to 'Created' (date-only,
  labeled) so backdated tickets are obvious; SLA deadline is unchanged and
  still runs from creation time so backfilling never instantly breaches.
- Tests: backdated create persists + is exposed on list/detail; omitted
  reported_at defaults to now; SLA window unchanged; full datetime round trip.
2026-08-03 09:40:23 +00:00
root bf361d76bc no-mistakes(document): Docs synced for Cancelled status; lint cleaned 2026-08-02 14:37:37 +00:00
root 6b92c9098c no-mistakes(review): Guard photo cleanup; add transitions helper and assign auto-advance 2026-08-02 14:26:48 +00:00
root 237284b012 no-mistakes(review): Make Cancelled reachable from all active states; wire phone PATCH; exclude cancelled from CEO resolution avg 2026-08-02 14:12:46 +00:00
root 1dd88a141e feat: Wahab demo prep — Cancelled status, phone persistence, admin delete, users picker, detail-page fixes
- Add Cancelled as terminal status reachable from all active states; exclude
  from SLA breach reporting and dashboard active counts; add to status pickers
- Persist customer phone on ticket create/update (was silently dropped);
  add tickets.phone migration + legacy self-heal guard
- Add admin-only DELETE /api/tickets/{id} (removes timeline/photos/escalations)
- Add GET /api/auth/users for the assign-technician dropdown (was hardcoded)
- TicketOut now returns nested unit/category so the detail page stops showing
  '—' for Unit/Property/Category
- Ticket numbering uses max+1 so deletions never re-issue a number
- New-issue form: require Category and (standard mode) Priority client-side
- Tests: 11 new cases covering cancellation, SLA exemption, phone, delete,
  users endpoint, numbering
2026-08-02 14:06:30 +00:00
root 2407f294f4 feat: Sprint A Wahab review batch — categories, property hierarchy, priority grouping
Items 1-5, 9, 11 from denya-wahab-feedback-s2:
- Category.show_in_form (alert-only flag): Gas Leak hidden from issue picker
  but kept urgent for SLA/alert and reporting; emergency quick path on the
  new-issue form creates urgent tickets via include_hidden categories.
- Seed: Aluminum/Glass, Carpentry, Mould & Damp (Medium default) maintenance
  categories; Lost Property renamed Missing Item (+ sub).
- One alembic migration: add show_in_form (backfill True, Gas Leak False) +
  data rename Lost Property -> Missing Item.
- Property -> Building -> Apartment cascade with searchable apartment combobox
  on the new-issue form and ticket list filters; /api/tickets/units gains
  building filter + /units/grouped variant; /api/tickets gains additive
  building/unit_id filters. apartment_mapping.json committed (deterministic).
- Group-by-priority toggle on /tickets (four sections + unknown bucket,
  age-sortable, composes with filters, URL deep links), FM dashboard active
  tickets, and CS dashboard priority card click-through.
- Tests: 13 new (category visibility, seed idempotency/sync, unit grouping,
  ticket building/unit filters).
2026-08-02 09:30:29 +00:00
root d074f347dc no-mistakes(review): Add pytest-asyncio dev dep and deterministic pagination tiebreaker 2026-07-31 09:57:56 +00:00
root 01e28bbcc7 fix: map customer_name to reporter in create_ticket service
Per captain decision: customer_name maps to reporter field (fallback),
phone field skipped for MVP (no DB column).
2026-07-23 19:26:04 +00:00
root 5560496653 no-mistakes(review): Fix F01/F02/F05: technician name, duplicate timeline, FM dashboard property counts 2026-07-23 19:13:10 +00:00
root 3dc383e62d fix: auto-fix findings from no-mistakes review
- Remove duplicate  import
- Fix  →  in create ticket
- Fix  →  in ticket detail
- Add note field to TicketUpdate schema and handle note-only updates in backend
- Update frontend submitNote() to use PATCH endpoint
2026-07-23 19:06:33 +00:00
root 344d555529 no-mistakes(document): Fix stale seed.py docstring and remove unused imports across 3 files 2026-07-23 17:42:54 +00:00
root 57b18a27e3 no-mistakes(review): Removed redundant or 0 guard on reopen_count increment 2026-07-23 17:33:19 +00:00
root a27b1856cc no-mistakes(review): All F01-F09 findings verified as properly fixed in the codebase 2026-07-23 17:24:57 +00:00
root 31ae78ec07 no-mistakes(review): Fix redundant OR, missing note field, dead code, and redundant subquery in ticket service/schema 2026-07-23 17:18:13 +00:00
root 65622de7a6 Sprint 2: Ticket Engine + SLA + Photo Uploads
- Ticket CRUD with full 15-status lifecycle enforcement
- Auto-generated ticket numbers (PAV-YYYY-NNNNN)
- Status transitions validated and auto-logged to timeline
- Reopen with 7-day window + auto-escalation to Ama
- SLA engine: priority-based deadlines and breach detection
- Photo uploads to uploads/ with multipart support
- Category system seeded from PRD §7 taxonomy (20 top-level)
- Flat and tree category listing endpoints
- SLA status check endpoint (/api/tickets/{id}/sla)
- Paginated ticket listing with filters
2026-07-23 17:13:12 +00:00
root 32a4c50b23 feat: Sprint 1 foundation - FastAPI scaffold, DB schema, auth, seed data, mock WhatsApp, Docker 2026-07-23 12:04:14 +00:00