Jun 26 - Update documents

This commit is contained in:
2026-06-29 16:14:11 -04:00
parent b00bbba2da
commit d0b1b7ae23
2 changed files with 66 additions and 7 deletions
+32 -7
View File
@@ -2,7 +2,7 @@
> **Audience:** AI assistants and developers working on this codebase.
> **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 + dashboard grouped sections + issues/inspections PDF export + date/ID filters + Reports expansion Phases R1R4 + Phase 24 issue_created notify defaults + Phase 25 inspection GPS + Phase 26 issue vendor fields + Phase 27 facility 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; MT-9 iOS pending**)
> **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 + Phase 24 issue_created notify defaults + Phase 25 inspection GPS + Phase 26 issue vendor fields + Phase 27 facility 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 brute-force protection; welcome email on signup; dunning sequence day-3/7/14; MT-9 iOS pending**)
---
@@ -193,8 +193,12 @@ lt_janitorial_quality_control/
│ │ ├── health.py # GET /health/ — monitoring dashboard (tenant status, schema, trials)
│ │ ├── wsgi_panel.py # WSGI entry point — Gunicorn on port 8001
│ │ └── templates/panel/ # base.html, login.html, tenants_list.html, tenant_detail.html, provision.html, health.html
│ └── migrations/ # control Alembic chain (control{N}_…)
│ └── versions/control0001_init.py ← HEAD
│ └── migrations/ # control Alembic chain: control0001_init → control0002_billing → control0003_trial_reminder_sent → control0004_dunning_tracking ← HEAD
│ └── versions/control0001_init.py … control0004_dunning_tracking ← HEAD
├── deploy/
│ └── fail2ban/ # Fail2ban filter + jail configs for login brute-force protection
│ ├── filter.d/jqc-login.conf # Matches WARNING LOGIN_FAILED from app log
│ └── jail.d/jqc.conf # maxretry=5 / findtime=300s / bantime=3600s
└── ...
```
@@ -448,7 +452,7 @@ api_device_tokens: id, user_id, device_id, apns_token, device_name, app_version
| `inspections` | `/inspections` | list, start, execute, view, PDF export, flag-issue, save-draft (AJAX), flag-followup, reinspect, upload-photo (AJAX) |
| `templates` | `/templates` | list, create, edit, delete, form editor, preview |
| `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), trial-reminders (cron), dunning-reminders (cron) |
| `audit` | `/audit` | list (admin only), view, purge |
| `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 (accessible via Reports sub-nav) |
@@ -661,6 +665,8 @@ EVENT_SCORE_ALERT = 'score_alert' ← Phase 27
| `POST /notifications/check-sla` | SLA breach/at-risk alerts | `*/30 * * * *` |
| `POST /notifications/cleanup-tokens` | Purge expired API tokens | `0 3 * * *` |
| `POST /notifications/check-score-trends` | Facility score drop alerts (Phase 27) | `0 8 * * *` |
| `POST /notifications/trial-reminders` | Trial-ending warning emails (≤3 days left) | `0 9 * * *` |
| `POST /notifications/dunning-reminders` | Payment-failure escalation emails (day 3/7/14) | `0 10 * * *` |
---
@@ -1112,6 +1118,10 @@ set -a; . /etc/jqc/control.env; set +a
-d "secret=SECRET"
0 8 * * * curl -s -X POST https://your-domain.com/notifications/check-score-trends \
-d "token=SECRET"
0 9 * * * curl -s -X POST https://your-domain.com/notifications/trial-reminders \
-d "token=SECRET"
0 10 * * * curl -s -X POST https://your-domain.com/notifications/dunning-reminders \
-d "token=SECRET"
```
---
@@ -1389,7 +1399,7 @@ Stripe-backed subscription billing. Controlled by `BILLING_ENABLED` env var (def
### Trial period
- New tenants provisioned via `create_tenant()` get `subscription_status='trial'`, `trial_ends_at = now + 14 days` by default.
- Self-service signup (`/signup`) provisions a tenant immediately with a 14-day trial.
- Self-service signup (`/signup`) provisions a tenant immediately with a 14-day trial and sends a `welcome` email.
- Trial enforcement is in `_billing_gate()` — no Stripe required until they subscribe.
### Billing emails (`app/billing/emails.py`)
@@ -1398,12 +1408,27 @@ Stripe-backed subscription billing. Controlled by `BILLING_ENABLED` env var (def
| `event_type` | Trigger | Required context keys |
|---|---|---|
| `payment_failed` | `invoice.payment_failed` Stripe webhook | `portal_url` |
| `trial_ending` | Cron (not yet wired — see §11 cron table) | `trial_ends_at`, `subscribe_url` |
| `welcome` | `POST /signup` success | `tenant_name`, `login_url`, `trial_days`, `trial_ends_at`, `plan_name` |
| `payment_failed` | `invoice.payment_failed` Stripe webhook (day 0) | `portal_url` |
| `payment_reminder` | Dunning cron (day 3 + day 7) | `portal_url`, `tenant_name`, `days_overdue` |
| `payment_final` | Dunning cron (day 14) | `portal_url`, `tenant_name`, `days_overdue` |
| `trial_ending` | Cron `/notifications/trial-reminders` | `trial_ends_at`, `subscribe_url`, `days_left`, `tenant_name` |
| `subscription_cancelled` | `customer.subscription.deleted` Stripe webhook | `portal_url` |
HTML templates live in `app/templates/billing/email/`. `base.html` provides the branded layout; each event type extends it.
### Dunning sequence
Three `Tenant` columns track payment-failure escalation state:
| Column | Type | Purpose |
|---|---|---|
| `past_due_since` | `DATETIME NULL` | Set when payment first fails (webhook `_on_payment_failed`). Reset to `NULL` on recovery. |
| `dunning_stage` | `TINYINT DEFAULT 0` | 0=none, 1=day-3 sent, 2=day-7 sent, 3=day-14 sent. Reset to 0 on recovery. |
| `dunning_sent_at` | `DATETIME NULL` | Timestamp of the last dunning email. Reset to `NULL` on recovery. |
Cron endpoint `POST /notifications/dunning-reminders` runs daily, checks `elapsed = now - past_due_since`, and advances the stage if behind schedule. Migration: `control0004_dunning_tracking`.
### Plan seeding
```bash