Jul 8 - Update documents

This commit is contained in:
2026-07-08 16:25:35 -04:00
parent 2674ccbab4
commit 97a559d5c0
5 changed files with 198 additions and 7 deletions
+18 -4
View File
@@ -7,9 +7,11 @@ A production-grade web application for managing janitorial service contracts, fa
## Features
- **Inspection Management** — Execute structured inspections against configurable templates with a drag-and-drop form builder supporting ratings, pass/fail, photos, signatures, and free-form fields. Starting an inspection requires only a Template and Facility selection.
- **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
- **Scheduled Inspections** — Plan one-time or recurring (daily/weekly/monthly) inspection assignments per facility/template/inspector with a due date. The assigned inspector is notified on assignment, reminded the day before and on the due date, and managers are alerted on overdue; completing a linked inspection rolls recurring schedules forward automatically. Upcoming/overdue panel on the dashboard.
- **Issue Tracking** — Full lifecycle management (open → in-progress → pending verification → resolved) with SLA enforcement, follower subscriptions, resolution photo uploads, and inline quick-assign. Each issue records **who handles it** — our staff, the facility's own staff, or an external vendor — while always keeping one of our staff as the internal follow-up owner
- **Facility QR Codes** — Each facility has a printable QR code (single or bulk print sheet) linking to a login-free, occupant-friendly status page showing recent cleaning quality and a "Report a Problem" form that files an issue directly; token-addressed and rate-limited
- **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, plus optional per-contract additional recipients (staff users or external emails) for chosen events; per-user preferences including digest mode and a one-click "Pause All Emails" toggle
- **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
@@ -48,7 +50,7 @@ A production-grade web application for managing janitorial service contracts, fa
## Prerequisites
- Python 3.11+
- Python 3.12+ (several route files use nested same-quote f-strings that require 3.12)
- MySQL 5.7+ (or 8.0+)
- A configured SMTP server (port 465 or 587)
@@ -158,6 +160,8 @@ server {
}
```
> **Reverse proxy:** the app wraps its WSGI stack in `ProxyFix` (trusting one proxy hop), so it reads the real client IP and scheme from the `X-Forwarded-For` / `X-Forwarded-Proto` headers Nginx sets above. This is required for correct per-client rate limiting and `https://` external links. Do not remove those `proxy_set_header` lines.
### Systemd service (example)
```ini
@@ -180,13 +184,17 @@ WantedBy=multi-user.target
## Cron Jobs
Four background tasks require scheduled execution. All endpoints that require a token use `DIGEST_SECRET`.
Background tasks require scheduled execution. All endpoints that require a token use `DIGEST_SECRET`.
```bash
# SLA alerts — every 30 minutes
*/30 * * * * curl -s -X POST "https://your-domain.com/notifications/check-sla" \
-d "token=YOUR_DIGEST_SECRET"
# Scheduled inspection reminders (advance/due to inspector, overdue to managers) — every 30 minutes
*/30 * * * * curl -s -X POST "https://your-domain.com/scheduled-inspections/run" \
-d "token=YOUR_DIGEST_SECRET"
# Daily digest emails — 7:00 AM
0 7 * * * curl -s -X POST "https://your-domain.com/notifications/send-digest" \
-d "token=YOUR_DIGEST_SECRET&frequency=daily"
@@ -198,6 +206,10 @@ Four background tasks require scheduled execution. All endpoints that require a
# Scheduled report delivery — 8:00 AM
0 8 * * * curl -s -X POST "https://your-domain.com/scheduled-reports/run" \
-d "secret=YOUR_DIGEST_SECRET"
# Facility score-drop trend alerts — 8:00 AM
0 8 * * * curl -s -X POST "https://your-domain.com/notifications/check-score-trends" \
-d "token=YOUR_DIGEST_SECRET"
```
---
@@ -274,6 +286,7 @@ flask db downgrade
- **ENUM changes** require three steps: expand → migrate data → contract. Never skip steps.
- **`CREATE INDEX IF NOT EXISTS`** is not supported on MySQL < 8.0.1. Use `information_schema.statistics` existence checks instead — see `phase12_performance_indexes.py` for the reusable `_index_exists()` helper pattern.
- **Migration `revision` ids must be ≤ 32 characters** — Alembic's `alembic_version.version_num` column is `VARCHAR(32)`. A longer id passes the DDL step but fails when Alembic writes the version row (`Data too long for column 'version_num'`). Keep the `revision = '...'` value short even if the filename is long.
---
@@ -304,6 +317,7 @@ flask db downgrade
| `REDIS_URL` | — | Redis connection URI for shared rate-limit storage; optional but recommended in production |
| `GROQ_API_KEY` | — | Groq API key. When absent the AI chatbot is disabled; customers can still submit support tickets. |
| `GROQ_MODEL` | `llama-3.3-70b-versatile` | Groq model ID override |
| `GOOGLE_MAPS_API_KEY` | `""` | Optional. Enables the Google Maps embed of inspection GPS coordinates on the inspection detail page (admin/director). |
---