diff --git a/CLAUDE.md b/CLAUDE.md index 2288b26..c8d94d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ Full design lives in `docs/spec.md` (read it before changing pipeline semantics) ## Commands - `uv sync` — install deps (Python 3.12+, managed by **uv**; use `uv add`, never pip). `uv run bggpipe init` handles first-run setup (folders, .env credentials, the one-time `playwright install chromium`). -- `uv run bggpipe web` — the app: seven pages (Pipeline `/`, Photos, Titles, Review, Queue, Library, Help) in a shared sidebar shell (responsive: hamburger nav + stacked tables under 900px); stage runs execute one-at-a-time in a background job. `--lan` binds 0.0.0.0 behind a per-device access key: persisted in `data/.lan_key` (gitignored), printed as a QR at startup, cookie-paired for a year, required on EVERY network request (loopback clients and `/static/*` are exempt; the Host/Origin guard still applies). Phone camera uploads (generic `image.jpg` names) get minted `shelf-` names — only explicitly-named files trigger the replace-to-reshoot flow. +- `uv run bggpipe web` — the app: eight pages (Pipeline `/`, Photos, Titles, Review, Queue, Library, Shelves, Help) in a shared sidebar shell (responsive: hamburger nav + stacked tables under 900px); stage runs execute one-at-a-time in a background job. `--lan` binds 0.0.0.0 behind a per-device access key: persisted in `data/.lan_key` (gitignored), printed as a QR at startup, cookie-paired for a year, required on EVERY network request (loopback clients and `/static/*` are exempt; the Host/Origin guard still applies). Phone camera uploads (generic `image.jpg` names) get minted `shelf-` names — only explicitly-named files trigger the replace-to-reshoot flow. - `uv run bggpipe ` — run a pipeline stage. Non-secret settings come from `config.toml` (dirs, rate limit, `vision_provider` + per-provider `[vision.*]` blocks — "anthropic" or any OpenAI-compatible endpoint incl. local Ollama); `--config` overrides the path. - `uv run pytest` — the suite runs fully offline against fixtures. Tests marked `live` hit the real BGG API (read-only) and are skipped unless you pass `--run-live`. - `uv run ruff check` / `uv run ruff format` — lint (rules E, F, I, UP, B, SIM) and format. diff --git a/README.md b/README.md index 0ed97f9..55e42f4 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Everything runs locally, every stage survives being killed mid-run, and all arti ![Pipeline dashboard: six stage cards with live counts and Run buttons, showing a completed pipeline — 136 titles extracted, 115 resolved, 62 games added, 136 in the library](docs/screenshots/01.png) -**➔ [See the full tour](docs/tour.md)** — all seven pages, the game-detail view, and the phone experience. +**➔ [See the full tour](docs/tour.md)** — all eight pages, the game-detail view, and the phone experience. ## Requirements diff --git a/data/furniture.json b/data/furniture.json index 70289cc..91c3729 100644 --- a/data/furniture.json +++ b/data/furniture.json @@ -115,7 +115,8 @@ "height_in": 13.25, "depth_in": 15.4 } - ] + ], + "description": "Centerpiece of the game wall in the library" } ] } diff --git a/docs/guide.md b/docs/guide.md index fcb6469..474374b 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -40,7 +40,7 @@ Non-secret knobs live in `config.toml`: `photos_dir`, `data_dir`, the BGG rate l bggpipe web # opens http://127.0.0.1:8377/ — the whole app in the browser ``` -Seven pages — Pipeline, Photos, Titles, Review, Queue, Library, and Help — all [pictured in the tour](tour.md). Stage runs execute one at a time in the background with live output: +Eight pages — Pipeline, Photos, Titles, Review, Queue, Library, Shelves, and Help — all [pictured in the tour](tour.md). Stage runs execute one at a time in the background with live output: ![The Pipeline page mid-extract: stage cards above a live activity log listing each photo and how many titles it yielded](screenshots/15-extract-live.png) @@ -111,26 +111,48 @@ BGG application approval can take a week or more. Until then: `extract` works im ## Where everything lives -The **Shelves** page maps your physical storage: create units from presets -(IKEA Kallax cube 13.25″ × 13.25″ × 15.4″, Billy shelf, custom sizes) as -grids of rows × columns, add one-off openings (double-wides, a top shelf), -and no-size virtual spots ("travel case", "lent out"). Openings carry free- -text zones, are editable and reorderable, and everything lands in -`data/furniture.json` + `data/locations.json` — committed local stores; +The **Shelves** page maps your physical storage and draws it as it really +stands: openings group into rows by their label letters, and each cell's +width is proportional to its interior width, so a Kallax with a double-wide +top row renders as exactly that — a diagram of the wall, not a list. Create +units from presets (IKEA Kallax cube 13.25″ × 13.25″ × 15.4″, Billy shelf, +custom, or a no-size virtual spot like "travel case") as grids of rows × +columns; add more sections to an existing unit the same way — a later grid +continues the row letters, so 3 × 4 under an A row lands as B1…D4. Openings +are editable (dimensions are all-or-none: three numbers or a no-limit +spot), reorderable within their row (moves clamp at row boundaries so the +diagram can't fragment), and deletable. Both units and openings take a +free-text **description** alongside the **zone** keyword — the label is +the address, the zone matches, the description explains. Everything lands +in `data/furniture.json` + `data/locations.json` — committed local stores; your shelf layout is never sent anywhere. -Assign games by tapping an unshelved game's suggested openings (only -openings it actually fits, with room to spare), by searching inside an -opening, or from a game's detail page (openings grouped by unit, each -labeled fits / doesn't fit / can't verify). Games stored inside another -box inherit their container's spot. On a phone over `--lan`, the opening -view docks as a bottom sheet — the moving-day loop is search, tap, done. +Assigning games: every measured unshelved game shows up to three suggested +openings, ranked by a strict relevance doctrine. An opening already holding +a **series-mate or base game ranks first** (marked ♥) — kinship is the +pre-colon name stem plus BGG's series field, no taxonomy to maintain, so +every placement you confirm teaches the suggester your organization and +expansions chase their base games automatically. "Fits" always means the +**remaining** opening — stack budget already spent is subtracted — and +after that, tightest verified fit, so small boxes are offered cubes and +never the oversize row. A measured game with nowhere suitable says +"no matching openings yet"; an unmeasured game gets no suggestions at all, +because can't-verify is not the same as fits. You can also assign by +searching inside an opening, or from a game's detail page (openings +grouped by unit, each labeled fits / doesn't fit / can't verify). Games +stored inside another box inherit their container's spot — through whole +chains (minis in an insert in a big box live where the big box does). On a +phone over `--lan`, the opening view docks as a bottom sheet — the +moving-day loop is search, tap, done. Bulk-load a reviewed plan with `bggpipe shelve --import plan.csv` (columns `name,opening`, accepting opening ids or labels) — rejects are reported (unknown name, ambiguous copies, unknown opening, doesn't fit, lives -inside another box), never guessed. `bggpipe dims` reports per-opening -capacity, overfull warnings, and misfits against your real furniture. +inside another box), never guessed, and re-imports preserve hand-entered +notes. `bggpipe dims` reports per-opening capacity, overfull warnings, and +misfits against your real furniture. Fill bars measure stacked thickness +against interior height (boxes lying flat); unmeasured boxes are counted +and shown, never silently assumed to fit. ## Shelf-space planning diff --git a/docs/screenshots/17-shelves.png b/docs/screenshots/17-shelves.png new file mode 100644 index 0000000..bcffc93 Binary files /dev/null and b/docs/screenshots/17-shelves.png differ diff --git a/docs/tour.md b/docs/tour.md index af7b1db..6f4faa6 100644 --- a/docs/tour.md +++ b/docs/tour.md @@ -1,6 +1,6 @@ # A tour of bggpipe -Seven pages in one local app — Pipeline, Photos, Titles, Review, Queue, Library, and Help. Every screenshot below is the real app on the author's real shelves, and the end product is public: [the author's BGG collection](https://boardgamegeek.com/collection/user/ewagoner) is what this pipeline built. (Back to the [README](../README.md) · how to use it all: the [user's guide](guide.md).) +Eight pages in one local app — Pipeline, Photos, Titles, Review, Queue, Library, Shelves, and Help. Every screenshot below is the real app on the author's real shelves, and the end product is public: [the author's BGG collection](https://boardgamegeek.com/collection/user/ewagoner) is what this pipeline built. (Back to the [README](../README.md) · how to use it all: the [user's guide](guide.md).) **The Pipeline page** — every stage is a card with live counts and a Run button; blockers (missing token, stub-data lock) surface as banners, not surprises. Here: the settled state after a full run — 136 titles read, 115 matched, 62 added. @@ -34,6 +34,10 @@ Seven pages in one local app — Pipeline, Photos, Titles, Review, Queue, Librar ![Game detail page for Britannia: box art beside player counts, playing time, weight, rank, designers and mechanics as chips, with a Your Edition card naming the owned printing](screenshots/10-game-detail.png) +**Shelves** — your furniture drawn as it stands: units render their physical arrangement (a double-wide top row spans the top), with fill bars, zones, and a suggestion engine that learns your organization from every placement you confirm. + +![Shelves page: the add-a-unit form with presets above a Library Kallax unit drawn as its real arrangement — two double-wide openings spanning the top, three rows of four cubes beneath, each with zone label and fill bar](screenshots/17-shelves.png) + **Help** — the whole flow, every page, every status, and every keyboard shortcut, documented in-app. ![Help page documenting the shelves-to-collection flow, what each page is for, and the proofreading and review checkpoints](screenshots/07.png) diff --git a/src/bggpipe/templates/pages/help.html b/src/bggpipe/templates/pages/help.html index 5753a72..5606182 100644 --- a/src/bggpipe/templates/pages/help.html +++ b/src/bggpipe/templates/pages/help.html @@ -30,7 +30,7 @@

