Adds /dashboard/plant/map: a Leaflet view of every vehicle scanned from
the MEGA Clock kiosk, plotted at its last known position.
Schema
- vehicles.last_latitude / last_longitude / last_scanned_at /
last_location_accuracy_m denormalised off fuel_logs so the map page
renders every vehicle in a single query. Same best-effort pattern as
attention_dismissed_at; updated by /api/clock/vehicle-scan after every
successful scan. PB init defaults new number cols to 0 (not null) —
filter uses 'last_latitude > 0 || last_latitude < 0' to mean 'real fix'.
- Indexed via idx_vehicles_last_scanned.
Map UI
- Custom SVG markers per unit_type: car silhouette for fuel, tractor
silhouette for plant, 24x24, drop-shadowed.
- Clustering via react-leaflet-cluster over Leaflet.markercluster.
Cluster icons colour-ramp with size (green->sky->amber->rose) and
scale 32->54px.
- Three-button base-layer switcher: Street (OSM), Dark (ESRI Dark
Gray Canvas — CartoDB watermarks tiles without a key), Satellite
(ESRI World Imagery). Last choice persists in localStorage.
- Site pins: small purple map-marker divIcon, click flies the map to
zoom level 15.
- Empty-state is a floating chip on the map rather than a full-page
card so the map is always visible.
APIs
- /api/clock/vehicle-scan: stores the GPS fix on the fuel_logs row
AND denormalises onto the vehicle when present; missing-coord
scan leaves last_* untouched.
Sidebar: new Map entry under Plant group.
The new PWA icon matches the supplied reference: dark background, a
clock face with an orange upper-right arc and hands at 12 and 4
o'clock, sitting on an isometric cube whose two visible faces each
have the MEGA 'M' carved into the background colour, with two small
orange base wedges under the cube.
When the /clock URL is shared (Slack, iMessage, etc.) the static
1200x630 opengraph-image.png is picked up automatically and renders
the icon alongside the 'MEGA Clock' wordmark and tagline, via
openGraph + twitter metadata added to the route.
The next-pwa plugin's `manifest` option is silently ignored in
@ducanh2912/next-pwa@10.2.9 — only the service worker is generated.
The dashboard Web App Manifest now lives as a static file at
public/manifest.json, sourced from the next.config.js block we just
removed. This is the same shape the project shipped at HEAD~3, just
with the new short_name and id field added by Task 4.
The dashboard's manifest is generated by next-pwa from next.config.js.
A second static manifest in public/, linked from the chat page,
installs as its own app called Ask. The explicit id field stops the
two manifests on the same origin from being treated as updates to one
another.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 card showed hardcoded '5 projects · 3 flagged · 2 on schedule'
stats that were never updated from the mock data and duplicated
information in the Sites module. Removing it gives the sidebar a
cleaner Logo → Nav → Lock structure and means the Lock screen button
is visible without scrolling on standard heights.
Also align the mobile drawer's close-button breakpoint from lg to xl
to match the rest of the sidebar's breakpoint logic.