Commit graph

33 commits

Author SHA1 Message Date
DEls
8e72acc8a5 chore(assets): update application icons and logo with new designs 2026-09-11 20:54:44 +02:00
DEls
dc85da3f36 docs(plan): suppliers implementation plan
13 tasks across 6 phases: additive schema, pure matching/ledger
functions (TDD, tested in isolation), the one irreversible migration
(guarded, dry-run default), OCR wiring, API routes, and UI.

Grounded in the actual codebase rather than the spec's prose: the
existing "unknown supplier" inline-editor on the PO detail page
(SupplierEditor + POST /api/purchase-orders/[id]/supplier) is upgraded
in place rather than duplicated, following the same principle applied
to the sidebar restructure's delivery-note review queue. Every code
sample is written against files actually read during planning, not
guessed -- site-form-dialog.tsx, the /api/sites routes, matchSite,
po-fulfilment.ts, and the live purchase_orders.supplier data.

Self-review caught a real gap before committing: pb-bootstrap-schema.py
and pb-types.ts were named in the file-structure table but no task
actually touched them -- exactly the foot-gun docs/data-model.md
section 7 warns about. Added as Task 1 steps 5-8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 18:08:30 +02:00
DEls
f3d433160b chore: untrack compiled Python bytecode, fix missed Task 17 checkboxes
.pyc files are generated, not source -- machine/version-specific,
produce spurious diffs, and a routine __pycache__ cleanup can delete
tracked files as a side effect (hit this earlier in the session). Added
__pycache__/ to .gitignore.

Also fixed a boundary error in the plan's checkbox sweep: Task 17's own
6 steps were skipped when checking off Task 18's range. Task 17 has been
done and independently verified since commit 29ee2cc.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 16:18:06 +02:00
DEls
9b9d7097bb docs(plan): check off Task 20 — all 20 tasks complete 2026-09-11 16:17:41 +02:00
DEls
530d837bd6 docs(plan): check off Task 19 2026-09-11 16:08:34 +02:00
DEls
13f76ac894 perf(schema): index the columns every per-site query filters on
timesheet_entries, fuel_logs and delivery_notes had no indexes at all --
fine at today's row counts, not once site count grows toward the 18-20
target. Added 8 indexes across fuel_logs, timesheet_entries,
delivery_notes, purchase_orders and plant_hours_log, unioned into each
collection's existing index array rather than replacing it.

Verified both pre-existing UNIQUE indexes (idx_po_number, load-bearing
for the placeholder-PO-number scheme; idx_plant_hours_log_qr_start,
prevents duplicate weekly imports) are byte-for-byte unchanged.
Idempotent: a second run touches nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 16:08:34 +02:00
DEls
f007b5e8fb feat(schema): require site on every ingested collection
Tightened site from optional to required on fuel_logs, timesheet_entries,
delivery_notes and purchase_orders now that every route writes it and
every historical row has been backfilled. plant_hours_log was already
required (matches docs/data-model.md's documented invariant, confirmed
against production). timesheets (the document collection) was already
required from Task 6 -- a no-op here, not a regression.

fuel_sheets.site and plant_hours_sheets.site deliberately stay optional:
those sheets can legitimately span multiple sites.

Verified: creating a fuel_logs row with no site now gets a hard 400
(validation_required) from PocketBase itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 15:32:48 +02:00
DEls
f184776148 docs(n8n): repoint PO ingest workflow at purchase_orders
Task 15 of the ingestion restructure. Edited the live n8n workflow
(005iI4jX5mq9DsTR) directly via MCP and published the new version.

Repointed Watchdog: List Stuck, Watchdog: Reset Stuck Rows, Fetch Pending
Batches, Atomic Claim, Claim Successful?, Download File and Escalate
Failure from data_import_batches/status onto purchase_orders/
processing_status. Verified zero in-flight rows would be orphaned: all
26 old purchase_orders-type batches were already processed or failed,
and all 24 real PO rows had processing_status unset (won't match the new
pending filter).

Two things found on the live workflow that the plan didn't anticipate:

- Atomic Claim had no ?filter=processing_status="pending" guard at all --
  an unconditional PATCH, despite the workflow's own name and this doc's
  prior description both calling it "atomic". Added while repointing the
  same node.
