Jun 26 - Update documents
This commit is contained in:
@@ -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 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 + **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 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 + **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
|
||||
|
||||
@@ -186,6 +186,27 @@ ufw enable
|
||||
ufw status
|
||||
```
|
||||
|
||||
### 1.5b Install Fail2ban (brute-force protection)
|
||||
|
||||
```bash
|
||||
apt install -y fail2ban
|
||||
|
||||
# Copy the JQC filter and jail configs from the repository
|
||||
cp /home/jqc/deploy/fail2ban/filter.d/jqc-login.conf /etc/fail2ban/filter.d/
|
||||
cp /home/jqc/deploy/fail2ban/jail.d/jqc.conf /etc/fail2ban/jail.d/
|
||||
|
||||
# Confirm logpath in jqc.conf matches your actual log file
|
||||
# Default is /var/www/jqc/logs/jqc.log — update if your path differs:
|
||||
# sed -i 's|/var/www/jqc/logs/jqc.log|/home/jqc/logs/jqc.log|g' /etc/fail2ban/jail.d/jqc.conf
|
||||
|
||||
systemctl enable fail2ban
|
||||
systemctl restart fail2ban
|
||||
|
||||
# Verify the jail is active
|
||||
fail2ban-client status jqc-login
|
||||
# Expected: "Status for the jail: jqc-login" with Banned IP counts
|
||||
```
|
||||
|
||||
### 1.6 Create the `jqc` system user
|
||||
|
||||
```bash
|
||||
@@ -1206,6 +1227,18 @@ SHELL=/bin/bash
|
||||
0 3 * * * curl -s -X POST https://YOUR_DOMAIN/notifications/cleanup-tokens \
|
||||
-d "token=YOUR_DIGEST_SECRET" >> /home/jqc/logs/cron.log 2>&1
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Trial-ending reminder emails — 9:00 AM Eastern
|
||||
# ----------------------------------------------------------------
|
||||
0 9 * * * curl -s -X POST https://YOUR_DOMAIN/notifications/trial-reminders \
|
||||
-d "token=YOUR_DIGEST_SECRET" >> /home/jqc/logs/cron.log 2>&1
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Payment dunning reminders (day 3 / 7 / 14 escalation) — 10:00 AM Eastern
|
||||
# ----------------------------------------------------------------
|
||||
0 10 * * * curl -s -X POST https://YOUR_DOMAIN/notifications/dunning-reminders \
|
||||
-d "token=YOUR_DIGEST_SECRET" >> /home/jqc/logs/cron.log 2>&1
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Nightly database backup — 2:00 AM Eastern
|
||||
# ----------------------------------------------------------------
|
||||
@@ -1384,6 +1417,7 @@ Work through this list after DNS propagation is confirmed. Check each item in th
|
||||
- [ ] Log rotation is working: `/home/jqc/logs/` is not filling up unexpectedly
|
||||
- [ ] First nightly backup completed (check `/var/backups/jqc/` the morning after cutover)
|
||||
- [ ] Firewall is active: `ufw status` shows correct rules
|
||||
- [ ] Fail2ban is active: `fail2ban-client status jqc-login` shows the jail running
|
||||
|
||||
### Decommission old server (after 48 hours)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user