fc5df28b8c
Two taxonomy stamps, validation/module + 412 hash mismatch, SKU charset vs UTF-8 titles, 409 open_existing required, draft = phone form + failed row.
173 lines
7.8 KiB
Markdown
173 lines
7.8 KiB
Markdown
# SlabUploader UX — POC interaction spec
|
||
|
||
Status: SPEC · 2026-09-01 · issue #10 (presentation) · functional rules in #9 / AGENTS
|
||
This is the UAT-facing interface contract. Wireframes are described as screens and states, not pixels. Implementers and testers use this file plus `AGENTS.md` and `docs/TECH-SPEC-PIPELINE.md`.
|
||
|
||
Functional numbers (0.7 threshold, empty vs prefill) live in AGENTS §6. This file only says how those rules look and feel.
|
||
|
||
---
|
||
|
||
## 0. Principles
|
||
|
||
- One-handed phone, outdoor or mill-floor lighting, thumb reach.
|
||
- The user always sees what is missing **on the field**, not only after Submit.
|
||
- Manual values always beat inference. Empty is honest; fake prefill is not.
|
||
- No raw HTTP codes or stack traces. Recovery stays on the same screen as the field.
|
||
|
||
Mandatory before **ready** (continue to publishable):
|
||
|
||
- exactly **one species**
|
||
- **at least one wood category**
|
||
- **at least one figure** (`fig-*` or the Figure attribute — same locked set as DATA-MODEL)
|
||
|
||
Issue #9 named species + ≥1 figure as the confidence-gate floor. Wood category is also required to list (original product). Presentation treats all three as mandatory with inline nudges (#10).
|
||
|
||
---
|
||
|
||
## 1. First-run (calibration trick)
|
||
|
||
Not OpenCV ruler detection (that path is deferred). First launch of capture shows a short overlay, dismissible, remembered in localStorage:
|
||
|
||
1. Lay the slab on a **green or black sheet**.
|
||
2. Shoot **top-down**, lens parallel to the broad face.
|
||
3. Put a tape or known length along the prevailing grain so *you* can type length in inches. The app does not read the tape.
|
||
4. Take 1–5 photos. Confirm the mask before trusting numbers.
|
||
|
||
Skip control: “Don’t show again.” Reset lives in Settings, not on the capture chrome.
|
||
|
||
---
|
||
|
||
## 2. Capture — mask is the load-bearing step
|
||
|
||
Background removal defines the pixel footprint. Length, widths, sqft, and bdft all sit on that mask. A clipped or fat mask silently moves the bounding rectangle and the 6" width samples.
|
||
|
||
### Layout (one screen)
|
||
|
||
- Full-bleed photo with **mask overlay** on the original (included vs excluded), not only the cropped PNG.
|
||
- Four knobs **on this screen**, next to the preview — never a trip to Settings:
|
||
- Sheet: auto / green / black
|
||
- Sensitivity
|
||
- Edge offset
|
||
- Feather
|
||
- Confirm edge. Then length-axis overlay (rotate / confirm). Then length, thickness, SKU.
|
||
- Retake photo. POC does **not** show “Try harder” (server U2Net). That control is deferred, not deleted — do not remove it from architecture docs.
|
||
|
||
### Live re-run
|
||
|
||
Changing any knob re-runs client background removal on the current photo and refreshes the overlay immediately. No save button for knobs. No server round trip for mask tuning in POC.
|
||
|
||
### Empty / error states (capture)
|
||
|
||
| Situation | What the user sees |
|
||
|---|---|
|
||
| Sheet color not auto-detected | Prompt: pick green or black. Stay on this screen. |
|
||
| Mask not one contiguous slab | Banner on the photo: “Cut is broken — retake or tighten the sliders.” Confirm stays disabled. |
|
||
| Axis looks wrong | Rotate control; if still wrong, retake. |
|
||
| After crop, shorter side would be < 1600px | Warn: this photo cannot list until retake. No fake upscale. |
|
||
| User tries to continue without confirming mask | Confirm is the gate; Continue is disabled until confirm. |
|
||
|
||
Knobs persist in localStorage (reset-to-default in Settings). They are not server secrets.
|
||
|
||
---
|
||
|
||
## 3. Review screen
|
||
|
||
After calibrated upload (and Call 1 if inference is on).
|
||
|
||
### Field rendering
|
||
|
||
| Call 1 confidence | Species, wood categories, edge, figure, grade, feat-* |
|
||
|---|---|
|
||
| **≥ 0.7** (default; configurable in server settings later, not a POC slider) | Prefill from Call 1. Every value is editable. Show a quiet “suggested” affordance, not a lock. |
|
||
| **< 0.7** | Leave **empty**. Do not stash the low-confidence guess in a hidden field. |
|
||
| Inference OFF | Empty; user fills by hand. Same mandatory set. |
|
||
|
||
Pickers for species, wood category, and figure list **only** Woo-synced leaves. No “other”, no hardcoded mill list. A species that appeared in Woo after last sync is invisible until the next successful sync.
|
||
|
||
Price: recommendation from species $/bdft × bdft when a rate exists; otherwise empty. Override always allowed.
|
||
|
||
Title / description: empty until the user taps **Generate text** (Call 2) or types. Call 2 never auto-runs.
|
||
|
||
### Per-field nudges (not submit-only)
|
||
|
||
While a mandatory field is empty, that control shows an inline state (mark + short line under the field):
|
||
|
||
- Species: “Pick the species from the store list.”
|
||
- Wood category: “Pick at least one wood category.”
|
||
- Figure: “Pick at least one figure.”
|
||
|
||
Nudges appear as soon as the screen loads with empties, and clear when the field is valid. Submit/Continue to ready stays disabled while any of the three is empty — **and** the user can still see which one without scrolling to a toast after tap.
|
||
|
||
Do not use a single post-submit modal as the only signal.
|
||
|
||
### Overrides
|
||
|
||
Changing a prefilled species/figure is a normal edit. No confirm dialog. Manual value is what publishes.
|
||
|
||
---
|
||
|
||
## 4. Settings (relevant bits)
|
||
|
||
- **Store URL**: read-only text from `WOO_BASE_URL` (compose). Not an input.
|
||
- Woo username + application password: inputs. Password never round-trips on GET.
|
||
- Inference endpoint + key + model; enable flags.
|
||
- Species $/bdft table (seeded from synced species only).
|
||
- `woo_create_status` draft | publish.
|
||
- Reset capture knobs to factory.
|
||
- Manual “Refresh taxonomy” is optional for POC; test-connection always syncs.
|
||
|
||
---
|
||
|
||
## 5. Validation (field exit and submit)
|
||
|
||
Shared module on FastAPI (`docs/OPENAPI.md`). Client caches it; hash checked **on submit**, not on every blur.
|
||
|
||
- Blur: local check with cached rules. Required fields block; optional empty is valid; optional with content must pass.
|
||
- Length: hard cap at the Woo limit (cannot type past it).
|
||
- Character set: SKU `[A-Z0-9-]{3,24}`; title/description UTF-8 within Woo max. Invalid characters rejected on exit. Not “extended ASCII”.
|
||
- Submit: full pass + hash check. Mismatch → “Updating rules” (HTTP 412, never shown) → re-validate → retry. No data loss.
|
||
|
||
Presentation: errors sit under the field. No top-of-screen dump for field problems.
|
||
|
||
---
|
||
|
||
## 6. Publish errors (after commit)
|
||
|
||
The phone keeps the form. The server slab goes `failed` (retryable). No IndexedDB.
|
||
|
||
**409 duplicate SKU** — inline on SKU:
|
||
|
||
- “This SKU already exists in the store (any status).”
|
||
- Actions: **Edit SKU** (focus the field) · **Open existing listing** (required). Use the admin URL/id when the server returned them; otherwise keep the button and “look this SKU up in Woo admin”.
|
||
- Never show `409` as the message.
|
||
|
||
**422 stale value** — inline on the field Woo rejected (category, attribute, price, …):
|
||
|
||
- “This value is no longer valid. Pick from the current list.”
|
||
- Options from the synced cache after the submission-time refresh.
|
||
- Never show `422` as the message.
|
||
|
||
Server 5xx / timeout / auth: one recoverable banner (“Couldn’t reach the store — try again”), draft intact. Not a field nudge.
|
||
|
||
---
|
||
|
||
## 7. UAT can write cases against
|
||
|
||
1. First-run overlay appears once; skip persists.
|
||
2. Knobs on capture; each slider live-reruns mask overlay on the source photo.
|
||
3. Confirm disabled until mask is contiguous.
|
||
4. Review with inference ON and confidence ≥ 0.7: fields filled, editable.
|
||
5. Review with confidence < 0.7: species/wood category/figure empty; inline nudges; cannot mark ready until all three satisfied.
|
||
6. Species picker contains only synced names; typing a non-synced name is impossible.
|
||
7. Duplicate SKU: inline SKU recovery, two actions, no raw code.
|
||
8. Stale category after sync: 422 copy on that field with current options.
|
||
|
||
---
|
||
|
||
## 8. Non-goals (this spec)
|
||
|
||
- Visual branding, type scale, color tokens.
|
||
- Server U2Net “Try harder” control (deferred).
|
||
- Configurable 0.7 slider in the UI.
|
||
- Offline / airplane-mode chrome.
|