CLAUDE.md breadcrumb: 'subsequent UX polish' → '6 subsequent
commits' so the next session can see at a glance how much is
pending pull-and-restart on production.
parked-work.md:
- 'Small polish follow-ups' section: 7 items cleared on 15 May;
section header retained as a landing pad for future cleanups.
- 'Pending pull-and-restart' table: added rows for 70fa085
(day-name in modal) and d1d3e15 (polish pass) so the deploy
checklist is current.
- 'Recently shipped' grew two new entries at the top: the polish
pass and the day-name modal change.
CLAUDE.md changes:
- 'What's mid-flight' breadcrumb updated: SiteReport/Absences
migrations are LIVE on prod; only the 4 latest UX commits await
a pull-and-restart (no migration / collectstatic needed).
- URL Routes table entries for /workers/ and /history/ now document
the new ?team= filter (and team=none for unassigned / no-team cases).
- Worker Management UI inline description mentions the team filter
+ Absences tab on the worker detail page.
- Two new Coding Style gotchas captured: (1) Bootstrap dropdowns
inside .card elements get clipped by sibling cards — fix is to
lift the wrapping card with position:relative + z-index;
(2) JS reading from data-worker-id was unreliable on production —
read input[name="workers"][value] directly (the attendance-form
pattern that's been working for years).
parked-work.md changes:
- Pending-deploy section rewritten: the BIG deploy (migrations +
collectstatic) is DONE; only 4 small commits await a pull +
service restart.
- 'Recently shipped' grew two new entries: the team filters on
/workers/ + /history/, and the two absences UX polish fixes.
- Updated timestamp to 15 May 2026.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Worker Absences feature shipped (bf6f0a5..27fe05e), so it's no
longer the active queue item. Promoted the pending production
deploy (run /run-migrate/, collectstatic, restart service) to the
top of parked-work.md — production /history/ is 500ing until those
migrations run. CLAUDE.md breadcrumb updated to flag this as the
next operator action when a fresh session starts.
Also captured the small polish follow-ups from the absences code
reviews (AbsenceQuickForm dead code, N+1 in team_workers_map,
duplicated CSV filter block, etc.) so they don't get lost in a
future janitorial pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the deferred work (Phase A.2 manual JournalEntry UI,
Phase B Letterly webhook) and queues the next brainstorm topic
(worker absence records). Adds an 8-line breadcrumb at the top
of CLAUDE.md so a fresh session sees it in the first 20 lines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four buttons at top of /payroll/ currently mix 3 treatments (outline
+ solid btn-primary one-off). Design swaps all 4 to a unified
.btn-action-soft base class with per-button colour modifiers
(Lookup=blue, Pay=amber, Add=green, Price=mauve). Reuses existing
--badge-*-bg tokens for the Add + Price buttons; adds 2 new token
pairs for Lookup + Pay. Removes the shadow-sm / btn-sm / fw-bold
one-offs — the new class handles sizing + weight.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five tasks: (1) docs/design-tokens.md as the canonical colour
reference; (2) CLAUDE.md UI-vs-DB naming-drift note (ships BEFORE
the rename so it's searchable from minute one); (3) display-only
TYPE_CHOICES rename + auto-migration + template visible-text swap
to get_type_display; (4) badge colour unification on Pending +
History tabs + loan-flag recolor; (5) CSS root-cause fix for the
group-summary narrow-wrap bug (move display:flex from <tr> to <td>).
Execute via subagent-driven-development. Auto mode — no mid-execution
checkpoints.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four UX asks bundled in one pass:
1+2. Display-only rename of adjustment types: 'New Loan' (DB) →
'Loan' (UI), 'Advance Payment' → 'Advance', 'Advance Repayment'
→ 'Advance Repaid'. DB values preserved forever — zero data
migration, zero formula / constant / CSS / test changes.
3. Unify badge colours across all payroll tabs using the existing
.badge-type-* semantic palette. Recolour Pending "With loans"
flag to match the Loan type colour.
4. Fix CSS bug in .adj-group-meta (margin-left:auto doesn't work
in a <td> — make the td a flex container).
Plus: new docs/design-tokens.md as the canonical colour reference,
and a crucial CLAUDE.md section documenting the UI-vs-DB naming
drift so future Claude sessions don't chase ghosts when writing
formulas / filters / ORM queries that reference the display label
instead of the DB value.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four tasks: mtime cache-bust token + tests; install & gate Django
Debug Toolbar dev-only; profile + fix N+1 on /; profile + fix N+1 on
/payroll/ (all four tabs) with before/after summary in the final
commit message.
Execute via subagent-driven-development. Auto mode — no mid-execution
checkpoints.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Short design covering four changes: mtime-based CSS cache-bust token,
Django Debug Toolbar (dev-only) for profiling, N+1 fixes on Dashboard
and Payroll pages, and a before/after measurement in the commit message.
Scope is deliberately tight — plan B (template splitting) and plan C
(full audit) are deferred until plan A evidence lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the 11-task implementation, 5 deviations (biggest: the
CP1 pivot from Choices.js chip-multiselect to popover-checkbox
filter UX after Konrad flagged the chip pattern as intrusive),
14 new adjustments-tab tests, and total code churn (~+1400 lines).
CLAUDE.md URL Routes table gains two rows so future sessions
surface /payroll/?status=adjustments and the bulk-delete endpoint.
Feature ready for final whole-feature code review + batched push.
11 tasks + 1 hard-pause checkpoint after Task 4. Targets ~960 LOC
across core/views.py, payroll_dashboard.html, _adjustment_row.html
(new), format_tags.py, custom.css, and tests.py.
Derived from docs/plans/2026-04-23-adjustments-tab-design.md (commit
12edafa) — execution plan for subagent-driven development.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the 6 deviations from the original design (each with driving
feedback + commit SHA), the 5 non-design polish commits, and the test
delta (42 → 47 passing). Keeps the design doc as the first-read for
understanding the feature while preserving decision history from the
Checkpoint-1 iteration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task-by-task plan for the design at 30d0991. 6 tasks, 1 checkpoint
after Task 4 (all pill interactions demoable, modal still as fallback).
Tasks:
1. Backend: project_team_pairs_json context + 2 tests
2. Template: popover shells + Apply button + json_script embeds
3. CSS: pill-editable, pill-dirty, popover, apply-group, toast (~150 lines)
4. JS: pill-popover interactive module (~300 lines, scoped IIFE)
--- CHECKPOINT 1 ---
5. Retire modal: delete _report_config_modal.html, update index + report
templates, keep backend context keys (still used by pill markup)
6. QA + shipped note
Scope: ~480 LOC net added (not the ~330 estimated — JS came out larger
once written with proper state management + cross-filter). Tests grow
42 -> 44. One new CDN-loaded library? No — Choices.js already loaded
from Executive Report v2. Zero model changes, zero migrations.
Noted trade-off in Task 5: selected_project_ids / selected_team_ids
context keys were KEPT despite design doc suggesting removal — the
pill popovers still use them for pre-selection + URL-diff init. Only
the modal markup was retired.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second brainstorm output of the day. New tab alongside Pending /
History / Loans & Advances (the URL pattern already established at
?status=pending|paid|loans — this slots in at ?status=adjustments).
Key decisions:
- Semantic badge palette: 5 colour categories mapped across 7 types.
Loan/advance repayments get +15% saturation — same family, hotter
signal for "money coming back" vs "money going out".
- Three multi-select filters (Type, Workers, Teams) via Choices.js.
Teams cross-filter Workers using JSON pair map (mirrors Feature 1's
project<->team pattern). Auto-remove invalid selections with toast.
- Single-date default with optional range toggle; presets for
Today / This week / This month.
- Sticky filter bar; sortable columns (Date / Worker / Amount / Status).
- Group-by toggle: Flat / By Type / By Worker. Collapsible group
headers show count + net sum per group (+R additive / -R deductive).
- Bulk action bar (floating) for multi-row delete on unpaid rows only.
New endpoint POST /payroll/adjustments/bulk-delete/ filters
payroll_record__isnull=True for safety.
- Inline row actions reuse existing modals: Preview (unpaid) /
View Payslip (paid) / Edit + Delete (unpaid). Zero new modal code.
- Empty state, keyboard Esc, URL state for everything (bookmark-safe).
Scope: ~960 lines, ~12 tasks, 2 checkpoints. Uses existing
#addAdjustmentModal / #editAdjustmentModal / #payslipPreviewModal
already on payroll_dashboard.html — zero duplication.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brainstorm output — Konrad's Checkpoint-3 UX request, now spec'd.
Key decisions:
- Pill-as-dropdown: existing filter pills become clickable popovers
- Explicit Apply button; hidden when no pending changes
- Modal retired; dashboard 'Generate Report' becomes a plain link
- Bidirectional cross-filter: selecting a project hides teams that
haven't worked on it (and vice versa). Strict behaviour with
auto-removal of now-invalid selections + toast notice.
- URL contract unchanged; PDF download unchanged (still uses
current querystring).
One new context key (project_team_pairs_json) serialises distinct
(project_id, team_id) pairs from WorkLog for client-side cross-filter.
~80 CSS lines for popover + dirty state + toast; ~150 JS lines for
one scoped module (createElement + textContent, XSS-safe).
Scope: 5-6 focused tasks, 1 checkpoint.
Next step: Feature 2 brainstorm (Payroll Adjustments Browser) before
handing both to writing-plans.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QA summary:
- 42/42 tests pass
- manage.py check clean
- No pending migrations
- Route sanity: /report/, /report/?project=1&project=2, /report/pdf/ all
resolve (302 as anon, 200 as admin)
- PDF generation verified for populated and empty date ranges
Appends a "Shipped" block to the design doc that captures the final
QA state, the deferred items, and the notable design decisions made
during implementation. Konrad's inline-filter UX improvement (raised
during Checkpoint 3) is explicitly flagged for a future brainstorm.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task-by-task plan for the design committed at 27cdb46. 14 tasks with
4 hard-pause checkpoints at natural demo points:
- After Task 6 (backend helpers done)
- After Task 8 (multi-select modal + filter pills)
- After Task 12 (full HTML layout — all 4 chapters)
- After Task 14 (PDF mirrored + QA + shipped note)
Task 1 is a pure refactor (extract _compute_outstanding from index())
so later tasks can reuse the dashboard math with filters. Tasks 2-5
add the new helpers alongside existing code with failing-test-first
discipline. Task 6 switches the main helper to multi-value filters
(project_ids/team_ids) — existing behaviour preserved via backward-
compatible getlist. Tasks 7-12 restructure the HTML template into
Hero + 4 chapters. Task 13 mirrors in the PDF. Task 14 QAs and ships.
~11 new tests across 4 test classes; total grows from 28 to ~39.
One new dependency: Choices.js 10.2.0 via CDN, admin-only gated,
graceful fallback to native multi-select on CDN failure.
Follows the CLAUDE.md conventions: # === SECTION === comments,
plain-English docstrings, subquery-filter pattern for M2M filters,
single-batched push at the end, Co-Authored-By trailer on every
commit, never amend.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brainstorm output for rebuilding /report/ as an executive-grade dashboard.
Key decisions captured:
- Multi-select filters (Choices.js) with empty=all semantics
- Hero KPI band: Paid / Outstanding NOW / Avg R/day / Avg R/month
- Chapter I: Lifetime context with working-day denominator for avg cost
- Chapter II: Selected period (existing content, restructured)
- Chapter III: Worker breakdown (existing, restyled)
- Chapter IV: NEW team × project activity pivot
Current Outstanding reuses dashboard math (live, stamped with generation
time). Company cost velocity = lifetime cost / distinct work-log dates;
monthly = daily × 30.44.
No model changes. One new CDN dep (Choices.js). Target: ~650 LOC
including ~120 new tests. Four checkpoint pauses proposed for the
subsequent implementation plan.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a consolidated regression test to WorkLogPayrollAjaxTests that
exercises: paid worker serialization shape, null team branch, OT flag
in JSON, full_page_url value, and adjustment payslip-link serialization.
Closes the 'Important' coverage gap flagged in Task 3's quality review.
Also appends a 'Shipped' block to the design doc summarising QA
status and capturing all five deferred nits (admin-gate consistency,
template branch tests, |default:0 redundancy, admin-gate expression
readability, background vs background-color) so they survive the
merge into project history.
All 19 tests pass. manage.py check clean. No migrations needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task-by-task plan for implementing the modal + /history/<id>/ page
designed in the companion design doc. 10 tasks, 4 hard-pause review
checkpoints (after tasks 2, 4, 6, 10). TDD for the pure helper
function (bootstraps the currently-empty core/tests.py), view-level
tests for the AJAX + detail endpoints, manual smoke tests for the
template/JS work.
Uses the existing worker_lookup_ajax JSON+DOM pattern for the modal
(createElement + textContent, not innerHTML) to match the codebase's
XSS-safe convention. Full page is server-side rendered via a Django
template.
No model changes. No migrations. Admin-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brainstorm output for the next UI refinement. Adds a click-through from
any historic work log (Work History, team detail Recent Work Logs, project
detail Recent Work Logs) to a compact modal showing paid/unpaid status per
worker, with links out to /workers/<id>/ and /payroll/payslip/<pk>/. The
modal has a "Open full page" button that navigates to a new
/history/<log_id>/ route for bookmark-able detail + pay-period context
(via get_pay_period). Admin-only; supervisors unchanged.
Read-only pass; no model changes, no migrations. Uses existing data:
PayrollRecord.work_logs (M2M) and PayrollAdjustment.work_log (FK).
Also fixes local dev: run_dev.bat now sets DJANGO_DEBUG=true so runserver
auto-serves /static/ (prior behaviour: CSS 404 on localhost because
Django's dev server only serves static files when DEBUG=True; production
keeps DEBUG=false and is served by Apache, so unaffected).
Design doc: docs/plans/2026-04-22-work-log-payroll-crosslink-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New AJAX endpoint (worker_lookup_ajax) returns a comprehensive financial
report card for any active worker. Modal shows: amount payable, outstanding
loans, paid this month/year, loans this year, recent activity, active loans
table, current project + days, PPE sizing, drivers license, and notes.
Worker names across all dashboard tabs are now clickable links that open
the modal. Header button with searchable dropdown for quick access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Straight port from V2 adapted for V5 field names. Creates expense
receipts with dynamic line items, VAT calculation (Included/Excluded/
None at 15%), and emails HTML + PDF to Spark Receipt. Uses lazy
xhtml2pdf import to avoid crashing if not installed on server.
Files: forms.py (ExpenseReceiptForm + FormSet), views.py (create_receipt),
create_receipt.html, receipt_email.html, receipt_pdf.html, urls.py, base.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- core/utils.py: render_to_pdf() wrapper for xhtml2pdf
- core/templates/core/pdf/payslip_pdf.html: A4 PDF payslip (matches V2 layout)
- core/templates/core/email/payslip_email.html: HTML email body for Spark
- core/templates/core/payslip.html: browser payslip detail page with print
- core/views.py: add payslip_detail view, wire email+PDF into process_payment
- core/urls.py: add payroll/payslip/<pk>/ route
- config/settings.py: add SPARK_RECEIPT_EMAIL setting
- payroll_dashboard.html: add "View" payslip link in Payment History tab
All templates show adjustments (bonuses, deductions, overtime, loan repayments)
as line items. Amounts always show 2 decimal places. Email failure does not
roll back payment — handled gracefully with warning message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>