# The Chippy Van — thechippyvan.co.uk

Domain switched 2026-06-30 from chippy.kaburu.co.uk to thechippyvan.co.uk (final domain). Cloudflare DNS updated, vhost created on Hetzner pointing to same docroot (/home/chippy.kaburu.co.uk/public_html/). DB search-replaced, child theme updated. Both URLs resolve but thechippyvan.co.uk is canonical.

Mobile fish & chip van, Renfrew area. GPS tracking + pre-order system.

## Brand - Colours: Red, White, Navy - Font: Bangers (titles), Barlow Condensed (UI) - Personality: Local, fun, plays Dixie from roof hailers - Strapline: Traditional Fish and Chips

## Tech Stack

Plugin Purpose
Trackserver 5.1.1 Receives GPS from phone, stores tracks, Leaflet map
RestroPress 3.2.8 Menu, order capture, order management
Perfecty Push Notifications Self-hosted web push, no Google, no fees
SuperPWA Install to home screen, offline support
DiviFlash Divi 5 frontend modules
chippy-bridge (custom) Glue plugin — wires all four together

Phone tracking app: GPSLogger (Android). See chippy-van-gps for full stack, evidence-based diagnosis, and the accuracy-filter tuning recommendation. Map tiles: OpenStreetMap via Leaflet (no Google Maps fees)

Notification day-picker popup (2026-08-04): DiviFlash popup `difl_popup` post 140 “Notification Preferences” holds `[chippy_day_picker]` shortcode; click-triggered by floating bell (`.chippy-notify-trigger`, child-theme wp_footer) — bell icons are media IDs 85/86. Flow: user taps bell → popup → picks days → POST `/wp-json/chippy/v1/preferences` with their Perfecty UUID → server resolves UUID→subscriber row id → stored in `wpdx_chippy_user_prefs` → `class-push.php` day-filter targets Tuesday users only for Tuesday pushes.

Fixes applied (2026-08-04): 1. day-picker.js read wrong localStorage key (`perfecty_push_user_id`) — Perfecty actually stores `perfecty_user_id` (a UUID). Fix: read real key, send UUID, pass `nearest_stop_id` explicitly. 2. class-rest.php `intval()` on UUID → garbage. Fix: `resolve_push_user_id()` accepts int row id OR char-36 UUID (lookup in `wpdx_perfecty_push_users`), cookie check uses `perfecty_user_id`. 3. nearest-stop was never persisted (JS sent `lat:null`). Fix: send `nearest_stop_id`; server stores it.

VERIFIED end-to-end with live subscriber (uuid f703d3e6-…, row id 1): POST → success, DB row `push_user_id=1, preferred_days=tuesday,friday`; GET returns prefs; homepage HTML contains popup container + trigger map + rendered day-picker + bell.

