docs: scrub SiteReport from CLAUDE.md + park rebuild (capture doc)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-05-17 02:11:37 +02:00
parent 120f21d645
commit e71109d27e
2 changed files with 57 additions and 87 deletions

View File

@ -11,14 +11,17 @@ Konrad verified 17 May 2026). `origin/ai-dev` HEAD `80d96d7` == prod
(the only delta over the functional tip `4c25011` is doc breadcrumbs).
Migrations `0016`/`0017` applied; `static/css/custom.css` collected.
**πŸ”§ In progress β€” local only, NOT pushed:** removal of the
"Log Today's Work" / **SiteReport** feature (Konrad wants to rethink
it from scratch separately β€” work mix is shifting). Designed +
planned; executes under a HARD STOP (destructive migration
`0018_delete_sitereport` on the daily-use attendance path) β€” nothing
reaches origin until Konrad verifies locally. See the SiteReport
entry in `docs/plans/parked-work.md` + the capture doc
`docs/plans/2026-05-17-site-report-removed-capture.md`.
**πŸ”§ In progress β€” local only, NOT pushed (HARD STOP):** removal of
the "Log Today's Work" / **SiteReport** feature (Konrad wants to
rethink it from scratch separately β€” work mix is shifting).
**Implemented locally β€” Tasks 1-3 complete:** model/table/UI/routes
deleted, migration `0018_delete_sitereport` drops `core_sitereport`,
post-attendance flow now returns to the dashboard, suite **193 OK**.
Still un-pushed and under a HARD STOP β€” nothing reaches origin until
Konrad verifies locally (destructive migration on the daily-use
attendance path). Design knowledge preserved for a future rebuild in
the capture doc `docs/plans/2026-05-17-site-report-removed-capture.md`;
see also the parked rebuild entry in `docs/plans/parked-work.md`.
**🧊 Backburner β€” do NOT start in `ai-dev`:** Phase A.2 (manual
JournalEntry UI) and Phase B (Letterly inbound webhook) are
@ -94,7 +97,6 @@ staticfiles/ β€” Collected static assets (Bootstrap, admin) β€” NOT in git (
- **ExpenseReceipt / ExpenseLineItem** β€” business expense records with VAT handling
- **WorkerCertificate** β€” per-worker certifications (Skills, PDP, First Aid, Medical, Work at Height) with `valid_until` expiry and optional document upload. Unique per (worker, cert_type). Has `is_expired` and `expires_soon` (≀30 days) properties.
- **WorkerWarning** β€” disciplinary records per worker with severity (verbal/written/final), reason, optional document. Ordered -date.
- **SiteReport** β€” optional 1:1 with `WorkLog`, captures what was DONE on site that day: weather, temperature_min/max (Β°C, IntegerField), free-form `notes`, and a flexible `metrics` JSONField with shape `{'counts': {key: int}, 'checks': {key: bool}}`. The metric KEYS live in `core/site_report_schema.py` (NOT in the model) β€” see the "SiteReport metric schema" section below for the rationale + how to add a new metric without a migration. Reverse accessor: `work_log.site_report` (1:1, raises DoesNotExist when absent β€” wrap with try/except or use `WorkLog.objects.filter(site_report__isnull=False)`).
- **Absence** β€” per-worker dated record of a day not worked. 8 reason choices (Sick, Family Responsibility, Annual Leave, Personal/Unpaid Leave, Injury on Duty, Suspension, Absconded, Other). Optional `project` FK (SET_NULL). `is_paid` boolean (default False) β€” when ticked, the save flow auto-creates a Bonus PayrollAdjustment via `_sync_absence_payroll_adjustment(absence)` helper, inheriting the absence's project for cost-attribution. Linked via OneToOneField (`payroll_adjustment`). Unique per (worker, date) at DB layer. Permission scoping: admin (all) or supervisor (workers in their teams).
### Schema name-drifts to remember
@ -172,45 +174,16 @@ the generated migration. Precedent `0012`; this feature added `0017`
- Loans have automated repayment deductions during payroll processing
- Cascading deletes use SET_NULL for supervisors/teams to preserve historical data
## SiteReport metric schema (Apr 2026) β€” flexible JSON, single Python source
## SiteReport / "Log Today's Work" β€” REMOVED 17 May 2026
**Why this pattern exists:** `SiteReport.metrics` is a `JSONField` with
shape `{'counts': {key: int}, 'checks': {key: bool}}`. The KEYS aren't
modelled as columns β€” they live in a single Python file
`core/site_report_schema.py`. To add a new metric (e.g. `cables_pulled`),
append one dict to `COUNT_METRICS` or `CHECK_METRICS` and redeploy. **No
database migration required.** The form auto-renders the new field; old
reports without that key just show 0 / unchecked.
**Why that's safe:**
- The form (`SiteReportForm` in `core/forms.py`) iterates the schema
lists at `__init__` time and builds dynamic `IntegerField` /
`BooleanField` per metric. Form state ↔ JSON blob via `save()`.
- Old data is never touched. Removing a metric from the schema means
the form stops rendering it; the JSON still contains the historic
value. `label_for(key)` falls back to the snake_case key when a
retired metric is shown on the detail page.
- The metric LABEL is rendered via `label_for(key)` (in
`core/site_report_schema.py`) so renaming a label is also a one-line
edit (and **doesn't break old data** because the key is unchanged).
**What to NEVER do:** rename a metric `key` that already has data β€”
historic reports will silently lose their value for that metric. If a
key MUST change, write a one-off Django data migration that walks
every `SiteReport` and renames the JSON key.
**Where the metric KEYS show up:**
- `core/site_report_schema.py` β€” the source of truth (COUNT_METRICS, CHECK_METRICS, helpers)
- `core/forms.py::SiteReportForm.__init__` β€” reads the lists, builds dynamic form fields
- `core/forms.py::SiteReportForm.save` β€” serializes form data into the JSON blob
- `core/templates/core/site_report_edit.html` β€” iterates `count_field_pairs` / `check_field_pairs` from the view
- `core/templates/core/site_report_detail.html` β€” iterates `counts_display` / `checks_display` from the view
**The two-step flow:** after `attendance_log` POST creates one or more
WorkLogs, the view redirects to `site_report_edit` for the most recent
log. The form has a "Skip" link to home β€” site reports are entirely
optional. WorkLogs without a SiteReport are completely valid historic
rows; they just don't show progress data on `/history/`.
**SiteReport / "Log Today's Work" β€” REMOVED 17 May 2026.** Feature
deleted (model/table/UI/routes; migration `0018_delete_sitereport`).
To be rebuilt from scratch later β€” see
`docs/plans/2026-05-17-site-report-removed-capture.md`, which preserves
the schema-as-Python design (flexible `metrics` JSONField, single
Python source of truth, no-migration metric adds) for the future
rebuild. Nothing site-report-related exists in the working app; the
post-attendance flow now simply returns to the dashboard.
## Absence-to-PayrollAdjustment cascade (May 2026)
@ -237,7 +210,7 @@ Edit / delete cascades:
The "Submit + Log Absences" button on `/attendance/log/` lets admins
jump from logging attendance straight to `/absences/log/` pre-filled
with the same date, team, and project. Uses `next_action=log_absences`
POST param; default Submit keeps the existing SiteReport redirect.
POST param; default Submit returns to the dashboard.
Permission scoping helper: `_absence_user_queryset(user)` in `core/views.py`
is the single authority for "which absences can this user see/touch". Admin
@ -429,8 +402,6 @@ numbers on hot pages.
| `/attendance/log/` | `attendance_log` | Log daily work with date range support |
| `/history/` | `work_history` | Work logs table with filters. Query params: `?worker=`, `?project=`, `?team=` (digit = WorkLog.team FK match; `none` = logs with no team set), `?status=paid|unpaid`. CSV export at `/history/export/` honors the same filters. |
| `/history/export/` | `export_work_log_csv` | Download filtered logs as CSV |
| `/site-report/<work_log_id>/edit/` | `site_report_edit` | Create-or-update the optional SiteReport for a WorkLog (auto-redirected here after `/attendance/log/` POST) |
| `/site-report/<work_log_id>/` | `site_report_detail` | Read-only view of the SiteReport (404 if none β€” use the edit URL to create) |
| `/absences/log/` | `absence_log` | Admin/supervisor: log absences (date range, multi-worker). Reads `date`, `team`, `project` GET params for prefill from /attendance/log/'s "Submit + Log Absences" shortcut. |
| `/absences/log/confirm/` | `absence_log_confirm` | Yellow conflict-warning page; per-row Remove-from-WorkLog checkboxes; reads pending data from session. |
| `/absences/` | `absence_list` | Filtered list with pagination. Multi-select reason filter (`?reason=sick&reason=iod` etc.). Direct `project_id` filter. |

View File

@ -9,29 +9,22 @@
## ⏸ Paused β€” ready to execute (not started, not pushed)
### Post-Attendance Flow v2
### Site-progress logging β€” rebuild from scratch (parked)
**Status:** Brainstormed + designed + planned, **approved by Konrad**,
execution paused (Konrad's call, 15 May 2026). Design doc
`docs/plans/2026-05-15-post-attendance-flow-v2-design.md` (local
commit `110545b`), plan `docs/plans/2026-05-15-post-attendance-flow-v2-plan.md`
(local commit `29c36be`). **These 2 commits are local-only on
`ai-dev`, NOT pushed to origin** β€” Konrad wants nothing reaching the
working app until he's verified the flow locally.
The SiteReport / "Log Today's Work" feature was **removed 17 May
2026** (Konrad's call β€” work mix shifting, scope uncertain). The
post-attendance flow now simply returns to the dashboard. A future
rebuild starts fresh β€” see
`docs/plans/2026-05-17-site-report-removed-capture.md` (preserves the
schema-as-Python pattern, recovery pointers, and the now-superseded
`2026-05-15-post-attendance-flow-v2-*` prior thinking, which stays on
disk).
**What it does:** Replaces the forced post-attendance SiteReport
redirect with 3 explicit buttons (Log Work β†’ dashboard / + Site
Journal / + Absences) + a "Save Site Journal + Add Absences" button
on the journal page. Renames user-facing "Site Report" β†’ "Site
Journal" (display-only, Path-A β€” frees "Journal" for the parked
voice feature, which must now be called "Voice Notes").
**To resume:** new or same session β†’ "execute the
post-attendance-flow-v2 plan". 4 tiny TDD tasks (~120 LOC), reuses
the proven Round C `next_action` pattern. **HARD STOP after Task 4
β€” Konrad runs the manual verification checklist (in the design doc)
locally and explicitly approves BEFORE any push.** No migrations /
collectstatic β€” pure template + view change.
**Removal status (local only, HARD STOP β€” not pushed):** Tasks 1-3
done β€” model/table/UI/routes deleted, migration
`0018_delete_sitereport` drops `core_sitereport`, suite **193 OK**.
Un-pushed pending Konrad's local verification (destructive migration
on the daily-use attendance path).
---
@ -121,19 +114,28 @@ the 36-commit push `d7015b9..4c25011`.
investigate a possible date/locale or response-rendering
nondeterminism in that test. **NOT introduced by this feature.**
> Note: the **Post-Attendance Flow v2** paused entry above is STILL
> paused / unchanged β€” this Manager/Salaried entry does not affect
> it.
> Note: the **Site-progress logging β€” rebuild from scratch** parked
> entry above is unaffected by this Manager/Salaried entry (it was
> superseded separately by the 17 May 2026 SiteReport removal).
---
## Production status β€” βœ… fully caught up (15 May 2026)
Production (`https://foxlog.flatlogic.app/`) is deployed at
`origin/ai-dev` HEAD **`1d224bc`**. Everything is live: SiteReport
+ Absences feature, all UX polish, the team filters, the
`origin/ai-dev` HEAD **`1d224bc`**. Everything is live: the original
SiteReport + Absences feature, all UX polish, the team filters, the
dashboard/report number audit (18 findings), and the
template-comment + subline-clarity fixes.
template-comment + subline-clarity fixes. (The 17 May Manager/
Salaried bundle has since shipped too β€” see the "Shipped & live"
section above.)
**In-progress local-only work (HARD STOP β€” not pushed):** the
SiteReport / "Log Today's Work" removal β€” Tasks 1-3 done, suite
**193 OK**, migration `0018_delete_sitereport` drops the table.
Un-pushed pending Konrad's local verify; see the "Site-progress
logging β€” rebuild from scratch (parked)" entry above + the capture
doc `docs/plans/2026-05-17-site-report-removed-capture.md`.
**Deploy-ordering lesson learned (now in CLAUDE.md):** production
runs `DEBUG=False` β†’ Django's cached template loader holds compiled
@ -202,16 +204,13 @@ revisits.
## Defaulted (not blocking β€” flag if you disagree)
From Q9, Q4 of the Site Work Logging brainstorm:
- **Q9 β€” photos on site reports.** Deferred to v2 of SiteReport.
Construction supervisors often want to attach a phone photo of
"plinths cast today" but it adds ~50 LOC + storage handling +
thumbnail rendering. v1 ships without.
- **Q4 β€” per-project metric templates.** Same metric set for all
projects in v1. If/when a non-solar-farm project lands and the
metrics diverge wildly, we add a `MetricTemplate` model. YAGNI
for now β€” `core/site_report_schema.py` is one Python file edit.
The Q9 (photos on site reports) and Q4 (per-project metric
templates) defaults from the Site Work Logging brainstorm are now
**obsolete** β€” the SiteReport feature was removed 17 May 2026. Both
were open design considerations for that feature; they are captured
(along with the rest of the design rationale) in
`docs/plans/2026-05-17-site-report-removed-capture.md` for whoever
rebuilds site-progress logging from scratch.
---