diff --git a/CLAUDE.md b/CLAUDE.md index 17fb780..0950f93 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 (Phase 19 complete + mobile API gap-fill Phases A–E + customer UI refinements + Phase 22 comment visibility + Phase 23 support chat/tickets + inspector performance Excel export + inspection list filters + customer issue logging + AI chatbot + dashboard grouped sections + issues/inspections PDF export + date/ID filters + Reports expansion Phases R1–R4 + Phase 24 issue_created notify defaults + Phase 25 inspection GPS + Phase 26 issue vendor fields + Phase 27 facility score alerts + Phase 28 inspection-notify fix + Phase 29 admin broadcasts + Phases 30–32 device registry consolidation + ProxyFix reverse-proxy fix) +> **Last reviewed:** July 2026 (Phase 19 complete + mobile API gap-fill Phases A–E + customer UI refinements + Phase 22 comment visibility + Phase 23 support chat/tickets + inspector performance Excel export + inspection list filters + customer issue logging + AI chatbot + dashboard grouped sections + issues/inspections PDF export + date/ID filters + Reports expansion Phases R1–R4 + Phase 24 issue_created notify defaults + Phase 25 inspection GPS + Phase 26 issue vendor fields + Phase 27 facility score alerts + Phase 28 inspection-notify fix + Phase 29 admin broadcasts + Phases 30–32 device registry consolidation + ProxyFix reverse-proxy fix + Phase 33 per-contract notification recipients + grouped Admin nav dropdown + forgot-password case-insensitive lookup & email normalization + transactional email sender/branding fix + Phase 34 facility QR public pages & report-a-problem + Phase 35 issue handler_type (our staff / facility / vendor) + Phase 36 scheduled inspections) --- @@ -133,7 +133,7 @@ lt_janitorial_quality_control/ │ └── utils/ ├── migrations/ │ └── versions/ -│ └── phase32_device_token_columns.py ← HEAD +│ └── phase36_scheduled_inspections.py ← HEAD └── ... Note: `app/routes/broadcast.py` + `app/models/broadcast.py` (admin broadcasts) and @@ -390,6 +390,7 @@ inspections.scheduled_inspection_id FK→scheduled_inspections SET NULL ← P **A plan, not an inspection.** Names a facility + template + assigned inspector + `next_due_date`. Lifecycle: - The assigned inspector (or a manager) clicks **Start** → `scheduled_inspections.start` creates a normal `in_progress` Inspection with `scheduled_inspection_id` set, then redirects to the execute flow. - On **completion** (execute route, status → `completed`), `ScheduledInspection.fulfill()` runs in the same atomic commit: `once` → `active=False`; recurring → `next_due_date` rolls forward past today via `_add_interval()` and the three `*_notified` flags reset. +- **Assignment notification** (immediate): on **create**, the assigned inspector gets an in-app + email "assigned to you" notification; on **edit**, only when the inspector actually changes (a "reassigned to you" notification to the new assignee). Via `_notify_assignee()` in the blueprint using `event_type=EVENT_SCHEDULED_INSPECTION`. - **Reminders** are dispatched by the cron endpoint (see §11): advance (1 day before) + due-date to the inspector, overdue to admin/director — each fires at most once per occurrence via the `*_notified` flags. Uses `notify()` with `event_type=EVENT_SCHEDULED_INSPECTION`. - Dashboard shows an **upcoming (next 7 days) / overdue** panel for non-customers (inspectors see only their own). @@ -932,6 +933,9 @@ if obj is None: abort(404) ### Active Nav Tab Detected via `request.endpoint.startswith('.')` in each nav `` tag. +### Admin Nav Dropdown +Admin-only tools (Users, Audit Trail, Notification Matrix, Broadcast, Devices) are consolidated into a single **Admin** dropdown in `base.html` (plain text items, no icons, no dividers — matching sibling top-level nav links). The dropdown toggle shows `active` when any of its endpoints is active (`admin_active` flag). The separate user-menu dropdown keeps its own dividers — don't `replace_all` on `dropdown-divider` across the file. + ### Display Names Always use `user.display_name` in templates — never `.username` for display purposes. @@ -960,7 +964,7 @@ Always use `user.display_name` in templates — never `.username` for display pu The Contract selector is always a plain HTML `