# 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 — van@thechippyvan.co.uk (LIVE 2026-07-14) - **Mailbox:** van@thechippyvan.co.uk - **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 (van@thechippyvan.co.uk) ### Tablet Setup Open your email app → Add account: - Email: van@thechippyvan.co.uk - 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 `van@thechippyvan.co.uk` as From address. If using PHP/WP: - SMTP: mail.kaburu.cc:587 - Auth required with van@thechoppyvan.co.uk credentials - Or use wp-config.php `define('SMTP_HOST', 'mail.kaburu.cc')` with plugin