Titles — every read off your shelves, alphabetized, with its status and photos. This is the proofread checkpoint: edit, split, remove. Its badge counts shaky read lines — the model wasn't sure and nothing has verified them; filter to them, then press ✓ looks right or edit each one.

Review — the decisions only you can make: which game a title is, which edition a copy is, whether two same-game reads are really one box (merges show a veto), and whether an unmatched title is a real game BGG simply doesn't have (keep locally: it joins the Library, never uploads). Keyboard-first; see shortcuts.

Queue — exactly what upload will do (new entries and version upgrades) and the log of everything it has done. Nothing reaches BGG that isn't visible here first. A job that fails is skipped by later runs (so one broken game can't loop forever); when any exist, the Pipeline's upload card offers a retry N failed checkbox. Each queued row shows what upload did with it — pending, done, failed, or retired (a review decision since the last diff withdrew it). Finished rows stay listed until the next diff rebuilds the queue; the log below them is the permanent record.

-

Shelves — where everything physically lives. Describe your furniture once (presets for Kallax cubes and Billy shelves, grids of rows × columns, custom sizes, and no-size spots like a travel case), then assign games to openings — by tapping suggestions next to unshelved games, by searching inside an opening, or from any game's detail page. Fill bars show stacked thickness against interior height; ⚠ flags overfull openings and boxes that can't fit. Games stored inside another box ride along with their container. Your layout is local data only — never sent anywhere. Bulk-load a plan with bggpipe shelve --import plan.csv (name,opening) and check capacity anytime with bggpipe dims.

