20 Commits

Author SHA1 Message Date
Konrad du Plessis
0c42cde4ff fix(perf): CLAUDE.md runbook + drop dead var in cache-bust test
Code-review followups on 16d4399:

- CLAUDE.md's "When CSS changes don't appear" diagnostic steps
  were written for the old per-request token. Under mtime-based
  caching, a stable ?v= number is the healthy expected state,
  not a broken one. Rewrote steps 1 + 3 so someone debugging
  a real production CSS issue gets the right advice.

- Dropped unused `original = cp._compute_cache_bust_token` line
  in test_token_falls_back_if_file_missing - it misled readers
  into thinking the function itself was patched. Added a one-
  line comment clarifying the monkey-patch is path-only.

Tests: still 68/68.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 00:38:52 +02:00
Konrad du Plessis
16d4399c28 perf(cache): mtime-based CSS cache-bust token
deployment_timestamp was int(time.time()) per-request, giving every
page load a new ?v=... query string on custom.css. Cloudflare treats
each unique URL as a new resource, so the CSS was fetched from the VM
on every page load — 64 KB over the wire per navigation.

Token now tied to static/css/custom.css mtime. The URL only changes
when the CSS actually changes, so Cloudflare can hold the file for
its full 4h TTL. Degraded-mode fallback preserves today's behaviour
if the file isn't on disk.

3 new CacheBustTokenTests; all 68 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 00:31:05 +02:00
Konrad du Plessis
503eff67a0 docs(claude): update CLAUDE.md for session's features + newly-learnt gotchas
Audit revealed several stale / missing items:

1. Wrong CSS selector for light theme — said `:root.light`, actual is
   `[data-theme="light"]`. Task 2 of Adjustments caught this in the
   implementer's self-review; the doc didn't get updated. Now correct.

2. `_report_config_modal (partial)` removed from templates list — the
   file was deleted in commit 1d00a3a (retire modal).

3. `_adjustment_row.html` added to templates list — new partial, shared
   by flat + grouped views on the Adjustments tab.

4. `format_tags.py` now lists all 5 filters: money, money_abs, type_slug,
   url_replace, dictlookup (was just 'money').

5. New narrative paragraphs for:
   - Inline Filters on /report/ (pill popovers, cross-filter, JSON gotcha)
   - Adjustments tab (filter pills, badge palette, group-by, bulk delete)
   - _delete_adjustment_with_cascade helper (shared by single+bulk)
   - Pill-popover filter pattern (.adj-hidden-inputs + OK-rewrites-inputs)

6. Two new schema name-drifts: PayrollRecord.amount_paid (not total_amount
   / days_worked); Loan.principal_amount (not principal). Both bit an
   implementer this session when writing test fixtures.

