backfill button and usage
Build and Push Docker Image / build (push) Successful in 16s

This commit is contained in:
2026-05-19 09:29:41 -05:00
parent 6ddc09aa71
commit 2d4920bd15
7 changed files with 171 additions and 5 deletions
+41
View File
@@ -158,6 +158,7 @@ Useful for showing the app to stakeholders without exposing live employee data.
- PDF download for any historical violation record
- **Notes & Flags** — free-text notes (e.g. "on PIP", "union member") with quick-add tag buttons; visible in the profile modal without affecting scoring
- **Point Expiration Timeline** — shows when each active violation rolls off the 90-day window, with a progress bar, days-remaining countdown, and projected tier-drop indicators
- **↻ Backfill Snapshots** button (next to the Active Violations header) — manually rebuilds the `prior_active_points` snapshot on every violation for this employee. Use after back-dating a violation under older code, or any time a regenerated PDF shows stale prior-point totals. Audit-logged as `violation_snapshots_recomputed` with reason `manual_backfill`. See [Backfilling Prior-Points Snapshots](#backfilling-prior-points-snapshots) below.
- **Toast notifications** for all actions: negate, restore, delete, amend, PDF download, employee edit
### Audit Log
@@ -208,6 +209,45 @@ Scores are computed over a **rolling 90-day window** (negated violations exclude
- Filename: `CPAS_<EmployeeName>_<IncidentDate>.pdf`
- PDF captures prior active points **at the time of the incident** (snapshot stored on insert)
- **Acknowledgment rendering**: if the violation has an `acknowledged_by` value, the employee signature block on the PDF shows the recorded name and date with an "Acknowledged" badge; otherwise, blank signature lines are rendered for wet-ink signing
- **Back-dated inserts** auto-refresh the snapshot on downstream violations whose 90-day prior window now includes the new earlier event (handled inside the insert transaction by `recomputeSnapshotsAfter()`). If a back-date happened under older code that lacked this auto-refresh, use the **↻ Backfill Snapshots** button in the Employee Profile Modal — see [Backfilling Prior-Points Snapshots](#backfilling-prior-points-snapshots).
---
## Backfilling Prior-Points Snapshots
Each violation stores a `prior_active_points` snapshot at insert time so its PDF always reflects the score *as it was on the incident date* (and stays stable through later negate/restore actions). Normally you never touch this column.
There is one situation where the snapshot can drift from current truth: a violation was back-dated *before* `recomputeSnapshotsAfter()` shipped (commit `e2c352d`), so the auto-refresh never ran on the violations that now sit inside its 90-day window. Symptom: re-downloading the PDF for the newer violation shows "Prior Active Points: 0" even though an earlier active violation clearly exists in the timeline.
**To fix:**
1. Open the affected employee's profile modal.
2. Click **↻ Backfill Snapshots** next to the **Active Violations** header.
3. Confirm the prompt. A toast reports `Updated X of Y snapshot(s)` or `Snapshots already up to date`.
4. Re-download the PDFs — they now reflect the corrected prior totals.
**What it does, exactly:**
- Iterates every violation belonging to that employee (active *and* negated).
- Recomputes each row's `prior_active_points` using the current set of non-negated violations in the 90 days before its `incident_date`.
- Writes only the rows that actually changed and reports the diff.
- Runs inside a single transaction.
- Writes one `violation_snapshots_recomputed` entry to the audit log with `reason: "manual_backfill"` and the per-row before/after values.
**When *not* to use it:**
- After a negate, restore, amend, or hard delete in normal workflow. The auto-managed snapshot is correct in those cases by design (PDFs are intentionally stable through negate/restore).
- As a routine maintenance step. It's a targeted repair tool, not a recurring task. If you find yourself reaching for it after normal back-dated inserts, file a bug — the auto-recompute should already be handling those.
**API endpoint:** `POST /api/employees/:id/recompute-snapshots`
Response shape:
```json
{ "success": true, "scanned": 2, "updated": 1, "changes": [
{ "id": 47, "incident_date": "2026-04-02", "old": 0, "new": 3 }
]}
```
---
@@ -222,6 +262,7 @@ Scores are computed over a **rolling 90-day window** (negated violations exclude
| PATCH | `/api/employees/:id` | Edit name, department, supervisor, or notes |
| PATCH | `/api/employees/:id/notes` | Save employee notes only (shorthand) |
| POST | `/api/employees/:id/merge` | Merge duplicate employee; reassigns all violations |
| POST | `/api/employees/:id/recompute-snapshots` | Manual backfill — rebuild `prior_active_points` on every violation for this employee. See [Backfilling Prior-Points Snapshots](#backfilling-prior-points-snapshots) |
| GET | `/api/employees/:id/score` | Get active CPAS score for employee |
| GET | `/api/employees/:id/expiration` | Active violation roll-off timeline with days remaining |
| GET | `/api/employees/:id/violation-counts` | 90-day non-negated counts grouped by violation type |