+

Shelves — where everything physically lives, drawn as it really stands: openings group into rows by label letter with widths proportional to their interiors, so the page is a diagram of your wall. Describe furniture once (presets for Kallax cubes and Billy shelves, grids of rows × columns — a later grid continues the row letters — custom sizes, and no-size spots like a travel case); units and openings both take a free-text description beside the zone keyword. Suggestions rank an opening holding a series-mate or base game first (marked ♥ — every placement you confirm teaches the suggester your organization), always against the remaining room, then tightest verified fit; a measured game with nowhere suitable says "no matching openings yet", and unmeasured games get no suggestions because can't-verify ≠ fits. Assign by tapping suggestions, searching inside an opening, or from any game's detail page. Fill bars show stacked thickness against interior height; ⚠ flags overfull openings and boxes that can't fit; games stored inside another box ride along with their container, through whole chains. Your layout is local data only — never sent anywhere. Bulk-load a plan with bggpipe shelve --import plan.csv (name,opening) and check capacity anytime with bggpipe dims.

Library — your enriched collection. Search titles, designers, mechanics and categories at once; filter by kind (board games, RPGs, off-BGG) or by how many people are playing tonight; sort by name, year, BGG rank, weight, or playing time. Click any game for its full detail: art, the usual stats, designers and mechanics, your edition, the shelf photos it was read from, and a link to its BGG page. RPG and off-BGG games live here too — identified and enriched, never uploaded. RPGs pull their designers, publishers and genres from RPGGeek; an off-BGG game's detail page lets you write its facts yourself and add a cover photo, since nothing else will ever have them (both are saved under data/ and folded in by the next enrich).