- Build Callback Payload sent the extracted PO number as `po_number`.
  process-batch's validator requires the field named exactly
  `purchase_order_number` -- the old field name would have failed
  validation on every single real upload, a total silent outage. Fixed
  before publishing, verified against the route's actual validateExtracted().

Also removed the n8n-side duplicate short-circuit: the old
Build Callback Payload queried purchase_orders and PATCHed the batch row
directly from n8n code to pre-empt process-batch's own dedup logic.
process-batch's merge branch (Task 14) already does this correctly,
server-side, tested. Keeping both meant the same decision made twice in
two places that could disagree. Is Duplicate? node removed; Build
Callback Payload connects straight to Send Callback.

Published as the active version and verified by reading the workflow
back in full -- every repointed node confirmed, connections confirmed,
zero validation warnings.

Rewrote docs/n8n/purchase-order-ingest-implementation.md end to end to
describe the deployed shape rather than the retired one. Flagged (not
fixed, separate decision) a plaintext PB superuser password baked into
the Auth PB Admin node.

Marked Tasks 1-15 complete in the plan's own checkboxes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 14:46:57 +02:00
DEls
3a71e7e884 feat(schema): add timesheets, fuel_sheets, plant_hours_sheets documents
Three document collections replacing data_import_batches for the
spreadsheet importers. Each owns its source file and carries honest
outcome counters (rows_total/created/failed, row_errors) — the counts the
current importers compute and then discard.

site is required on timesheets (a wage sheet belongs to one site) and
optional on the other two, which legitimately span sites since the fuel
importer resolves a site per row. cascadeDelete is false on all three, so
deleting a site cannot destroy its source spreadsheets.

Widened source_file mimeTypes beyond the plan's three entries to match
the pool being replaced. Browsers label CSVs text/csv, application/csv or
text/plain interchangeably and the importers branch on file extension,
not MIME — so the narrower list would have parsed a CSV successfully then
rejected it on write. The 2026-08-24 migration exists because that
already happened once.