7. Two new Coding Style rules in the top section:
   - Multi-line {# #} template comments are INVALID — use {% comment %}
     (bit us 4× in this session). With caveat that literal {# or #} can't
     appear inside a {% comment %} block either.
   - Duplicate id= attributes silently steal event handlers — grep before
     assigning (caught adjSelectAll collision between table header + modal).

Now 707 lines, 24 sections. Future sessions should have the context to
avoid the mistakes this session made.
2026-04-24 00:00:07 +02:00
Konrad du Plessis
269d86259a docs(adjustments): Shipped block on design doc + CLAUDE.md URL routes
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.
2026-04-23 19:26:46 +02:00
Konrad du Plessis
92036f7e4c Docs: update CLAUDE.md with session learnings
Five focused updates from the Apr 22-23 bug-fix + gitignore session:

1. Fix stale supervisor-picker queryset doc: it was showing the pre-fix
   Q(is_staff)|Q(is_superuser)|Q(groups__name='Work Logger') filter.
   Since commit 0ceceeb the queryset is just User.objects.filter(is_active=True).

2. Update "How to add a new supervisor" step 2: Work Logger group
   membership is no longer required for picker visibility — optional now.

3. Add "Schema name-drifts to remember" block near Key Models. Three
   recurring gotchas that burned four subagent tasks across two sessions:
   - PayrollAdjustment.description (not reason)
   - log.adjustments_by_work_log (not payrolladjustment_set)
   - log.overtime_amount (not log.overtime)

4. Add canonical test-command one-liner to the Commands section:
   USE_SQLITE=true DJANGO_DEBUG=true python manage.py test core.tests -v 2

5. Add "Django ORM gotcha" subsection documenting the M2M filter +
   values().annotate(Sum()) inflation bug and the id__in subquery fix
   pattern (refs commit f1e246c, ReportContextFilterInflationTests).

No code changes; no test impact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:36:35 +02:00
Konrad du Plessis
88e68f5e36 Stop tracking staticfiles/ — it's a build artifact, not source
Problem: every time collectstatic ran on the VM, Flatlogic's web UI
detected the modified files in staticfiles/ and auto-committed them
with a generic "Ver XX.YY" message (e.g. "Ver 30.04 Fix reports and
add Supervisor"), pushing the result to gitea but not GitHub. Every
push of CSS/JS changes triggered a reconciliation dance. See the
"Ver 30.04" divergence resolved by commit e0d2c74 for the most recent
example — that was the 3rd or 4th recurrence of this exact pattern.

Fix:
1. Add staticfiles/ to .gitignore
2. Untrack all 627 currently-tracked files via `git rm -r --cached`
3. Document the change in CLAUDE.md (Project Structure, Static Assets,
   and a new "NOT tracked in git" subsection)

Deploy consequence: the NEXT pull on the VM will delete
staticfiles/ from the working tree (because git sees those files
removed from the tree). Gemini MUST run `collectstatic --noinput`
IMMEDIATELY after `git pull` to repopulate from source, then
restart the service. Brief window of 404s on static assets is
acceptable at this scale (seconds).

After this change: collectstatic output lives on the VM's filesystem
but outside git's view, so Flatlogic's UI has nothing to auto-commit.
The recurring divergence pattern is permanently eliminated.

No runtime code changes — all 28 tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:45:20 +02:00
Konrad du Plessis
a8ef7bb341 Update CLAUDE.md with cache-busting, email fallback, and deploy context
Documents three things that came out of today's Phase 2 deploy session
and weren't previously written down:

1. Static Assets & Cache-Busting (new section): explains that production
   traffic goes through Cloudflare with 4h edge cache; the
   `deployment_timestamp` template variable is what breaks stale caches;
   and why `request.timestamp` must never be used (the silent-default-to-1.0
   bug that ate a couple of hours).

2. Environment Variables: inline notes for each var. Most important new
   fact is that DEFAULT_FROM_EMAIL is now optional — falls back to
   EMAIL_HOST_USER if unset (prevents the "Invalid address ''" failure
   mode on outbound mail). Also documents that .env lives at BASE_DIR.parent
   on Flatlogic and can only be edited via Gemini/shell.

3. Flatlogic Deployment: collectstatic isn't auto-run, django-dev.service
   runs manage.py runserver (dev server in prod — known but works at this
   scale), Cloudflare sits in front, VM has two git remotes (github +
   gitea) that must stay in sync, VM-local safety branches for rollback,
   and the "pick one write path" workflow rule to avoid divergence.

No code changes — documentation only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 04:42:32 +02:00
Konrad du Plessis
3c28387dd3 WIP: 2026-04-22 session checkpoint
Complete working state of the session. Will be split into two deploy
phases (safety scaffolding then feature release) before merging to ai-dev.

Includes:
- Security fixes (email creds / SECRET_KEY / DEBUG / CSRF)
- Backup + restore management commands and browser endpoints
- WeasyPrint migration (replaces xhtml2pdf)
- New Worker fields + WorkerCertificate + WorkerWarning models
- Worker / Team / Project friendly management UIs
- Dashboard cert-expiry card + Manage All buttons
- Bootstrap tooltips (global init + theme-aware CSS)
- Django admin template override (taller M2M pickers)
- Money filter for ZAR currency formatting
- Resources dropdown nav
- Massive CLAUDE.md expansion + deploy plan docs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:19:15 +02:00
Konrad du Plessis
a1ac8540ab Add comprehensive features guide and update CLAUDE.md
New docs/FEATURES.md covers all 15 feature areas: dashboard, attendance,
work history, payroll, payments, adjustments, loans, worker lookup, worker
management, team schedules, receipts, emails/PDFs, auth, exports, and
deployment tools. CLAUDE.md updated with accurate line count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 15:15:24 +02:00
Konrad du Plessis
60ee21dd61 Add Worker Lookup modal to payroll dashboard
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>
2026-04-20 14:15:04 +02:00
Konrad du Plessis
81009be0c6 Add PPE sizing and drivers license fields to Worker model
New fields: shoe_size, overall_top_size, pants_size, tshirt_size,
has_drivers_license (boolean), drivers_license (file upload).
Admin organised into 3 fieldsets. CSV export updated with new columns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:10:46 +02:00
Konrad du Plessis
803f8696e7 Update CLAUDE.md: accurate function count, quick adjust docs
- views.py now has 27 functions (~2470 lines)
- Document the Quick Adjust button on pending payments rows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 12:25:22 +02:00
Konrad du Plessis
c3bbffe9c0 Update CLAUDE.md with Pay Immediately loan documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 10:00:39 +02:00
Konrad du Plessis
72d40971f1 Update batch pay modal: 3-option loan filter + radio button fix
- Replace "Exclude workers with loans" checkbox with dropdown
  (All Workers / With loans only / Without loans) in batch pay modal,
  matching the pending payments table filter style
- Fix radio button visual state when switching between
  "Until Last Paydate" and "Pay All" modes (set checked after DOM append)
- Update CLAUDE.md with pending table filter and overdue badge docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 09:23:01 +02:00
Konrad du Plessis
2c3410e7c7 Update CLAUDE.md with batch pay feature documentation
- Add batch pay workflow docs (schedule vs pay-all modes, shared helper)
- Add batch-pay preview and process endpoints to URL routes table
- Update view count to 19 (~2000 lines)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:32:05 +02:00
Konrad du Plessis
79b6345cb9 Document /run-migrate/ endpoint and unreliable auto-migrations
Flatlogic doesn't always run migrations on Pull Latest. Added note
about using /run-migrate/ to fix "Unknown column" errors after deploy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 21:22:42 +02:00
Konrad du Plessis
394f9bdfe4 Update CLAUDE.md with split payslip and team pay schedule docs
Document the new split payslip feature, team pay schedule fields,
pay period calculation helpers, and backward-compatible process_payment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 21:08:32 +02:00
Konrad du Plessis
d51d06d28d Redesign advance payments: auto-process immediately with auto-repayment
Advances are now treated as immediate payments (not pending salary items):
- Auto-creates PayrollRecord + sends payslip email at creation time
- Auto-creates Advance Repayment adjustment for next salary cycle
- Validates worker has unpaid work logs (otherwise use New Loan)
- Requires project selection for cost tracking
- Partial repayment converts advance to regular loan
- Admin can edit auto-repayment amount before payday
- Negative net pay warning in preview modal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:23:03 +02:00
Konrad du Plessis
0257b454af Add Advance Payment system + enhanced preview modal with inline repayments
Redesign Advance Payments to work like loans with tracked balances:
- Add loan_type field to Loan model ('loan' or 'advance')
- Move Advance Payment from DEDUCTIVE to ADDITIVE types (worker receives money)
- Add new Advance Repayment type for deducting from future salary
- Create/edit/delete handlers mirror New Loan behavior for advances
- Loans & Advances tab with type badges and filter buttons

Enhance Payslip Preview modal into "Worker Payment Hub":
- Show outstanding loans & advances with balances in preview
- Inline repayment form per loan (amount pre-filled, note, Deduct button)
- AJAX add_repayment_ajax endpoint creates adjustment without page reload
- Modal auto-refreshes after repayment showing updated net pay
- New refreshPreview() JS function enables re-fetching after AJAX

Other changes:
- Rename History to Work History in navbar
- Advance-specific payslip layout for pure advance payments
- Fix JS noProjectTypes to hide Project field for advance types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:46:58 +02:00
Konrad du Plessis
19c662ec7d Fix 3 critical bugs in dashboard + attendance logging
- Fix outstanding payments: check per-worker (not per-log) to handle partially-paid WorkLogs
- Fix adjustment math: deductions now subtract from outstanding instead of adding
- Fix conflict resolution: use explicit worker ID list (QueryDict.getlist) instead of broken form.data.workers iteration
- Add missing migration 0003 for Project start_date/end_date fields
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:28:11 +02:00