docs: initial set - README, PLAN, UI-SPEC, RANKING
This commit is contained in:
38
README.md
Normal file
38
README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Bike-Tinder
|
||||
|
||||
A private, Tinder-style web app for browsing the motorcycle market: swipe real listings (like / nope / maybe), see everything on one editable list, and let the deck learn your taste. Built for Glenn; runs on the Rotarran, published to the tailnet only.
|
||||
|
||||
**Status:** v0.1 — design phase. No code yet; this repo currently holds the design docs. Build begins once the docs are approved.
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
[single-source crawler] → [nightly importer] → [app DB] → [API + PWA deck] → Glenn's thumb
|
||||
↓
|
||||
[swipe history] → [ranking]
|
||||
```
|
||||
|
||||
- **Crawl** — one marketplace source (chosen for scrape-simplicity; see `docs/SOURCES.md`) is fetched nightly by a pure script. No LLM involved, zero token cost.
|
||||
- **Import** — the importer upserts the source's catalog into the app database: new listings appear, changes update, vanished listings retire after repeated misses (never a blocked page, never a guess).
|
||||
- **Deck** — a Tinder-like PWA: card stack, drag to swipe, big buttons. Like / Nope / Maybe. "It's a match" moment when you like something.
|
||||
- **List & edit** — every entry in one table; re-file any call later (a nope can become a like).
|
||||
- **Ranking** — cold start uses the hunt's rubric score; after ~20–30 swipes a small, explainable model orders the deck by *your* taste (retrained nightly). "Because you liked X" chips, never a black box.
|
||||
|
||||
## Docs
|
||||
|
||||
- [`docs/SOURCES.md`](docs/SOURCES.md) — the v1 source decision (candidates, evidence, choice)
|
||||
- [`docs/DESIGN.md`](docs/DESIGN.md) — architecture, components, data flow, deployment
|
||||
- [`docs/DATA-MODEL.md`](docs/DATA-MODEL.md) — database schema + sync semantics
|
||||
- [`docs/RANKING.md`](docs/RANKING.md) — cold-start + learned ranking design
|
||||
- [`docs/UI-SPEC.md`](docs/UI-SPEC.md) — screens, gestures, Tinder-fidelity goals
|
||||
- [`docs/PLAN.md`](docs/PLAN.md) — phases, acceptance criteria, status
|
||||
|
||||
## Deployment (planned)
|
||||
|
||||
A small podman compose stack on the Rotarran under `/var/mnt/DATA/podman-stacks/bike-tinder/`, its own systemd user unit (`Delegate=yes`), SQLite database, published to the tailnet only via `tailscale serve` on port 9453. Single user; no auth beyond the tailnet.
|
||||
|
||||
## Crew
|
||||
|
||||
- **Glenn** — owner; the thumb that swipes.
|
||||
- **Alex** — resident agent; architecture, orchestration, docs.
|
||||
- **Torres** — engineer; builds and maintains this repo.
|
||||
57
docs/PLAN.md
Normal file
57
docs/PLAN.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# PLAN — Bike-Tinder
|
||||
|
||||
**Status:** Planning (2026-11-10). 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
|
||||
|
||||
- [x] Engineering consultation (Torres) → memo
|
||||
- [x] Design docs in this repo: SOURCES, DESIGN, DATA-MODEL, RANKING, UI-SPEC
|
||||
- [ ] Glenn's read on source choice + docs
|
||||
- **Exit criteria:** docs merged to `main`; source decision recorded.
|
||||
|
||||
## Phase 1 — Data spine
|
||||
|
||||
- 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; counts reconcile against the source; no schema surprises.
|
||||
|
||||
## 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`)
|
||||
- Tailscale serve on 9453; PWA install on Glenn's phone
|
||||
- Nightly no-LLM importer cron (post-crawl); 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 — pending consultation evidence (see `docs/SOURCES.md`)
|
||||
- Mockup direction — Glenn picks at Phase 2 start
|
||||
34
docs/RANKING.md
Normal file
34
docs/RANKING.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# RANKING — Bike-Tinder
|
||||
|
||||
The deck is ordered by predicted taste. Two stages: a cold start (the hunt's existing rubric), then a small learned model that never becomes a black box.
|
||||
|
||||
## Signals
|
||||
- Like = strong positive (+1). Maybe = weak positive (+0.25, kept in its own bucket). Nope = negative (−1). List-view edits count identically to in-deck swipes; the latest call wins.
|
||||
- Planned v2 signals: dwell time on card, "open listing" click-outs.
|
||||
|
||||
## Features (v1)
|
||||
Per listing: family tier (from the hunt rubric), displacement (cc), price, year, km, km/year, dealer vs private, place/region, keyword flags from title + description (MVI/inspection, whitewalls, spokes, windshield, saddlebags, ABS, bobber/custom), color words (red is known lore), title tokens (make/model). Numeric features normalized; missing values neutral.
|
||||
- Single-source v1 makes source/region features near-constant — kept in the schema for v2.
|
||||
|
||||
## Stage 1 — Cold start
|
||||
Order by the hunt's existing rubric score (family tiers + MVI / whitewalls / windshield / spokes / ABS bonuses + price fit). This is already explainable (reason strings exist in the hunt system). Deck = rubric order until ≥ 20 swipes.
|
||||
|
||||
## Stage 2 — Learned order
|
||||
- Model: logistic regression on the features above; target = like vs nope (maybes contribute softly positive). Trained on all swipe history including edits.
|
||||
- Pure-Python or numpy implementation (tiny data — no heavy ML dependency). Params + training metadata live in the DB; versioned.
|
||||
- Retrain nightly right after import; on-demand retrain available from the app.
|
||||
- Guardrails:
|
||||
- Blend: until 100 swipes, deck order = 50% rubric rank + 50% model rank; after, model order with an exploration slice (roughly every 8th card = top-rubric card not yet shown).
|
||||
- Never hide: everything stays in List; ranking only reorders the deck.
|
||||
- Sanity: if model like-rate underperforms the rubric baseline (tracked weekly), it reverts to rubric order silently.
|
||||
|
||||
## Explainability
|
||||
Each card can show up to 2 chips: top positive contributions for that bike ("low km for the money", "Vulcan family", "red", "MVI"). Chips derive from the live feature contributions; during cold start they come from the rubric's existing reasons.
|
||||
|
||||
## Evaluation
|
||||
- Track: swipes/session, like-rate trend, maybe-rate, undo rate, and "liked-item rank" (how deep liked items sat — should trend shallow).
|
||||
- Optional weekly digest via Conduit if Glenn wants it (default: silent).
|
||||
|
||||
## Open decisions
|
||||
- Maybe-handling: weak positive + separate bucket (proposed) vs pure third bucket — confirm with Glenn at Phase 2.
|
||||
- Distance feature (map-based proximity) — likely v2.
|
||||
45
docs/UI-SPEC.md
Normal file
45
docs/UI-SPEC.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# UI-SPEC — Bike-Tinder
|
||||
|
||||
Fidelity goal (Glenn's words): "as close to Tinder as possible." Photo-first, dark, big gestures. Everything below is the v1 spec; 2–3 visual mock variants get built at Phase 2 start and Glenn picks one before wiring proceeds.
|
||||
|
||||
## Screens
|
||||
|
||||
### 1. Deck (default)
|
||||
- Full-height card stack: the top card is draggable; the next card peeks, scaled (~95%) behind it.
|
||||
- Card anatomy: photo fills the card; bottom gradient overlay carries: year + make + model (title), price (large), sub-line: km · place · first seen. Small chips row when signals exist (e.g. "MVI", "whitewalls", "bags") — only derived from real listing data, never invented.
|
||||
- Stamps: during drag, "LIKE" (green) / "NOPE" (red) / "MAYBE" (amber) stamps fade in over the card proportional to horizontal drag; rotation up to ±12° follows the finger.
|
||||
- Commit: release past ~35% width (or a flick with velocity) → the card flies off; otherwise it springs back.
|
||||
- Buttons (bottom, thumb zone): ↺ undo · ✕ nope · ★ maybe · ♥ like — 56px circles; the like button carries the accent gradient.
|
||||
- Match moment: committing a Like plays a brief "It's a match!" overlay (bike thumbnail + flame accent, ~1.2s), then advances. No sound in v1 (a muteable chime could come later).
|
||||
- Tap (not drag) on the card = detail sheet: full photo, all fields, description snippet (if crawled), "Open listing" link (source URL), and the three action buttons.
|
||||
- Empty state: "You're all caught up — new bikes arrive nightly" (with the next import time). A fallback image is shown for listings without a photo — no card is ever blank.
|
||||
|
||||
### 2. List (all bikes)
|
||||
- The full catalog. Each row: thumbnail, title, price, km, place, and a 4-state control: ♥ / ★ / ✕ / — (no call yet). Tapping sets or edits the call — edits are first-class (Glenn asked for exactly this).
|
||||
- Filters (persisted): price min/max, km max, year min, text search; clear-all chip. Sort: score | price ↑↓ | newest | km.
|
||||
- Context line: "n new since your last visit".
|
||||
|
||||
### 3. Matches (liked)
|
||||
- Two segments: Liked ("matches") and Maybe. Same row style as List; opens the detail sheet. This is the actual shortlist for buying.
|
||||
|
||||
### 4. Trends (Phase 3)
|
||||
- Swipe stats (counts, like rate), learned lean summary ("you lean: V-twins · <$6k · low-km · NS"), retrain status, and the current top model weights rendered as plain language.
|
||||
|
||||
## Visual language
|
||||
- Dark theme, near-black background, one accent gradient (flame → red/pink), white primary text, ~60% secondary.
|
||||
- Cards: ~16px radius, full-bleed photo, subtle shadow; stamps are 3px outline uppercase, rotated ∓12°.
|
||||
- Type: system stack (SF on iPhone); title 22–24px bold; price 20px semibold.
|
||||
- Bottom tab bar: Deck · List · Matches · Trends (icons + labels), safe-area aware.
|
||||
|
||||
## PWA specifics
|
||||
- `display: standalone`; an install hint covers iOS "Add to Home Screen".
|
||||
- Service worker: cache the app shell only; API always live (tailnet). No offline deck in v1.
|
||||
- Icons 192/512 + maskable; theme color = dark.
|
||||
|
||||
## Interaction invariants
|
||||
- One-hand usable: all primary actions live in the bottom third of the screen.
|
||||
- Animation lock during commit (no double-fire); undo stack ≥ 10 deep.
|
||||
- Every card shows: photo, price, title, place.
|
||||
|
||||
## Acceptance (Phase 2)
|
||||
Glenn can open the PWA from his iPhone home screen, swipe a real deck one-handed, and fix any mis-swipe in the List view — without touching a desktop.
|
||||
Reference in New Issue
Block a user