Commit Graph
66 Commits
Author SHA1 Message Date
abiba-bot 7ca2924191 Merge pull request 'fix(whatsapp,roles): self-heal legacy whatsapp_log schema; map underscore role aliases' (#13) from fm/fix-denya-mocklog-roles-20260909 into main 2026-09-09 13:16:35 +00:00
root 0d79a582f6 no-mistakes(document): drop stale hand-copied test count from HARDENING.md 2026-09-09 13:06:19 +00:00
root 4e8b96ed0a fix(whatsapp,roles): self-heal legacy whatsapp_log schema; map underscore role aliases
CT115 (Mumuni relay #747) — two live-instance defects after PR #12:

1. GET /api/whatsapp/mock-log 500'd with a valid admin token:
   'no such column: whatsapp_log.message_text'. The model gained
   message_text/wa_message_id/ticket_number (and dropped command) in
   4afdc36 with no migration, so legacy DBs keep the (command, ...) shape.
   ensure_legacy_schema (startup, app/main.py) now adds the three missing
   columns idempotently and backfills legacy command bodies into
   message_text before dropping the obsolete NOT NULL command column, so
   both the mock-log read path and the ORM write path work on healed DBs.
   New producer/consumer regression (tests/test_whatsapp_log_legacy_heal.py)
   reproduces the exact OperationalError, then asserts 200 + data.

2. ROLE_ALIASES gap: underscore legacy roles (cs_rep, cs_manager,
   fm_dispatcher) were not mapped, so normalize_legacy_user_roles could not
   converge rows like user 18 (test@denya.com, role 'cs_rep') and the
   frontend stranded them on /tickets. Added the underscore aliases; tests
   assert normalize_role('cs_rep') == 'CS Rep' and a cs_rep row converges
   and authenticates.
2026-09-09 12:52:07 +00:00
abiba-bot 7b0365b135 Merge pull request 'fix(frontend): vendor Alpine.js + Tailwind same-origin (LAN-safe demo)' (#12) from fm/vendor-alpine-tailwind-locally-in-denya-00 into main 2026-09-09 12:41:21 +00:00
root 49b26926cf no-mistakes(document): Align vendor asset upgrade naming with committed files 2026-09-09 01:44:56 +00:00
fm crewmate 05d768343c fix(frontend): vendor Alpine.js + Tailwind same-origin (LAN-safe demo)
The P0 templates loaded Alpine.js from cdn.jsdelivr.net and Tailwind from
cdn.tailwindcss.com, so LAN-only demo clients got a login page whose JS never
engaged (stuck form). Vendor both libraries under app/static/vendor/
(alpine-3.17.2.min.js, tailwind-3.4.17.js) served same-origin at /static,
point base.html at local paths, and drop both CDN hosts from the CSP
(script-src/style-src stay 'self' 'unsafe-inline'; connect-src 'self').

HTML pages now ship Cache-Control: no-cache; vendored assets are cached
public, max-age=31536000, immutable (versioned filenames). HSTS stays
TLS-gated. Adds tests/test_frontend_vendoring.py (no external script src on
/login, both vendor paths 200, no-cache + immutable header checks, CSP
without CDN hosts).
2026-09-09 01:01:47 +00:00
abiba-bot 371826c15e Merge pull request #11: Denya OneCare P0 security lockdown (captain-approved) 2026-09-08 17:38:21 +00:00
root e627f50f66 no-mistakes(document): Document P0 auth batch; reconcile HARDENING statuses; lint fixes 2026-09-08 12:48:47 +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-bot 901f95e0f6 Merge pull request 'fix: P0 hardening — fail-closed SECRET_KEY, locked CORS, role-safe registration (HARDENING.md P0.1/P0.2/P0.3)' (#10) from fix/p0-hardening-prA into main 2026-09-03 00:10:55 +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-bot 76d9d12b78 Merge pull request 'feat: Phase 1 session timeout — access token 30 -> 60 min' (#9) from feat/phase1-session-timeout into main 2026-08-26 23:52:41 +00:00
Mumuni (Hermes) 3ad81e2c39 feat: increase access token lifetime 30 -> 60 min (Phase 1 session timeout) 2026-08-26 23:52:13 +00:00
mumuni-bot aef9d90097 Merge pull request 'feat: Phase 1 — apartment mapping (134 units) + 12 categories' (#8) from feat/phase1-apartment-mapping-categories-timeout into main 2026-08-26 23:51:40 +00:00
Mumuni (Hermes) c9b722041c fix: include Penthouse rows (PH1E-/PH1W-/PH2E-/PH2W-) in apartment mapping — parser had skipped them 2026-08-26 23:44:30 +00:00
Mumuni (Hermes) cf1d9413bb fix: COPY apartment_mapping.json into image (was missing -> built-in fallback used) 2026-08-26 21:29:55 +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
abiba-bot 78068c23d9 Merge pull request 'docs: Production hardening & review checklist (demo -> prod)' (#6) from docs/prod-hardening-checklist into main 2026-08-15 13:36:09 +00:00
abiba-bot 51e00a40cd Merge pull request 'feat: backdated reported date for old active tickets' (#7) from fm/denya-backdate-report-date into main 2026-08-03 09:59:06 +00:00
root fb0c1784d0 no-mistakes(review): Extend ensure_legacy_schema to add tickets.reported_at with backfill 2026-08-03 09:45:41 +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
abiba-bot 1f15ca5457 docs: production hardening & review checklist for demo->prod transition
Grounded in hands-on review of the live scottdenya deployment and main.
P0 security blockers, P1 operational hardening, WhatsApp wiring runbook,
no-mistakes review items, and production Definition-of-Done.

Prepared by Mumuni (Syslog Falcon) 2026-08-03.
2026-08-03 08:05:26 +00:00
abiba-bot 30c0c01c59 Merge pull request 'Wahab demo prep — workflow hardening, Cancelled status, ticket cleanup support' (#5) from fm/denya-wahab-cleanup-hardening into main 2026-08-02 15:01:24 +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
abiba-bot ffed595dbd Merge pull request 'Sprint A Wahab review batch — categories, property hierarchy, priority grouping' (#4) from fm/denya-wahab-sprint-a into main 2026-08-02 13:36:31 +00:00
root 5e9ec29439 no-mistakes(document): Sync AGENTS.md taxonomy, drop unused imports 2026-08-02 13:34:49 +00:00
root 663354eeaf no-mistakes(review): Extend legacy self-heal rename; clear stale Mould & Damp priority default 2026-08-02 13:22:32 +00:00
root db6826cb49 no-mistakes(review): Add startup self-heal guard for show_in_form column 2026-08-02 12:36:10 +00:00
root ae17005932 no-mistakes(review): Fix stale urgent priority when leaving emergency mode 2026-08-02 12:26:19 +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 2e995ee758 no-mistakes(review): Add pytest pythonpath config so tests resolve app imports 2026-07-31 10:18:52 +00:00
root d4ef96f17c no-mistakes(document): docs: add pytest suite to AGENTS.md structure and commands 2026-07-31 10:09:54 +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 47be148240 fix(dashboard): paginate CEO dashboard ticket fetch to respect API cap
The CEO dashboard requested /api/tickets?page_size=500, but the API caps
page_size at 200 (le=200 in app/routers/tickets.py), so the request
returned 422 and every KPI/chart rendered zeros.

- ceo.html: fetch all tickets by looping pages of page_size=200 until
  total items are collected (with a safety bound), keeping KPIs accurate
  as volume grows past 200.
- tests: add test suite anchoring the pagination contract — page_size=500
  returns 422, page_size=200 returns items/total/page/page_size, and a
  page loop collects every ticket without duplicates.
- pyproject: enable pytest-asyncio auto mode and tests/ discovery.
- .gitignore: un-ignore committed tests/test_*.py.
2026-07-31 09:53:35 +00:00
root f84021bc14 Merge remote-tracking branch 'origin/fm/denya-onecare-s3' 2026-07-25 00:19:59 +00:00
root cf55576d10 feat: Denya Developers brand theming
- Brand colors: primary #0d2b18 (deep forest green), accent #c8a96e (gold), bg #faf8f5 (cream), text #1a1a1a
- Nav bg #0d2b18 with gold logo mark and white text
- Denya Developers + OneCare branding in nav header
- Gold accent borders, hover states, and active tab highlights
- Toast/success use brand green shades
- Body background cream (#faf8f5)
2026-07-25 00:19:59 +00:00
jerome 4afdc36765 feat: Replace mock WhatsApp with real Meta Graph API webhook
- POST /api/whatsapp/webhook handles Meta verification (hub.challenge)
- Inbound text messages create tickets via create_ticket()
- Auto-reply confirmation sent back via Meta Graph API
- WhatsApp messages logged with ticket linkage in whatsapp_log
- Added WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_ACCESS_TOKEN, WHATSAPP_VERIFY_TOKEN config
- Kept /mock-log debug endpoint for backward compatibility
- Graceful degradation: logs message even if ticket/reply fails
2026-07-24 20:07:30 -04:00
root c9f5ac4380 feat: Denya Developers brand theming
- Brand colors: primary #0d2b18 (deep forest green), accent #c8a96e (gold), bg #faf8f5 (cream), text #1a1a1a
- Nav bg #0d2b18 with gold logo mark and white text
- Denya Developers + OneCare branding in nav header
- Gold accent borders, hover states, and active tab highlights
- Toast/success use brand green shades
- Body background cream (#faf8f5)
2026-07-23 19:46:08 +00:00
abiba-bot 3920cf14a1 Sprint 3: Alpine.js Dashboards 2026-07-23 19:36:35 +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 ef2297ea87 no-mistakes(review): Fixed aging bucket boundaries and removed wasteful API call 2026-07-23 19:21:31 +00:00
root a9c17d0703 fix: address remaining review findings
- Fix detail.html to use assigned_technician_name (not .assigned_technician?.full_name)
- Remove double error toast in submitNote() catch block
- Replace wasteful API calls in CEO dashboard with units+data approach
- Remove QR Code option from reported_via dropdown (excluded per scope)
2026-07-23 19:18:17 +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 7fab1ede51 fix: address ask-user findings from review
- Move unit loading to use real /api/tickets/units endpoint
- Match unit code format to backend seed (0101E style)
- Send unit_id in create ticket payload
- Fix tech IDs to match seed order (9-15 for Prosper-Afful)
- Add customer_name and phone fields to TicketCreate schema
- Map form customer_name/phone into API payload
2026-07-23 19:08:49 +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 9aa7971a28 feat: Sprint 3 frontend dashboards with Alpine.js + Jinja2
- Login page with JWT auth and role-based redirect
- CS Dashboard: KPI cards, priority breakdown, recent tickets
- FM Dashboard: tech workload, aging analysis, emergency alerts
- CEO Dashboard: executive KPIs, charts, risk indicators
- All Issues: filterable/sortable ticket table with pagination
- Create Issue: form with category tree, property/unit selector, photo uploads
- Issue Detail: full timeline, photo gallery, SLA status, action modals
- Role-based nav bar: CS/FM/Executive links adapt to user role
- Base template: shared Alpine.js app state, toast notifications, loading overlay
2026-07-23 19:01:26 +00:00