FastPixel gotchas hit (documented for next time): - FastPixel's HTML optimizer STRIPS the DiviFlash popup container + inline trigger script from served pages. Workaround: add `/` to `fastpixel_exclusions` (homepage served unoptimized, marker `Optimized and served by FastPixel` gone) AND set `fastpixel_javascript_optimization=0` (keeps page cache + images; disables wpmeteor inline-script deferral that eats the popup). - FastPixel's Redis object cache (`fastpixel_object_cache_method=redis`, 127.0.0.1) serves STALE meta queries after you create popups — `wp cache flush` does NOT clear it (CLI uses non-persistent `WP_Object_Cache`). Use `redis-cli FLUSHDB`. - Re-activating FastPixel after deleting its cache dir recreates `object-cache.php` as root:root 640 → fatal (PHP runs as chipp4625). Fix: `chown chipp4625:chipp4625` + `chmod 644`. - `df_general_popup_enable` must be `'1'` exactly for `DF_Popup_Process` constructor to hook wp_footer (it's the DiviFlash → General Settings → Popup Enable toggle Steve switched on).

GPS reconciliation (2026-08-04): `~/.hermes/scripts/chippy-gps-reconcile.py` — weekly cron `chippy-gps-reconcile` (job `2e24029d5a44`, Mon 12:00, no_agent). Pulls all Trackserver points from chippy DB via SSH, geofences to Paisley/Renfrew bbox (55.82-55.91, -4.52/-4.31) so home/garage never appears, detects stops (dwell ≥4 min, 45m merge radius), merges into accumulating state (`~/.hermes/cache/chippy-gps/stops.json`) with running-mean centroids → meter-perfect over weeks. Outputs: stops.json, routes.json, dark Leaflet map.html. Silent when no new trips; reports repeat stops + routes when new data. Pure stdlib (no pandas). KAT-Coder can narrate from stops.json; math stays deterministic in script.

## Novel / Fun Features (keep all of these)

### Animated Fish Marker Red pin marker on the Leaflet map with a fish emoji inside. In demo: bobs in a gentle circle using sin/cos offset every 1000ms. In production: real GPS coords from Trackserver replace the orbit — marker moves with the actual van. Keep the fish, it's a crowd pleaser. ```javascript // Demo animation (replace with Trackserver live coords in production) let angle = 0; setInterval(() ⇒ {

angle += 0.002;
marker.setLatLng([
  vanLat + Math.sin(angle) * 0.0004,
  vanLng + Math.cos(angle) * 0.0004
]);

}, 1000); ```

### Pulsing Status Dot Gold dot on the status bar pulses when van is live/serving. CSS keyframe animation — pulse-dot scales 1 to 0.7 on 1.5s loop. Stops pulsing / goes grey when van is off for the night.

### Dixie Reference Van plays Dixie from roof hailers. Baked into copy throughout: - Order confirmation: “Listen out for Dixie — that's your cue!” - Push when approaching: “Dixie's playing — nearly at [Street]!”

### Geofencing Auto-Stop Detection chippy-bridge plugin puts a lat/lng + radius on each route stop. When Trackserver reports GPS inside a stop's radius, system auto-marks that stop as current — no phone touching required while frying. Status bar and map popup update automatically.

### PWA Install Prompt SuperPWA triggers “Add to Home Screen” after 2nd visit. Feels like a proper app — full screen, red splash, fish icon. Offline page shows last known position and menu.

### Push Notification Triggers

Trigger Title Message
Route starts “Chippy's out tonight!” “The van is rolling — order now!”
Leaving previous stop “On his way!” “Dixie's playing — nearly at [Street]!”
Arrived at stop “Chippy's here!” “The van is at [Street] — come get it!”

## Full Menu ### Mains

Item Single Supper
Fish (1) 3.70 5.90
Fish (2) 3.90 7.50
Half Chicken 5.50 9.50
Steak Pie 5.90
Black Pudding 5.90
Full Pizza 4.90 5.90
Full Pizza Crunch 5.10 6.50

### Chips

Item Regular Large
Chips 3.20 3.95
Chips, Curry or Gravy 3.80 4.50
Chips & Cheese 4.20 4.90
Chips, Cheese & Gravy 5.00 5.90
Chips, Cheese & Curry 5.00 5.90

### Extras

Item Price
Portion of Curry or Gravy 2.20
Portion of Cheese 2.50
Pickles 0.40
Can 1.20

## Still To Get From Chippy - Route nights and all stop names in driving order - Approximate dwell time per stop - What time he sets off each night - Any stops that vary (weather/seasonal) - Confirm phone is Android - Route-start broadcast — automatic or manual trigger?

## Build Order 1. ✅ Trackserver + GPSLogger — installed, awaiting tablet config 2. ✅ RestroPress — installed, menu being populated by Steve 3. ✅ SuperPWA — installed 4. ✅ Perfecty Push — installed 5. ✅ chippy-bridge plugin — BUILT 2026-06-30, v1.0.0, all 7 REST endpoints working 6. ⬜ Divi 5 frontend — full page build, all novelties in place 7. ⬜ GPSLogger on Samsung tablet — configure, test live tracking 8. ⬜ Drive the routes — collect stops, dwell times, enter into route CPT 9. ⬜ End to end test — full order, push notification, map tracking

## Demo HTML mockup: chippy-demo_2_09.html (uploaded 2026-05-20) Shows: animated fish marker, status bar, order panel, menu, confirmation.

## GPSLogger + Trackserver — LIVE 2026-07-14 - Status: ✅ Fully operational - User: Danny (shop_manager, user ID 3) - App password: `chippy1234` (stored in `ts_app_passwords` usermeta) - Tablet: Samsung SM-T505, LineageOS, GPSLogger app - Endpoint: `https://thechippyvan.co.uk/osmand` - Method: GET (query string with username/password) - Live test: 2026-07-14 13:41 — user drove around Kirklandneuk, 5+ points recorded with live speed/altitude - Track ID: Auto-created per session (e.g. “OsmAnd 2026-07-14 13:41”)

### GPSLogger URL Template ``` https://thechippyvan.co.uk/osmand?username=Danny&password=chippy1234&lat=%LAT&lon=%LON&timestamp=%TIMESTAMP&altitude=%ALT&speed=%SPD&bearing=%DIR ```

### Infrastructure Notes - LiteSpeed rewrite rules added to vhost config (`/usr/local/lsws/conf/vhosts/thechippyvan.co.uk/vhost.conf`) to route `/osmand` through WordPress - If GPSLogger uses HTTP Basic Auth instead, use: `https://thechippyvan.co.uk/osmand` with Basic Auth `Danny` / `chippy1234` - ⚠️ 2026-08-14 fix: site migrated to `/home/thechippyvan.co.uk/` + DB `chippyvan` (separate from old `chippy` DB). The regenerated vhost was MISSING `rewrite { enable 1 autoLoadHtaccess 1 }` → LiteSpeed never applied the `.htaccess` WP rewrite → `/osmand` + `/wp-json/` + all pretty permalinks 404'd (GPS dead since Aug 4). Fix: re-added block + `lswsctrl fullrestart`. Verified `/osmand` returns `OK`. Lesson: CyberPanel vhost regeneration drops this block — re-verify after migrations.

## Email — [email protected] (LIVE 2026-07-14) - Mailbox: [email protected] - Password: `VanForChips4321` - Server: mail.kaburu.cc (IP 49.13.202.144) - IMAP: 993 SSL/TLS - SMTP: 587 STARTTLS + authentication required (for outbound) - Webmail: https://mail.kaburu.cc/rainloop/ - Username: full email address ([email protected])

### Tablet Setup Open your email app → Add account: - Email: [email protected] - Password: EE$&Ng2b*PXTgriJsGm! - IMAP server: mail.kaburu.cc, port 993, SSL - SMTP server: mail.kaburu.cc, port 587, STARTTLS, auth ON

### Order Confirmation Emails Use `[email protected]` as From address. If using PHP/WP: - SMTP: mail.kaburu.cc:587 - Auth required with [email protected] credentials - Or use wp-config.php `define('SMTP_HOST', 'mail.kaburu.cc')` with plugin