diff --git a/CLAUDE.md b/CLAUDE.md index 3b7ff02..c06c28e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,7 @@ > **Audience:** AI assistants and developers working on this codebase. > **Purpose:** Authoritative reference for architecture, conventions, gotchas, and decisions. -> **Last reviewed:** July 2026 (doc-reconciliation pass — verified against code on disk. Adds previously-undocumented phase28 notify-fix, phase29 broadcasts, phase30–32 device registry; `broadcast` + `devices` + `api_devices` blueprints; Broadcast + DeviceRegistration models; corrected MT-8 billing status to DONE; resolved the device-registration collision (rule 84 — removed duplicate `api_devices` blueprint + `DeviceRegistration` model, consolidated on `DeviceToken`). Prior: Phase 19 + mobile API Phases A–E + Phase 22 comment visibility + Phase 23 support chat/tickets + inspector Excel export + inspection list filters + customer issue logging + AI chatbot + dashboard grouped sections + issues/inspections PDF export + Reports R1–R4 + Phase 24 notify defaults + Phase 25 GPS + Phase 26 vendor fields + Phase 27 score alerts + **MT-0 through MT-8 complete; self-service signup; trial enforcement; billing emails; invoice history; superadmin billing controls; per-tenant backup CLI; health dashboard; fail2ban; welcome email; dunning day-3/7/14; ProxyFix middleware; QR occupant issue reporting; issue handler type (phase39); support chat persistence + knowledge base (phase40); MT-9 iOS pending**) +> **Last reviewed:** July 2026 (doc-reconciliation pass — verified against code on disk. Adds previously-undocumented phase28 notify-fix, phase29 broadcasts, phase30–32 device registry; `broadcast` + `devices` + `api_devices` blueprints; Broadcast + DeviceRegistration models; corrected MT-8 billing status to DONE; resolved the device-registration collision (rule 84 — removed duplicate `api_devices` blueprint + `DeviceRegistration` model, consolidated on `DeviceToken`). Prior: Phase 19 + mobile API Phases A–E + Phase 22 comment visibility + Phase 23 support chat/tickets + inspector Excel export + inspection list filters + customer issue logging + AI chatbot + dashboard grouped sections + issues/inspections PDF export + Reports R1–R4 + Phase 24 notify defaults + Phase 25 GPS + Phase 26 vendor fields + Phase 27 score alerts + **MT-0 through MT-8 complete; self-service signup; trial enforcement; billing emails; invoice history; superadmin billing controls; per-tenant backup CLI; health dashboard; fail2ban; welcome email; dunning day-3/7/14; ProxyFix middleware; QR occupant issue reporting; issue handler type (phase39); support chat persistence + knowledge base (phase40); Reports R1+R2 contract cascade filter; billing emails branded From address; MT-9 iOS pending**) --- @@ -116,7 +116,7 @@ lt_janitorial_quality_control/ │ ├── models/ │ │ ├── inspection.py # Inspection — mobile_local_id column (Phase B) │ │ ├── issue.py # Issue — mobile_local_id (Phase B), reported_by (Phase 18), mobile_photo_paths (Phase 19) -│ │ ├── support.py # SupportTicket, SupportTicketReply (Phase 23) +│ │ ├── support.py # SupportChatSession, SupportChatMessage, SupportKnowledge (phase40) + SupportTicket, SupportTicketReply (Phase 23) │ │ ├── tenant_settings.py # MT-7: TenantSettings — per-tenant branding (one row per tenant DB) │ │ └── ... │ ├── routes/ @@ -1106,11 +1106,13 @@ Always use `user.display_name` in templates — never `.username` for display pu The Contract selector is always a plain HTML `` (no name attribute — not submitted) appears above the Facility dropdown. On change, JS calls `GET /inspections/facilities_for_project/` to narrow the Facility list in-browser; clearing the contract restores all options. The route passes `projects` (all active, or scoped to customer facility set). The actual DB filter uses only `facility_id`. + Excel export: `GET /reports/export/issues-aging` — one sheet, color-coded severity and SLA columns. Helper: `_load_open_issues_scoped(customer_facility_ids, severity_filter, facility_id_filter)` — extracted so both the HTML route and the Excel export share identical query logic. @@ -1207,6 +1211,8 @@ Loads resolved issues in the date range, computes `within_sla()` per issue (comp - `by_severity` — dict with `total`, `met`, `pct`, `sla_hours` per severity tier - `by_facility` — list sorted by compliance % descending +**Contract cascade filter:** Same client-side Contract → Facility cascade as R1. Route passes `projects`; DB filter uses only `facility_id`. + Helper: `_sla_within(issue)` — used by both the HTML route and the Excel export. Excel export: `GET /reports/export/sla-compliance` — 2 sheets: **By Severity** (with totals row) and **By Facility**. @@ -1227,12 +1233,15 @@ A **PDF Summary** button was added to `reports/scorecard.html` alongside the exi ### Support Chat — Customer UX -`GET /support/chat` — customer only. Renders: -- Greeting message with `current_user.display_name` (injected via `var userName = {{ current_user.display_name | tojson }}` — use `tojson` not inline interpolation to prevent XSS/quote breaks). -- FAQ quick-reply chips: text stored in `data-faq="..."` HTML attribute (HTML-escaped with `| e`), read in JS via `btn.dataset.faq`. **Never use `| tojson` in an `onclick=""` attribute** — it emits double-quoted JSON inside a double-quoted attribute, breaking HTML parsing and truncating the `