Plan corrected: its TypeScript edit added a second `expand` property to
an interface that already had one, which does not compile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 11:09:14 +02:00
DEls
9117b73cd4 fix(fuel): backfill site on 147 orphaned fuel logs
147 of 320 fuel_logs had no site relation; their only attribution was the
denormalised project_code text, which Task 18 deletes. Backfilled before
that column goes, resolving each row twice (by project_code and via the
vehicle's own site) and writing only on agreement.

147/147 written, 0 skipped, 0 remaining.

Recorded a caveat the dry run exposed: with one site in production both
resolvers draw from a candidate set of size one, so "both agree" is
guaranteed rather than evidence. The write is still the only possible
correct value, but the guard only bites once more sites exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:44:19 +02:00
DEls
5274ac4981 fix(migration): separate download failures from missing files
Review found a transient 500 during download landed in the "no stored
file" bucket, so a broken run printed as a clean one and exited 0. Now
counted separately and exits non-zero.

Also: 404 is no longer swallowed on mutations (a PATCH against a deleted
record was counted as written), the target host and mode are printed, the
apply path reports a final written count, and filenames quote with
safe="".

Plan Task 1 Step 4 still carried the superseded copy-from-batch code
block under the rewritten prose, contradicting it. Replaced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:39:54 +02:00
DEls
147ce7e77a feat(schema): hash entity files directly instead of copying batch hashes
Production disproved the copy-from-batch approach in two ways:
- 10 delivery-note batches carry no file_hash at all (they predate
  78fa8da), and all 10 sit inside the 30-day dedup window, so copying
  would have left a live gap rather than a historical one
- one PO row was produced from two different files with different
  hashes via the dedup-by-PO-number branch, so copying gives
  last-write-wins on an arbitrary one

Hashing the stored bytes has neither problem and does not depend on the
collection we are about to delete. 56/56 records covered, none skipped.

Immediately surfaced a real duplicate the old path missed: two delivery
notes numbered IN132202 with identical bytes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:32:41 +02:00
DEls
9a8d637ff1 docs(plan): ingestion restructure implementation plan
20 tasks across four phases, each phase ending at a shippable state.
Phase 1 additive only, Phase 2 renames and document collections, Phase 3
route cutover, Phase 4 drops. Nothing is deleted before Phase 4, so every
earlier phase is reversible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:21:29 +02:00
DEls
2ea87ce56d docs(plan): implement vehicle unit_type inline-edit UI on Fleet + Plant 2026-08-31 12:57:18 +02:00
DEls
055387cc6d docs(plan): MEGA Ask vs MEGA OPS PWA split-install icon plan 2026-08-30 22:12:30 +02:00
DEls
b2b72dacfe docs(plan): agent coverage gaps, vision and PDF export
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:27:38 +02:00
DEls
410e2f6606 docs(plan): chat detail tools, PO upload and standalone PWA
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 08:27:49 +02:00
DEls
ca262cc789 docs(plan): chat UI + provider abstraction (phase 3)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 20:33:03 +02:00
DEls
e82754ee38 docs(plan): agent tool layer + read-only MCP server (phase 2B)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 20:13:39 +02:00
DEls
15206fa650 docs(plan): fuel attention extraction plan (phase 2A)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 20:04:51 +02:00
DEls
2d36e9b1cd fix(vehicles): handle empty unit_type during updates
Updated the vehicles API to allow PATCH requests with an empty unit_type. This change ensures that existing records with unit_type='' can be updated without validation errors, while maintaining the default value of 'fuel' for new inserts. This adjustment resolves issues with updating pre-existing vehicle records that lack a unit_type field.
2026-08-29 19:17:14 +02:00
DEls
71eb1c00cc docs(plan): fix byDateDesc to return 0 on equal dates 2026-08-28 12:54:02 +02:00
DEls
dc966086bd docs(plan): mark backfill migration as required after schema deploy 2026-08-28 12:47:02 +02:00
DEls
45e2cd7827 docs(plan): clarify Burn by category stays monthly-only 2026-08-28 12:37:53 +02:00
DEls
574df58011 docs(plan): site overhead monthly + one-off implementation plan 2026-08-28 12:37:29 +02:00
DEls
2204989a3c docs(plan): plant hours weekly log implementation plan
Bite-sized TDD task decomposition covering 13 tasks:
1. PocketBase schema (vehicles.unit_type + plant_hours_log)
2. Type updates (UnitType, PlantHoursLogRecord, BatchType)
3. Shared import-parse helpers + parseTime
4. Per-row validator + derived fields
5. Template generator + seed script
6. GET /api/plant-hours/template
7. Exception-report CSV builder + route
8. POST /api/plant-hours/import
9. DELETE /api/plant-hours/[id]
10. PATCH /api/vehicles/[id] accepts unit_type
11. ImportPlantHoursButton component
12. /dashboard/plant page extension
13. End-to-end smoke test

Each task has files, failing tests, implementation code, run commands,
and commit step. Follows the approved design spec.
2026-08-28 12:26:35 +02:00
DEls
c5230190d0 docs(plan): fuel attention dismissal implementation plan
7-task TDD plan: PB migration, API route + tests, isAlertAcknowledged
helper + tests, server mapper + filter, Dismiss button + optimistic
overlay, Dismissed pill + Restore on detail page, full verification
with Agent Browser. Steps use checkbox syntax for subagent-driven
or inline execution.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 12:24:14 +02:00
DEls
58f2ca6a7b docs(plan): PO supplier edit + DN collapse implementation
5 tasks: API route (TDD), SupplierEditor component, wire into
PoDetailView with state, wrap received items in <details>,
final verification with Agent Browser.
2026-08-27 00:50:44 +02:00
DEls
a8e67faf3d docs(plans): purchasing UI tweaks — 4 small tasks with TDD-friendly bite-sized steps 2026-08-26 23:58:30 +02:00
DEls
aded006b9f docs(plans): PDF URL fix + modal compact 2026-08-26 23:21:26 +02:00
DEls
6df78d8ccd docs(plans): needs-review modal resize + inline PDF viewer 2026-08-26 23:00:10 +02:00
DEls
84ff4c25b2 docs: add PO import queue spec/plan, ignore cooler.env, rewrite n8n ingest impl
Captures the async-queue redesign of the PO/DN import pipeline (see
spec + plan) and rewrites the n8n implementation doc to match the
new cron-driven architecture (workflow 005iI4jX5mq9DsTR). Also
gitignores cooler.env so the local-only deployment reference is no
longer tracked.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 22:03:39 +02:00
DEls
24fc85d911 Plan: Purchase Order upload + n8n ingestion implementation
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 02:16:22 +02:00