Commit graph

21 commits

Author SHA1 Message Date
DEls
d5e3b2ce2b docs(spec): Workers/Timesheets split and worker QR badges
Workers becomes a lean roster (name, employee number, position, type,
site, rate) with filters unchanged. Everything currently cluttering the
list row -- total hours, cost, the 8-week sparkline, per-employee entry
history -- moves to a new worker detail page that doesn't exist yet
(today's "detail" is a dialog). Same pattern already used for Suppliers
and Vehicles/Equipment this session: lean list, detail page carries
depth.

Timesheets keeps its flat entries table but gains a genuinely separate
upload-status section -- the timesheets document collection already has
this data, it's just currently squeezed into a per-row badge instead of
being its own thing. The duplicated Import-timesheets button (currently
on both pages) moves here only.

QR badges: encodes employee_no directly, no new PocketBase field --
every worker already has a valid code the moment they exist, with no
generation step. Explicitly a deliberate tradeoff (guessable numbers,
no revocation) the user chose for now, pending seeing how the separate
timekeeping PWA wants identity handled -- moving to a stored opaque
token later is additive, not a rework. Card layout confirmed via the
visual companion (centered, QR-forward). Both single-worker and
batch-sheet print confirmed in scope. Rendering via the qrcode npm
package + the browser's own print dialog (@media print), not a PDF
library -- CSS handles real-world card dimensions more reliably than
fighting a PDF engine's coordinate system.

The timekeeping PWA itself is explicitly out of scope -- a separate
project this spec only needs to stay compatible with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 19:04:34 +02:00
DEls
c73a2aad6c docs(spec): correct the suppliers migration's expected merge count
19 -> ~16 was wrong. Ran the actual normalizeSupplierName() (trim +
whitespace-collapse + uppercase) against the three example pairs cited
as evidence: only the case-variant pair (Builders Warehouse) actually
collapses. The Ikhasi pair keeps a stray space after a hyphen that
differs between variants; the Global Precast pair differs by the
"(Pty) Ltd" suffix, not case or whitespace. Neither collapses under
exact-normalized matching.

This is not a defect -- it's the conservative-matching principle in
section 3 working as designed. The correct expectation against
production is 19 raw strings -> 18 groups, one merge. Both pairs that
don't collapse are exactly the kind of ambiguous case the spec already
says should stay separate for a human to resolve, not the kind that
should be forced together by loosening the normalizer.

Caught while grounding the implementation plan in real data, before
writing a single line of the plan itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 18:02:18 +02:00
DEls
cfefb61c1b docs(spec): suppliers — new collection, PO relation, live AP ledger
New suppliers collection replacing purchase_orders.supplier (free text)
as the authoritative value, kept alongside it as OCR provenance rather
than dropped -- it genuinely is the supplier name, just inconsistently
formatted, unlike project_code which never held a real project code at
all.

Grounded in production: 24 POs, 19 distinct raw supplier strings, at
least 3 confirmed duplicates under a formatting variant. Migration
auto-merges only exact-normalized matches; anything ambiguous (e.g. two
"Vula" entries that may or may not be the same company) stays separate
rather than guessed.

The accounts-payable rollup (ordered/delivered/outstanding per supplier,
in Rand) is computed live from purchase_order_items and
delivery_note_items every read, never stored -- same reasoning as
po-fulfilment.ts: a stored balance has to be kept correct on every PO,
delivery, and correction, and PocketBase has no transactions to
guarantee that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 17:31:43 +02:00
DEls
12639e98f0 docs(spec): sidebar restructure — grouped nav with landing pages
Reorganizes the flat 7-item sidebar into Workforce/Plant/Financial
groups, each with a landing dashboard and sub-pages split out of
today's combined Employees and Purchasing pages. Delivers the Delivery
Notes page and ingestion-status Uploads view that
2026-09-11-ingestion-restructure-design.md section 8 deliberately left
for later, now that the data model is settled.

Suppliers (new collection, PO relation, free-text-to-record matching
migration) is explicitly out of scope -- split into its own spec per
user request, same rigor as the ingestion restructure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:37:59 +02:00
DEls
8075f6798a docs(spec): add PO fulfilment model — outstanding is computed, not stored
Partial deliveries against a PO line are the reason qty_outstanding is
dropped rather than wired: a stored counter must be decremented correctly
on every receipt, OCR re-run and correction, and PocketBase has no real
transactions to guarantee that. The sum over delivery_note_items cannot
drift.

Records the relation chain, the two invariants (unmatched lines count
toward nothing; over-delivery is legal), and the fulfilment test cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:09:12 +02:00
DEls
2814061b28 docs(spec): ingestion restructure — per-entity documents, honest status
Replaces the data_import_batches upload pool with five typed document
collections that each own their file, makes upload status reflect what
actually happened, puts a real site on every ingested row, and removes
the project_code duplication.

Audited against production on 2026-09-11:
- 19 plant_hours batches marked 'processed'; plant_hours_log has 1 row
- 147 of 320 fuel_logs have no site relation
- purchase_orders.project_code holds requisition numbers and site names,
  not project codes — automatic site matching succeeds ~8% of the time
- PLANT collection and two data_import_batches fields have zero readers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:02:42 +02:00
DEls
31c86b5b89 docs(spec): vehicle unit_type inline-edit UI (fleet + plant)
The vehicles PB collection already has a unit_type field (fuel |
plant, default fuel, made optional on 2026-08-28) and the
PATCH /api/vehicles/[id] endpoint accepts it with full test
coverage. Today there is no UI surface for assigning or changing a
vehicle's unit_type on either the Fleet page (/dashboard/fuel) or
the Plant page (/dashboard/plant), so the 53 currently mis-classified
vehicles cannot be triaged from the UI.

This spec adds that surface via the existing inline-edit pattern
already used on both pages for description editing: a Type column
renders a 'Fleet (L)' / 'Plant (h)' badge in display mode and a
Select in edit mode. Saving a flip calls PATCH /api/vehicles/[id];
on success router.refresh() re-pulls the page and the row drops
out of the page's filter, effectively moving it to the other page.

Scope is intentionally tight:
- Server-side filter on each page (Fleet: unit_type=fuel or empty;
  Plant: unit_type=plant AND cost_per_hour > 0).
- New Type column on the existing Fleet and Plant tables (no new
  pages, no new top-level nav).
- New shared <UnitTypePill> / <UnitTypeSelect> cell components.
- Reuses the generic useInlineEdit<K extends keyof T> hook (no
  hook changes needed).
- No schema migration, no API changes, no new tests.

Spec self-review pass: tightened two claims (pb-types.ts UnitType
line 37 not 48; useInlineEdit is already generic so no hook edit).
2026-08-31 12:48:57 +02:00
DEls
459905758f docs(spec): MEGA Ask vs MEGA OPS PWA split-install icon design 2026-08-30 22:11:02 +02:00
DEls
ccaeee6896 docs(spec): clarify card subtitle covers monthly + one-off 2026-08-28 12:33:53 +02:00
DEls
2fac85e79d docs(spec): site overhead monthly vs one-off design 2026-08-28 12:33:39 +02:00
DEls
cc0abfdc2c docs(plant-hours): weekly log import + exception report design
Adds a design doc for capturing weekly plant-equipment hours via an Excel
template against the existing /dashboard/plant page. One new
plant_hours_log collection, one vehicles.unit_type field, three new
routes (import, template download, exception report CSV), and an
extension to PlantView.

Spec covers: lenient import with per-row errors, downloadable exception
report for fix-and-retry, snapshot of vehicle.unit_type on each row,
over-budget flag against a per-week budget, and a symmetric attention
panel on /dashboard/plant for type mismatches.
2026-08-28 12:20:58 +02:00
DEls
0e13720fa7 docs(spec): fuel attention dismissal design
Per-vehicle 'I've seen this' control on the Fuel dashboard. Stamps
attention_dismissed_at on the vehicles collection; auto-undismisses when
a flagged fuel log with date_logged > dismissal arrives. Timestamp only,
no reason field. Tiny POST/DELETE route + filter line in page mapper +
Dismiss button on alert rows + Dismissed/Restore pill on vehicle detail.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 12:19:59 +02:00
DEls
6c00676343 docs(spec): PO detail supplier edit + DN items collapse
Two scoped follow-ups to the supplier-unknown flag (9897f47):
- Edit supplier on detail page when flagged as unknown
- Collapse received items per delivery note by default
2026-08-27 00:49:42 +02:00
DEls
7020449853 docs(specs): purchasing UI tweaks — shorter upload labels, unlinked-DN styling, view PO PDF, fulfillment bug 2026-08-26 23:56:34 +02:00
DEls
417723628f docs(specs): fix stale URL example, 'above' wording, and add recordId notes 2026-08-26 23:34:10 +02:00
DEls
0c95243ecf docs(specs): screenshot of compact needs-review modal with working PDF 2026-08-26 23:33:33 +02:00
DEls
5e86fadc38 docs(specs): PDF URL fix + compact needs-review modal 2026-08-26 23:20:08 +02:00
DEls
988ffc6377 docs(specs): needs-review modal resize + inline PDF viewer 2026-08-26 22:58:11 +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
8f37f3467f Spec: clarify PO upload dialog does not auto-close
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 15:03:48 +02:00
DEls
14b63e50ab Design: Purchase Order upload + n8n ingestion
Adds design spec and n8n handoff doc for the new PO upload flow:
browser -> Next.js /api/purchase-orders/upload -> n8n OCR ->
Next.js /api/purchase-orders/ingest -> PocketBase via pbAdmin().

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 02:10:58 +02:00