# 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×tamp=%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