The Aug 2026 pump sheet from The Hills (and any future sheet from
the same source) uses different column names and a different date
format than the legacy CSV the import route was built for. Adapts
the route so the same endpoint accepts either Excel (.xlsx) or CSV,
maps the new column names onto the existing FUEL_LOGS schema, and
persists their 'Latest Consumption' column verbatim.
What's new
• SheetJS (xlsx) replaces PapaParse for parsing. Single code path
handles both .xlsx and .csv uploads.
• Resolves columns case-insensitively against an alias table so
legacy CSVs (vehicle_description, odo_reading) still work
alongside the new shape (Date Logged, Vehicle QR, Km's/ Hours,
Litres Pumped, Current Site, Latest Consumption).
• Date parser: DD/MM/YYYY first (with leading-space tolerance),
falls back to YYYY-MM-DD, then to Excel serial numbers.
• Vehicle match: QR code first (clean identifier in the source
data), falls back to description text for legacy CSV.
• Site match: by sites.name (one round-trip, cached for the
import). project_code is derived from the resolved site; falls
back to the vehicle's project_code.
• Latest Consumption persisted as a new FUEL_LOGS field
(latest_consumption, number, optional). Empty source cells
stay empty rather than getting coerced to 0.
PocketBase change
• scripts/migrations/2026-08-24-fuel-logs-latest-consumption.py
adds the new field. Idempotent; follows the pattern of the
2026-08-19 migration. Run it with PB_ADMIN_EMAIL +
PB_ADMIN_PASSWORD before importing the new sheets, or the
import will fail with 'latest_consumption is not a field'.
UI
• Import button now accepts .xlsx and CSV; SAMPLE_HEADERS +
SAMPLE_OPTIONAL show the new column expectations and the
DD/MM/YYYY date format hint.
• fuel-view.tsx shows a 'Consumption (src)' column on the row
table so operators can eyeball what their fuel team sent
against the app's recomputed variance.
Out of scope (intentionally untouched)
• vehicles, sites, data_import_batches and every other
collection — no schema changes there.
• PO / timesheets / delivery-notes imports.
• fuel/page.tsx business logic (variance calc, vehicle summaries).
Verified
• Dry-run against 'The Hills Diesel 1-24 August.xlsx': 134/134
rows parse cleanly, 0 errors. 12/134 rows correctly carry an
empty Latest Consumption (matches the source).
• vitest: 20/20 fuel-import-parse + 35/35 PO-schema tests pass.
• tsc --noEmit clean.
• One pre-existing failure in
src/app/api/purchase-orders/process-batch/route.test.ts
unrelated to fuel; confirmed failing on main before this change.
Extends the data_import_batches collection for the PO/DN async-import
queue redesign (see spec docs/superpowers/specs/2026-08-19-po-import-queue-redesign.md
and plan docs/superpowers/plans/2026-08-19-po-import-queue-implementation.md).
Adds 8 fields:
content_type, status (select: pending|processing|processed|failed|dead),
attempts, last_error, last_attempt_at, next_retry_at, processed_at,
processed_record_id
Extends the batch_type enum to include purchase_orders and delivery_notes.
Adds index idx_batches_pending on (status, batch_type, next_retry_at) for
the cron query.
Idempotent: safe to re-run.
Co-Authored-By: Claude <noreply@anthropic.com>
- Added `pocketbase` as a dependency in `package.json` and `package-lock.json`.
- Updated the `dev` script in `package.json` to run on port 6004 instead of 3000.
- Removed unused API routes: `src/app/api/health/route.ts`, `src/app/api/mcp/route.ts`, `src/app/api/upload/route.ts`, and their associated logic to streamline the codebase.
- Cleaned up `package-lock.json` by removing unnecessary peer dependencies and ensuring consistency in the dependency tree.
When someone shares a link to the dashboard in WhatsApp, Facebook,
LinkedIn, Discord, etc., the platform now shows a custom preview
instead of a plain blank card.
- public/og-image.png 1200x630 PNG with the brand mark, the
MEGA INFRASTRUCTURE wordmark, and a
tagline over a dark gradient with the
brand accent bars.
- public/fonts/ Inter ExtraBold (woff) used by the OG image
generator so the rendered text is identical
on every machine.
- scripts/build-og-image.mjs
Generates the image from an SVG template
using sharp. The font is loaded from the
local file (or Google Fonts CDN as fallback)
and embedded as base64 inside the SVG so
the renderer doesn't depend on system
fonts.
- src/app/layout.tsx Adds the openGraph + twitter metadata
pointing at /og-image.png so the preview
appears in link-unfurl contexts.
- package.json 'npm run og-image' runs the generator;
'npm run build' chains it via prebuild so
the image is regenerated on every CI build.
The postinstall hook runs scripts/patch-next-dev-blocker.cjs, but at
that point in the Docker build only package.json and package-lock.json
have been copied — the scripts/ directory isn't there yet, so the
hook fails with MODULE_NOT_FOUND.
The patch is dev-only (it mutates Next 16's dev-only cross-site
guard, which is never loaded in production), so it's safe to skip
during the Docker build. Two changes:
1. Dockerfile: use 'npm ci --ignore-scripts' in the deps stage so
the postinstall hook doesn't run before the scripts/ directory
is available.
2. scripts/patch-next-dev-blocker.cjs: bail out cleanly with exit 0
when node_modules/next is missing, so the script is also safe to
run in any intermediate state.