4.0 KiB
PLAN — Bike-Tinder
Status: Build phase — Phase 1 complete (2026-11-10); Phase 2 not yet started. Phases are gated: each lands, is verified, then the next begins. Glenn's standing rule applies — "pause" stops all spend immediately.
v1 goal
A single-source, single-user, tailnet-only Tinder-style PWA on the Rotarran: nightly-updated catalog, swipe deck (Like / Nope / Maybe), full editable list, taste-ranked ordering.
Phase 0 — Planning
- Engineering consultation (Torres) → memo
- Design docs in this repo: SOURCES, DESIGN, DATA-MODEL, RANKING, UI-SPEC
- Glenn's calls (2026-11-10): v1 source = Kijiji · deck = show all, taste-ranked · new-bike feed = in-app badge only
- Repo housekeeping (2026-11-10): branches
dev/main/release· dedicatedbike-tinder-importcron (parked for deploy) · stack-owned Tailscale sidecar in the deploy plan - Build gate opened — Glenn green-lit (2026-11-10)
- Exit criteria: docs merged to
main(done 2026-11-10); source decision recorded inSOURCES.md.
Phase 1 — Data spine
Status: complete (2026-11-10). Built by Torres on dev (5bf180c..19e46cd), independently re-verified by Alex (fresh-DB import x2, deck CLI, 8/8 selfcheck), merged to main (d890dcd). Live result: 640 rows → 560 active + 80 dup; deck top = Indian Scout family (91) then Vulcan 900 Classic (73).
(Build work lands on dev; verified milestones merge to main; deploys track release.)
- DB schema + migrations (SQLite)
- Importer: source catalog → upsert into DB (new / changed / gone states)
- Cold-start scoring wired (existing rubric logic)
- Proof: CLI query shows a ranked, deduped queue from the real live catalog
- Exit criteria: importer runs clean twice in a row (done — idempotent); counts reconcile against the source (done — 560+0+80=640); no schema surprises (done).
Carried into Phase 2 from P1 findings:
- Dedupe pairing refinement — multi-unit dealer groups (BMW G 310 R, 2 groups) over-merge under the v1 collapse-to-one rule;
min(ns,nb)pairing → 77 dup, keeps sibling rows visible. Revisit before launch. - Image backfill is priority — only ~20/640 rows carry an image in the state; the DESIGN bootstrap backfill is essential for the deck.
- Dealer-blast mitigation + Stage 1.5 swipe boost matter immediately — only ~67/560 active rows are family-scored; the rest sort below.
Phase 2 — The swipe app (core)
- 2–3 UI mock variants → Glenn picks one
- API (queue, swipe, edits, filters) + PWA frontend: card stack, drag physics, Like / Nope / Maybe, match moment
- Full list view with inline edit; basic filters
- Proof: runs locally, exercised on Glenn's phone over the tailnet dev port
- Exit criteria: Glenn can swipe a real deck on his phone and edit results in the list.
Phase 3 — Personalization
- Swipe history → nightly retrain of explainable ranking
- Trends panel ("you lean: …"); "because you liked X" chips
- Deck ordering by learned taste with cold-start guardrails
- Exit criteria: after ~30 swipes, deck order visibly reflects taste; explainability shown in UI.
Phase 4 — Deploy + automate
- Podman compose stack at
/var/mnt/DATA/podman-stacks/bike-tinder/+ systemd unit (Delegate=yes) + in-stack Tailscale sidecar servinghttps://biketinder.tailf35a34.ts.net; PWA install on Glenn's phone - Enable the new
bike-tinder-importHermes cron (08:30 daily, post-hunt; script-only, zero LLM; parked until deploy); DB backup routine - Runbook in DESIGN.md; announce + handover note
- Exit criteria: survives a reboot; refreshes overnight unattended; installable and used from the phone.
Non-goals (v1)
- Multi-user accounts, social features, comments
- Additional sources (v2+); Facebook (never — manual by Glenn)
- Notifications beyond what already exists (Conduit is the house channel)
- Buying workflow (contact/inspection tracking) — possible v2
Open decisions
- v1 source — resolved 2026-11-10: Kijiji (see
docs/SOURCES.md) - Mockup direction — Glenn picks at Phase 2 start