06/12 Update documents

This commit is contained in:
2026-06-12 13:08:58 -04:00
parent 6d42c81491
commit d965fa6ce2
2 changed files with 120 additions and 10 deletions
+112 -9
View File
@@ -2,7 +2,7 @@
> **Audience:** AI assistants and developers working on this codebase. > **Audience:** AI assistants and developers working on this codebase.
> **Purpose:** Authoritative reference for architecture, conventions, gotchas, and decisions. > **Purpose:** Authoritative reference for architecture, conventions, gotchas, and decisions.
> **Last reviewed:** June 2026 (Phase 19 complete + mobile API gap-fill Phases AE + customer UI refinements + Phase 22 comment visibility + Phase 23 support chat/tickets + inspector performance Excel export + inspection list filters + customer issue logging + AI chatbot) > **Last reviewed:** June 2026 (Phase 19 complete + mobile API gap-fill Phases AE + 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 R1R4)
--- ---
@@ -41,7 +41,7 @@
- **Issue** tracking with SLA enforcement, follower subscriptions, and verification workflow - **Issue** tracking with SLA enforcement, follower subscriptions, and verification workflow
- **Customer portal** with scoped facility visibility and invitation-based onboarding - **Customer portal** with scoped facility visibility and invitation-based onboarding
- **Notification** system (in-app + email) driven by an admin-controlled matrix - **Notification** system (in-app + email) driven by an admin-controlled matrix
- **Reports** — on-demand PDF/CSV scorecards and scheduled email digests - **Reports** — on-demand PDF/CSV/Excel scorecards, scheduled email digests, Issues Aging, SLA Compliance, Follow-up Closure Rate, and per-facility Customer PDF Summary
- **Audit trail** — immutable log of every create/update/delete action - **Audit trail** — immutable log of every create/update/delete action
- **Support chat** — Groq AI chatbot for customers with preset FAQ chips; escalation to admin via ticketing system; customers can view and reply to their own tickets; admins manage tickets at `/support/admin/tickets` - **Support chat** — Groq AI chatbot for customers with preset FAQ chips; escalation to admin via ticketing system; customers can view and reply to their own tickets; admins manage tickets at `/support/admin/tickets`
- **Mobile API** — JWT-authenticated REST layer for the iPad native app - **Mobile API** — JWT-authenticated REST layer for the iPad native app
@@ -110,10 +110,20 @@ lt_janitorial_quality_control/
│ │ ├── issue_photos/ # photo_path and mobile_photo_paths files │ │ ├── issue_photos/ # photo_path and mobile_photo_paths files
│ │ └── issue_result_photos/ # result_photos files (web-added resolution photos) │ │ └── issue_result_photos/ # result_photos files (web-added resolution photos)
│ ├── templates/ │ ├── templates/
│ │ ── issues/ │ │ ── issues/
│ │ ├── view.html # Shows photo_path + mobile_photo_paths under "Photo Evidence" │ │ ├── view.html # Shows photo_path + mobile_photo_paths under "Photo Evidence"
│ │ └── issues_view.html # Same photo evidence logic │ │ └── issues_view.html # Same photo evidence logic
│ ├── templates/ │ ├── reports/
│ │ │ ├── _subnav.html # Shared sub-nav include for all report pages
│ │ │ ├── index.html # Overview & Trends (score trend, facility scores, charts)
│ │ │ ├── facility.html # Per-facility detail report
│ │ │ ├── scorecard.html # Per-facility scorecard (trend, area scores, SLA, open issues) + PDF Summary button
│ │ │ ├── inspector_performance.html # Inspector KPI table + drill-down chart
│ │ │ ├── issues_aging.html # Open issues grouped by age bucket (R1)
│ │ │ ├── sla_compliance.html # SLA compliance by severity and facility (R2)
│ │ │ └── followup_closure.html # Follow-up re-inspection closure rate (R3)
│ │ ├── scheduled_reports/
│ │ │ └── index.html # Includes _subnav.html for Reports sub-nav
│ │ └── support/ │ │ └── support/
│ │ ├── chat.html # Customer AI chatbot + FAQ chips + submit-ticket modal │ │ ├── chat.html # Customer AI chatbot + FAQ chips + submit-ticket modal
│ │ ├── my_tickets.html # Customer: list of own tickets │ │ ├── my_tickets.html # Customer: list of own tickets
@@ -346,8 +356,8 @@ api_device_tokens: id, user_id, device_id, apns_token, device_name, app_version
| `issues` | `/issues` | list, view, create, update, verify, comment, follow/unfollow, verification queue, bulk-verify, delete, quick-assign | | `issues` | `/issues` | list, view, create, update, verify, comment, follow/unfollow, verification queue, bulk-verify, delete, quick-assign |
| `notifications` | `/notifications` | list, mark-read, preferences, send-digest (cron), check-sla (cron), cleanup-tokens (cron) | | `notifications` | `/notifications` | list, mark-read, preferences, send-digest (cron), check-sla (cron), cleanup-tokens (cron) |
| `audit` | `/audit` | list (admin only), view, purge | | `audit` | `/audit` | list (admin only), view, purge |
| `reports` | `/reports` | index, facility report, scorecard, CSV/PDF export | | `reports` | `/reports` | index, facility report, scorecard, CSV/PDF/Excel export, issues-aging, sla-compliance, followup-closure, facility summary PDF |
| `scheduled_reports` | `/scheduled-reports` | CRUD + manual trigger | | `scheduled_reports` | `/scheduled-reports` | CRUD + manual trigger (accessible via Reports sub-nav) |
| `support` | `/support` | `GET /chat`, `POST /chat/message` (AJAX→Groq), `POST /tickets`, `GET /my-tickets`, `GET/POST /my-tickets/<id>`, `GET /admin/tickets`, `GET/POST /admin/tickets/<id>` | | `support` | `/support` | `GET /chat`, `POST /chat/message` (AJAX→Groq), `POST /tickets`, `GET /my-tickets`, `GET/POST /my-tickets/<id>`, `GET /admin/tickets`, `GET/POST /admin/tickets/<id>` |
| `api` | `/api/v1` | parent blueprint | | `api` | `/api/v1` | parent blueprint |
| `api_auth` | `/api/v1` | `/auth/login`, `/auth/refresh`, `/auth/logout`, `/auth/me`, `/devices/register` | | `api_auth` | `/api/v1` | `/auth/login`, `/auth/refresh`, `/auth/logout`, `/auth/me`, `/devices/register` |
@@ -386,6 +396,16 @@ All WTForms classes. `AreaForm.area_type` includes `floor`. `UserForm` excludes
### `pdf_export.py` ### `pdf_export.py`
ReportLab-based. 12-column grid must be preserved — never collapse in PDF views. ReportLab-based. 12-column grid must be preserved — never collapse in PDF views.
**Public functions:**
- `generate_inspection_pdf(inspection, form_fields, form_data, issues, static_folder)` — per-inspection PDF
- `generate_issues_list_pdf(issues, filter_summary)` — landscape issues list PDF (from issues list export)
- `generate_inspections_list_pdf(inspections, filter_summary)` — landscape inspections list PDF
- `generate_facility_summary_pdf(facility, days, start, now, total_inspections, avg_score, area_scores, open_issues, resolved_count)` — customer-facing one-page facility summary PDF (Phase R4)
**`_build_styles()` registered style names:** `ReportTitle`, `ReportSub`, `SectionHead`, `FieldLabel`, `FieldValue`, `MetaLabel`, `MetaValue`, `IssueDesc`, `FooterStyle`, `SummaryTitle`, `ReportSubtitle`, `Meta`, `ScoreValue`, `ScoreLabel`, `SectionHeader`, `TableHeader`, `TableCell`
The last eight styles (`SummaryTitle` through `TableCell`) were added for the facility summary PDF and are available for any future customer-facing PDF functions.
--- ---
## 9. Mobile API (Phase 7 / Phase AE) ## 9. Mobile API (Phase 7 / Phase AE)
@@ -740,13 +760,96 @@ Rendered in `dashboard.html` for `current_user.role == 'customer'`. Uses a Boots
`inspections.index()` accepts five additional query params: `date_from`, `date_to` (ISO date strings), `score_min`, `score_max` (0100 floats), `inspector_id` (int). Inspector filter is suppressed when the viewer has the `inspector` role (they always see their own only). The `inspectors` variable is passed to the template only for non-inspector roles so the dropdown is conditionally rendered. `inspections.index()` accepts five additional query params: `date_from`, `date_to` (ISO date strings), `score_min`, `score_max` (0100 floats), `inspector_id` (int). Inspector filter is suppressed when the viewer has the `inspector` role (they always see their own only). The `inspectors` variable is passed to the template only for non-inspector roles so the dropdown is conditionally rendered.
### Inspection List — PDF Export & Filter State Preservation
`GET /inspections/export-list-pdf` — same filter logic as `index()`, passes current filters as `filter_summary` string to `generate_inspections_list_pdf()`. Logs `ACTION_EXPORT`.
**Filter state on back-navigation:** `list.html` adds class `insp-list-link` to every View/Continue button. On click, JS saves `window.location.href` to `sessionStorage['insp_list_back_url']`. `view.html` reads this key on load and updates the back button `href` so returning from a detail view restores the previous filter state.
### Issues List — ID Filter, Date Filter & PDF Export
`issues.index()` accepts three additional query params: `issue_id` (exact match on `Issue.id`), `date_from`, `date_to` (ISO date strings applied to `Issue.reported_at`). The `date_to` end is expanded to `23:59:59` so the whole day is included.
`GET /issues/export-list-pdf` — same scope + filter logic as `index()`, applies SLA post-filter for `?sla=` param (SLA is computed in Python, not stored). Calls `generate_issues_list_pdf()`.
Both `index()` and `export_list_pdf()` carry `date_from` / `date_to` in pagination links and the unfollow-next URL.
### Inspector Performance — Excel Export ### Inspector Performance — Excel Export
`GET /reports/export/inspector-performance` generates a `.xlsx` with two sheets: `GET /reports/export/inspector-performance` generates a `.xlsx` with two sheets:
- **Performance Summary** — all inspector KPIs, color-coded cells, totals row - **Performance Summary** — all inspector KPIs, color-coded cells, totals row
- **Inspection Detail** — individual inspection records for the period - **Inspection Detail** — individual inspection records for the period
Accepts `date_from`, `date_to`, `inspector_id` query params matching the HTML report page. Logs an `EXPORT` audit action. Uses `openpyxl`. Accepts `start`, `end`, `inspector_id` query params. Logs an `EXPORT` audit action. Uses `openpyxl`.
### Dashboard — Grouped Sections
The dashboard cards are organised into two labelled sections separated by a divider rule:
**Inspections section** (all roles see first 2; staff see all 4):
1. Today's Inspections — links to `inspections.index` filtered by today
2. Submitted Today — links to `inspections.index` with `status=completed` + today's date
3. Stale In-Progress — inspections with `status=in_progress` AND `inspection_date < now - 24h`; links to `inspections.index?status=in_progress`
4. Pending Follow-ups — inspections with `follow_up_required=True`; links to `inspections.index?status=follow_up`
**Issues section** (customers see first 3; staff see all 5):
1. Open Issues — `status=open` with severity breakdown badges
2. Issues Opened Today — links to `issues.index` with `date_from=today&date_to=today` (uses the date filter added to `issues.index`)
3. Resolved Today — `status=resolved` + today's date range
4. Pending Verification — `status=pending_verification`
5. Unassigned Open — `status=open` issues with no `assigned_to`
Each card has a subtitle line explaining what it counts. Section dividers use `d-flex align-items-center gap-2` with a `<div style="flex:1;height:1px;background:#e2e8f0;">` rule.
**Inspector Activity table** follows the cards for admin/director/PM: all active inspectors, today's completed inspection count per inspector, progress bar scaled to `max_count`. Green row highlight if count > 0.
### Reports — Navigation & New Pages
The **Reports** main-nav item is positioned second (right after Dashboard). **Scheduled Reports** was removed from the main nav and is now a sub-nav tab inside Reports (visible to admin/director/PM).
All report pages include `{% include 'reports/_subnav.html' %}` as the first element inside `{% block content %}`. The sub-nav tab visibility is role-gated:
| Tab | Roles |
|---|---|
| Overview & Trends | All |
| Issues Aging | All |
| SLA Compliance | All |
| Follow-up Closure | admin, director, project_manager |
| Inspector Performance | admin, director |
| Scheduled Reports | admin, director, project_manager |
### Reports — Phase R1: Issues Aging (`/reports/issues-aging`)
Loads all non-resolved issues scoped by role, groups into five age buckets (`<24h`, `13 days`, `37 days`, `14 weeks`, `>4 weeks`). SLA status computed per-issue via `sla_status()`. Filters: severity, facility (both applied in Python after the main query to avoid double-outerjoin conflicts with customer scope).
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.
### Reports — Phase R2: SLA Compliance (`/reports/sla-compliance`)
Loads resolved issues in the date range, computes `within_sla()` per issue (compares elapsed hours to `SLA_HOURS[severity]`). Produces:
- `overall_pct` — org/scope-wide compliance %
- `by_severity` — dict with `total`, `met`, `pct`, `sla_hours` per severity tier
- `by_facility` — list sorted by compliance % descending
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**.
### Reports — Phase R3: Follow-up Closure (`/reports/followup-closure`)
`@supervisor_required`. Loads inspections with `follow_up_required=True` in date range. Determines which have been re-inspected via a separate `SELECT parent_inspection_id FROM inspections WHERE parent_inspection_id IN (...)` query — avoids iterating the dynamic `follow_ups` relationship.
Annotates each inspection with `insp._has_followup = insp.id in followed_up_ids` (transient Python attribute, not an ORM column).
Excel export: `GET /reports/export/followup-closure` — one sheet with color-coded "Followed Up?" column (green/red).
### Reports — Phase R4: Customer Facility PDF Summary
`GET /reports/facility/<id>/summary-pdf` — available to all roles with facility access (customer scope enforced). Accepts `days` param (30/60/90/180/365; default 90). Calls `generate_facility_summary_pdf()` from `pdf_export.py`. Downloads directly as a PDF attachment.
A **PDF Summary** button was added to `reports/scorecard.html` alongside the existing Full Report and period selector buttons.
### Support Chat — Customer UX ### Support Chat — Customer UX
+8 -1
View File
@@ -10,7 +10,14 @@ A production-grade web application for managing janitorial service contracts, fa
- **Issue Tracking** — Full lifecycle management (open → in-progress → pending verification → resolved) with SLA enforcement, follower subscriptions, resolution photo uploads, and inline quick-assign from the issues list - **Issue Tracking** — Full lifecycle management (open → in-progress → pending verification → resolved) with SLA enforcement, follower subscriptions, resolution photo uploads, and inline quick-assign from the issues list
- **Customer Portal** — Scoped facility visibility for client accounts with invitation-based onboarding; admin enters name and email only, customer chooses their own username and password via a 72-hour emailed link; expired invitation warnings surface on the admin dashboard - **Customer Portal** — Scoped facility visibility for client accounts with invitation-based onboarding; admin enters name and email only, customer chooses their own username and password via a 72-hour emailed link; expired invitation warnings surface on the admin dashboard
- **Notification System** — In-app + email notifications driven by an admin-controlled routing matrix; per-user preferences including digest mode and a one-click "Pause All Emails" toggle - **Notification System** — In-app + email notifications driven by an admin-controlled routing matrix; per-user preferences including digest mode and a one-click "Pause All Emails" toggle
- **Reports** — On-demand PDF/CSV scorecards and scheduled recurring email reports (daily/weekly/monthly) - **Reports & Analytics** — Comprehensive reporting suite accessible from the second nav position:
- *Overview & Trends* — facility scorecards, score trend charts, and PDF/CSV exports
- *Issues Aging* — open issues grouped into age buckets (`<24h``>4 weeks`) with SLA status per issue; Excel export
- *SLA Compliance* — resolved-issue SLA compliance % broken down by severity tier and facility, with progress bars; Excel export (2 sheets)
- *Follow-up Closure Rate* — tracks which flagged inspections received a re-inspection; per-facility closure rates; Excel export
- *Customer Facility PDF Summary* — downloadable PDF report for a facility covering KPIs, area scores, and open issues; accessible from the scorecard page
- *Inspector Performance* — per-inspector KPI summary with Excel export (admin/director only)
- *Scheduled Reports* — recurring email delivery of summary, facility, or issues reports (daily/weekly/monthly)
- **Audit Trail** — Immutable log of every create, update, and delete action with actor and IP capture - **Audit Trail** — Immutable log of every create, update, and delete action with actor and IP capture
- **Support Chat** — Groq AI-powered chatbot for customers with preset FAQ quick-replies; automatic escalation to a ticketing system when the AI cannot resolve the issue; admins manage and reply to tickets at `/support/admin/tickets` with in-app and email notifications on every state change - **Support Chat** — Groq AI-powered chatbot for customers with preset FAQ quick-replies; automatic escalation to a ticketing system when the AI cannot resolve the issue; admins manage and reply to tickets at `/support/admin/tickets` with in-app and email notifications on every state change
- **Inspector Performance Export** — Excel (`.xlsx`) export of the inspector performance summary with a color-coded KPI sheet and a detailed inspection log sheet - **Inspector Performance Export** — Excel (`.xlsx`) export of the inspector performance summary with a color-coded KPI sheet and a detailed inspection log sheet