5df2a20bac5dbd1e5150848685c5acc711524ca5
- create_app(db_path, img_dir, state_dir) factory; every route + payload
from app.state — selfcheck runs the real router on a temp DB copy
- /api/health (ok/db/counts), /api/stats (live/new/likes/maybes/nopes/
last_import), /api/deck (undecided semantics, score/first_seen/id DESC,
opaque '<score>|<first_seen>|<id>' cursor, strictly-after tuple page,
remaining count), /api/swipe upsert + DELETE (idempotent), /api/list
(decision/sort/q/limit/offset, total), /api/listing/{id}, /api/import
(importer, HTTP 200 even when gates fail), /api/badge/seen, /img/{id}
(cached file -> 302 img_url -> 404), static routes (/, manifest, sw.js,
icons, apple-touch; no-cache on index + sw.js)
- frozen payload contract incl. img=/img/{id} when img_url or cached file
- serve.py: argparse (--db/--img-dir/--state-dir/--host/--port, defaults
127.0.0.1:9453) -> uvicorn.run
- verified: 560-deep deck walks clean with zero page overlap, swipe ->
list -> edit -> delete -> back on deck, badge roundtrip (new 560 -> 0);
real uvicorn returns true 302 for the img fallback (TestClient in this
fastapi/httpx pair mangles RedirectResponse into a 404 — framework
artifact, not app behavior)
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 — Kijiji (NS + NB; decided 2026-11-10 — see
docs/SOURCES.md) is swept nightly by the existing hunt crawler; a script-only importer folds the results in. 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; a cheap, fully explainable swipe-boost lands first (v1.x), then a small learned model (Phase 3, retrained nightly) orders the deck by your taste. "Because you liked X" chips, never a black box.
Docs
docs/SOURCES.md— the v1 source decision (candidates, evidence, choice)docs/DESIGN.md— architecture, components, data flow, deploymentdocs/DATA-MODEL.md— database schema + sync semanticsdocs/RANKING.md— cold-start + learned ranking designdocs/UI-SPEC.md— screens, gestures, Tinder-fidelity goalsdocs/PLAN.md— phases, acceptance criteria, status
Branches
main— stable trunk (docs + verified code); the default branch.dev— active development; build work lands here first.release— deployable cuts; the Rotarran stack tracks this branch.
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. The stack ships its own Tailscale node (sidecar container — no host-tailnet coupling) and serves the app privately at https://biketinder.tailf35a34.ts.net. Single user; reachable only from Glenn's own devices.
Crew
- Glenn — owner; the thumb that swipes.
- Alex — resident agent; architecture, orchestration, docs.
- Torres — engineer; builds and maintains this repo.
Description
Releases
2
v1.1.0 — QOL patrol
Latest
Languages
Python
74.7%
HTML
24.6%
JavaScript
0.5%
Dockerfile
0.2%