05/08 Updated code: fixed some issues
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:** May 2026 (Phase B complete — iPad offline inspection app)
|
||||
> **Last reviewed:** May 2026 (Phase B complete — iPad offline inspection app; Critical/Notable hardening pass)
|
||||
|
||||
---
|
||||
|
||||
@@ -618,7 +618,9 @@ limiter = Limiter(
|
||||
```
|
||||
phase1_projects_roles → phase6_features → phase7_mobile_api → phase8_notification_matrix
|
||||
→ phase9_user_full_name → phase10_customer_password_setup → phase11_director_role
|
||||
→ phase12_performance_indexes → phase_b_mobile_local_id ← HEAD
|
||||
→ phase12_performance_indexes → phase_b_mobile_local_id
|
||||
→ phase13_issue_facility → phase14_facility_created_at
|
||||
→ phase15_audit_log_indexes ← HEAD
|
||||
```
|
||||
|
||||
### phase_b_mobile_local_id
|
||||
@@ -626,6 +628,21 @@ phase1_projects_roles → phase6_features → phase7_mobile_api → phase8_notif
|
||||
Adds `mobile_local_id VARCHAR(64) NULL` + index to both `inspections` and `issues`.
|
||||
Uses `INFORMATION_SCHEMA.COLUMNS` and `INFORMATION_SCHEMA.STATISTICS` existence checks — safe to re-run.
|
||||
|
||||
### phase13_issue_facility
|
||||
|
||||
Adds nullable `facility_id` FK column to `issues`; back-fills from `areas.facility_id`; makes `area_id` nullable.
|
||||
Uses direct `ALTER TABLE` + `INFORMATION_SCHEMA` checks — safe to re-run.
|
||||
|
||||
### phase14_facility_created_at
|
||||
|
||||
Adds nullable `created_at` `DATETIME` column to `facilities`.
|
||||
Uses direct `ALTER TABLE` + `INFORMATION_SCHEMA` check — safe to re-run.
|
||||
|
||||
### phase15_audit_log_indexes
|
||||
|
||||
Adds individual indexes on `audit_logs.action` and `audit_logs.entity_type`.
|
||||
Uses `INFORMATION_SCHEMA.STATISTICS` existence checks — safe to re-run.
|
||||
|
||||
### MySQL ENUM Change Protocol (3 steps — always follow)
|
||||
```sql
|
||||
-- 1. Expand
|
||||
@@ -748,6 +765,9 @@ timeout = 30
|
||||
| 28 | **`hmac.compare_digest()` for token comparison** | Prevents timing oracle attacks |
|
||||
| 29 | **`get_customer_scope()` uses bulk project query** | Replaces per-assignment loop |
|
||||
| 30 | **CSV exports always call `log_action(ACTION_EXPORT, ...)`** | Data exports are compliance-relevant audit events |
|
||||
| 31 | **Do NOT add an explicit `Issue.area` relationship** | `Area.issues` declares `backref='area'`, supplying `Issue.area` automatically. A second declaration on `Issue` raises `ConflictingBackreferences` at startup. The dependency is documented here; do not "fix" it by adding an explicit relationship. |
|
||||
| 32 | **Do not sync an issue when its parent `LocalInspection.syncStatus == "failed"`** | Submitting without `inspection_id` creates orphaned server records; mark issue `"failed"` instead |
|
||||
| 33 | **f-string fallback strings must use double-quotes inside single-quoted f-strings** | Python 3.11 raises `SyntaxError` on nested same-delimiter quotes; use `"\u2014"` not `'—'` inside `f'...'` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ class Issue(db.Model):
|
||||
mobile_local_id = db.Column(db.String(64), nullable=True, index=True) # idempotency key for mobile submissions
|
||||
|
||||
# Relationships
|
||||
# NOTE: Issue.area is provided by the backref on Area.issues (facility.py).
|
||||
# Do NOT add a second explicit db.relationship('Area') here — it conflicts
|
||||
# with that backref at mapper configuration time (CLAUDE.md rule 31 revised).
|
||||
facility = db.relationship('Facility', foreign_keys=[facility_id], backref='direct_issues')
|
||||
assigned_user = db.relationship('User', foreign_keys=[assigned_to], backref='assigned_issues')
|
||||
verifier = db.relationship('User', foreign_keys=[verified_by], backref='verified_issues')
|
||||
|
||||
+4
-2
@@ -137,10 +137,12 @@ def send_sla_alerts():
|
||||
hrs = sla_hours_remaining(issue)
|
||||
deadline = sla_deadline(issue)
|
||||
|
||||
facility_name = issue.resolved_facility.name if issue.resolved_facility else "\u2014"
|
||||
|
||||
if status == 'breached':
|
||||
title = f'🚨 SLA Breached — Issue #{issue.id} ({issue.severity.title()})'
|
||||
body = (
|
||||
f'Issue #{issue.id} at {issue.resolved_facility.name if issue.resolved_facility else '—'} '
|
||||
f'Issue #{issue.id} at {facility_name} '
|
||||
f'has breached its SLA deadline. '
|
||||
f'Severity: {issue.severity.title()}. '
|
||||
f'Deadline was {deadline.strftime("%Y-%m-%d %H:%M") if deadline else "N/A"}. '
|
||||
@@ -149,7 +151,7 @@ def send_sla_alerts():
|
||||
else: # at_risk
|
||||
title = f'⚠️ SLA At Risk — Issue #{issue.id} ({issue.severity.title()})'
|
||||
body = (
|
||||
f'Issue #{issue.id} at {issue.resolved_facility.name if issue.resolved_facility else '—'} '
|
||||
f'Issue #{issue.id} at {facility_name} '
|
||||
f'is approaching its SLA deadline with approximately '
|
||||
f'{abs(hrs):.1f}h remaining. '
|
||||
f'Severity: {issue.severity.title()}. '
|
||||
|
||||
Reference in New Issue
Block a user