docs: B1 (photo experience v2) contract frozen — UI-SPEC §11 (galleries, photo flip, fullscreen viewer, repeat rotation), DATA-MODEL B1 additions; PLAN/BACKLOG: B1 pulled forward before Phase 4

This commit is contained in:
AlexanderRozhenko
2026-11-10 23:57:33 -04:00
parent 8c1946db8e
commit 6de2fcc1bd
4 changed files with 66 additions and 1 deletions

View File

@@ -172,3 +172,54 @@ Top→bottom:
- Deck buffer source becomes `GET /api/section` (pinned order). All P2 wiring (optimistic swipe + retry queue, badge, SW) unchanged; bump the `sw.js` cache version.
- Card payload additions the FE reads: `slot` ('new'|'return'|'wildcard'), `points`, `tank` {value, band}, `round_next` (1|2, for the SECOND LOOK band copy when needed).
## 11. Photo experience v2 (B1) — galleries, photo flip, fullscreen viewer
**Frozen 2026-11-10 (Glenn approved: gesture map + repeat rotation picked by him in chat).** Additive; §1–§10 remain in force except where explicitly superseded here (§2's "Tap … → dossier" and §3's "(or tap)" are retired — §11.4).
### 11.1 Galleries
- Every listing carries its full photo gallery: `imgs[]` (page order, deduped by image id; entry 0 = the established primary = today's `img`/`img_url`).
- Every gallery image is mirrored locally (`data/img/{id}_{n}.webp`) and served by the app (`GET /img/{id}?i={n}`, `i` default 0; falls back into the §7.6 chain). The client never hotlinks directly.
- Zero photos → §2 placeholder; one photo → single photo, no segments, no flip.
### 11.2 Photo flip (deck card — top card only)
- Tap LEFT third → previous photo; tap RIGHT third → next photo. **Clamp at the ends** (no wrap). Tap test = §2's (≤6px movement on pointerup); a tap inside the ⓘ button hits ⓘ, not the zones.
- Segment indicator bars: one segment per photo along the top edge of the photo, centered, ~3px tall; current = solid white, others `rgba(255,255,255,.35)`; Tinder-style. (§10.3 amendment: when segments are present, band chips render at `top:22px`; no other change to §10.3.)
- Flip is instant, commits nothing, locks nothing (§2 THE law). A drag that starts anywhere still drags for LIKE/NOPE/MAYBE — the zones apply to taps only.
- Photo position is per-card-session state; a card re-shown fresh returns to §11.5's lead photo.
### 11.3 Fullscreen viewer
- Tap the CENTER third → fullscreen viewer opens on the photo currently shown.
- Viewer: horizontal swipe = prev/next (clamp); pinch-zoom + double-tap = zoom (1×–~4×); segment bars stay visible; close via ✕ (36px, top-left) or pull-down (grabber or photo, `dy > 110` — the §3 idiom). Closing returns to the same card, same photo position; deck state untouched.
- Also opens from the dossier hero (starts at photo 0). Same sheet geometry as the dossier (z-band 69/70), photo-first: no body, no actions row.
### 11.4 Doors (supersedes the old tap→dossier)
- ⓘ (top-right of card) → dossier (unchanged). The card face now owns: **sides = flip, center = fullscreen**; the "tap anywhere → dossier" gesture is RETIRED.
- The dossier stays reachable from ⓘ and from list rows (§3/§4 unchanged).
### 11.5 Repeat rotation
- A listing presented again (second look / re-show) opens on a different photo than the last one viewed: lead = `(last_photo_idx + 1) % n`; no stored index → photo 0.
- The index is persisted server-side at swipe-commit time (survives sessions and devices; works with §7.2's optimistic retry queue).
- List thumbnails and the dossier hero keep photo 0 (the canonical shot) — rotation is deck-only.
### 11.6 Performance & invariants
- Preload the top card's next photo and the next card's lead photo; decode off the critical path; **no network on the swipe path** (all mirrored locally).
- Stack metrics, `.topcard`, z-order law, stamps, undo, no-lock — all §2 laws untouched. Bands and segments coexist per §11.2.
### 11.7 Acceptance (B1)
Machine-checkable:
- Gallery capture ≥1 photo for every listing with a page image; multi-photo listings show N segments = N photos; the mirror holds all gallery files; `/img/{id}?i=n` answers for every n.
- Flip: left/right taps advance and clamp; a tap never commits (no stamp flash, no flight); drag-commit regression passes (fast-chain, no-lock, one `.topcard`).
- Viewer: opens from center tap and dossier hero; swipe/zoom/close work; close restores the card and photo position.
- Rotation: a re-shown card leads at `last+1`; persisted across page reload (server-side).
- Fallbacks: 0-photo placeholder, 1-photo (no segments), broken file → §7.6 chain.
- All §9/§10 acceptance re-run green.
Human: Glenn flips photos on his phone, opens fullscreen, and sees a fresh photo on a repeat — the B1 exit criterion.