docs: remove live UX.md
This commit is contained in:
-235
@@ -1,235 +0,0 @@
|
|||||||
# Mill-owner UX — phone and PC browsers
|
|
||||||
|
|
||||||
Status: SIGNED · 2026-09-06 PT · Ty approved with PC browsers in the compatibility matrix · SlabUploader
|
|
||||||
|
|
||||||
This is the presentation spec for the mill-owner flow. It says what a mill owner sees and does, in the
|
|
||||||
order they do it. The rules behind each screen live elsewhere: `AGENTS.md` locks the product
|
|
||||||
decisions, `docs/TECH-SPEC-PIPELINE.md` owns the math and image prep, `docs/DATA-MODEL.md` owns
|
|
||||||
the store row and its statuses, `docs/CONTENT-WOO.md` owns listing copy and the Woo payload,
|
|
||||||
and `docs/OPENAPI.md` owns the wire. This file names what shows up on screen; it does not restate
|
|
||||||
those rules.
|
|
||||||
|
|
||||||
The reader is a mill owner photographing one slab at a time, online, from a supported browser on a
|
|
||||||
phone or a PC. The app is a single column of screens, top to bottom: capture, then review, then
|
|
||||||
publish. There is no dashboard and no batch view in this version. Capture often starts on a phone
|
|
||||||
camera; the same flow must also run on a PC browser.
|
|
||||||
|
|
||||||
## Jobs
|
|
||||||
|
|
||||||
Five jobs cover the whole flow. Each section below names what the owner does, what they see, and
|
|
||||||
the lock that governs it.
|
|
||||||
|
|
||||||
1. **Phone photo to a store listing.** Photograph the slab, confirm the cut and the numbers on
|
|
||||||
the browser, review the listing, create the WooCommerce product. The happy path stays in the
|
|
||||||
browser until the owner confirms the mask and the numbers.
|
|
||||||
2. **Practice drafts customers never see.** A practice run creates a WooCommerce draft with an SKU
|
|
||||||
that starts `SLAB-UAT-`. Customers cannot open it. It is always a draft, even when Settings say
|
|
||||||
publish.
|
|
||||||
3. **Retake when the overlay cut looks wrong.** The mask overlay on the source photo is the only
|
|
||||||
quality check. If the edge is off after tuning the four knobs, the owner retakes the photo.
|
|
||||||
4. **Fill or override store fields.** On review, the owner fills every required field by hand, or
|
|
||||||
keeps what vision filled when it was confident enough. Typed values always win.
|
|
||||||
5. **Publish.** The owner taps publish. The server creates the product in the store and reports the
|
|
||||||
result back on the same screen.
|
|
||||||
|
|
||||||
## Capture: photo to numbers
|
|
||||||
|
|
||||||
The capture flow is one continuous screen with a few confirmations, not separate pages. The owner
|
|
||||||
stays on it from first photo through confirmed mask and axis.
|
|
||||||
|
|
||||||
### Photos
|
|
||||||
|
|
||||||
The owner takes 1 to 5 inventory photos of the slab. The first should be top-down, lens parallel
|
|
||||||
to the broad face; a tilted shot makes square feet and board feet wrong, and retake is the fix.
|
|
||||||
There are no calibration photos in this design. Only inventory photos exist.
|
|
||||||
|
|
||||||
### Mask overlay and four knobs
|
|
||||||
|
|
||||||
The app removes the background sheet and draws the mask as an overlay on the source photo, showing
|
|
||||||
which pixels count as slab and which do not. The owner reviews that edge against the real wood.
|
|
||||||
This is the only quality check in the pipeline. There is no confidence score, no auto-gate, and no
|
|
||||||
photo-quality checker. A clipped or over-inclusive mask shifts every downstream number with nothing
|
|
||||||
later to catch it, so the eye on the overlay is what stands behind the measurement.
|
|
||||||
|
|
||||||
Four knobs sit on this same screen, next to the overlay:
|
|
||||||
|
|
||||||
- **Sheet** — auto, green, or black. Auto samples the borders and picks; the owner overrides when
|
|
||||||
the sheet is an odd color.
|
|
||||||
- **Sensitivity** — one slider from tighter to looser detection.
|
|
||||||
- **Edge offset** — pulls the cut in or out a few pixels so it sits on the wood, not in the sheet
|
|
||||||
or into the grain.
|
|
||||||
- **Feather** — hard edge versus a couple of pixels of blend.
|
|
||||||
|
|
||||||
Changing any knob re-runs background removal immediately and refreshes the overlay. There is no
|
|
||||||
apply step and no server round trip for mask tuning in this version. The four values persist on the
|
|
||||||
browser until reset to default; they are not Settings fields.
|
|
||||||
|
|
||||||
If the edge still looks wrong after tuning, the owner retakes the photo. That is the resolution in
|
|
||||||
this version. A server-side matting path exists in the architecture for awkward backgrounds later,
|
|
||||||
but it is deferred and has no control here.
|
|
||||||
|
|
||||||
### Length axis
|
|
||||||
|
|
||||||
After the mask is confirmed, the app draws the bounding rectangle and the length axis over the slab,
|
|
||||||
with width sample lines perpendicular to that axis. The owner confirms the axis follows the
|
|
||||||
slab's prevailing length. If it is skewed, they rotate it; samples and square feet update live. On a
|
|
||||||
nearly square slab the owner says which way is length.
|
|
||||||
|
|
||||||
### Numbers
|
|
||||||
|
|
||||||
The owner enters length (in 1/8" steps), thickness (a 1/8" pick), and the SKU by hand. The browser
|
|
||||||
then computes square feet, board feet, and width samples from the confirmed mask and axis:
|
|
||||||
|
|
||||||
- Board feet = square feet × thickness in inches. One square foot at one inch thick is one board
|
|
||||||
foot. There is no divide-by-12.
|
|
||||||
- Widths are sampled every 6" along the length axis; the listing carries min, max, and average.
|
|
||||||
- Square feet and board feet show to two decimals.
|
|
||||||
|
|
||||||
These numbers are computed in the browser and stored as sent. The server does not recompute them.
|
|
||||||
|
|
||||||
### Photo prep
|
|
||||||
|
|
||||||
Each inventory photo is cropped to a 3:4 portrait frame with the slab centered at 80% fill, saved as
|
|
||||||
a transparent PNG. If the source has enough pixels, the shorter side lands at 1600 or more after
|
|
||||||
crop. If it cannot reach that, the app warns and asks for a retake; it does not invent pixels. The
|
|
||||||
owner sees the processed result alongside the original while the draft is retained.
|
|
||||||
|
|
||||||
### Continue
|
|
||||||
|
|
||||||
When the mask, axis, length, thickness, and SKU are set, the owner continues. That uploads the
|
|
||||||
originals plus the processed PNGs plus the numbers to the server as a calibrated draft, and moves to
|
|
||||||
review. The slab status becomes `calibrated`.
|
|
||||||
|
|
||||||
## Review: fill or override store fields
|
|
||||||
|
|
||||||
Review is where the listing row gets filled. Every field below maps to a column in the `slabs` table
|
|
||||||
in `docs/DATA-MODEL.md`. The owner can type any of them; vision may have pre-filled some, but typed
|
|
||||||
values always win and every value stays editable.
|
|
||||||
|
|
||||||
### What vision fills, and when
|
|
||||||
|
|
||||||
When inference is on, Call 1 runs after the calibrated draft uploads. It sends all inventory photos
|
|
||||||
downscaled to 1024 plus the store's synced species and attribute lists, and returns a guess
|
|
||||||
with a confidence per field. The threshold is 0.7 by default:
|
|
||||||
|
|
||||||
- A field at or above 0.7 pre-fills on review. It stays editable; the owner can change or clear it.
|
|
||||||
- A field below 0.7 starts empty. The app does not show the model's low-confidence guess as a
|
|
||||||
default, and an empty start is not the same as a finished listing.
|
|
||||||
|
|
||||||
With inference off, every field starts empty and the owner fills all of them by hand. Inference
|
|
||||||
never blocks publish and never auto-publishes. Call 2 (Generate text) does not run on its own; it
|
|
||||||
fires only when the owner taps it.
|
|
||||||
|
|
||||||
### The fields
|
|
||||||
|
|
||||||
The required set for a list-ready slab is the full store row, not species plus one figure:
|
|
||||||
|
|
||||||
- **SKU** — `[A-Z0-9-]{3,24}`. Practice runs use `SLAB-UAT-*`.
|
|
||||||
- **Length and thickness** — from capture; still editable here.
|
|
||||||
- **Square feet, board feet, widths** — shown as the client-computed values, with a manual override
|
|
||||||
path. The owner's typed number wins over the computed one.
|
|
||||||
- **Species** — exactly one leaf category from the synced store list. No hardcoded or invented
|
|
||||||
species; a new store species appears only after the next sync.
|
|
||||||
- **Wood categories** — at least one, from the synced list.
|
|
||||||
- **Edge type** — one term from the synced attributes.
|
|
||||||
- **Figure** — at least one term.
|
|
||||||
- **Grade** — at least one term.
|
|
||||||
- **Thickness band** — the Woo range that the measured thickness rounds up into (for example, a 1"
|
|
||||||
pick lands in the `1"–1 1/2"` band). The exact labels come from the synced store attribute.
|
|
||||||
- **Moisture** — one term, defaulting to kiln-dried. It is never inferred; the owner sets or keeps it.
|
|
||||||
- **fig-* tags** — at least one.
|
|
||||||
- **feat-* tags** — zero or more (character, inclusions, voids, checks map to existing `feat-*`
|
|
||||||
tags only).
|
|
||||||
- **Price** — a recommendation pre-fills from the species $/bdft rule times board feet; the owner may
|
|
||||||
override and that sticks. With no rule for the species, the price starts empty and the owner types
|
|
||||||
it. Publish is still allowed with a manual price.
|
|
||||||
|
|
||||||
Title, short title, and description are not required to reach ready. They can be typed by hand,
|
|
||||||
generated from templates at publish, or written by Generate text (Call 2) when enabled. Templates
|
|
||||||
always run; they inject the deterministic numbers so the model never touches dimensions.
|
|
||||||
|
|
||||||
### How missing fields show up
|
|
||||||
|
|
||||||
A field that is still empty and required shows its nudge inline, in place, the moment it is empty.
|
|
||||||
The owner sees each gap where it sits rather than learning about a problem after scrolling past it.
|
|
||||||
There is no single submit-time check that lists everything at once; the nudges are per-field as the
|
|
||||||
owner works. The slab cannot reach `ready` until the full set above is filled, whether by hand or by
|
|
||||||
a confident Call 1 the owner kept.
|
|
||||||
|
|
||||||
### Generate text
|
|
||||||
|
|
||||||
When content generation is enabled, a **Generate text** button runs Call 2 and fills title, short
|
|
||||||
title, and description with model prose plus template numbers. The owner can edit the result freely.
|
|
||||||
If the endpoint is missing or down, the button is disabled; templates still work and publish is never
|
|
||||||
blocked by a failed Generate text.
|
|
||||||
|
|
||||||
## Publish: create the store listing
|
|
||||||
|
|
||||||
The owner taps **Publish** when review is complete. What happens next depends on the SKU and Settings.
|
|
||||||
|
|
||||||
### Draft versus live
|
|
||||||
|
|
||||||
- A normal SKU publishes according to the `woo_create_status` setting, which defaults to draft.
|
|
||||||
- Any SKU matching `SLAB-UAT-*` always creates a WooCommerce draft, even if Settings say publish.
|
|
||||||
That is how practice runs stay invisible to customers.
|
|
||||||
|
|
||||||
The app's "published" means the store create succeeded and the local row plus photos were cleaned up.
|
|
||||||
That is not the same as the product being live in the store; a draft is created but hidden until Ty
|
|
||||||
promotes it.
|
|
||||||
|
|
||||||
### What the owner sees on each outcome
|
|
||||||
|
|
||||||
- **Success.** The screen shows that the listing was created, with the store's product reference when
|
|
||||||
available. The local draft and its photos are gone from the app.
|
|
||||||
- **SKU already exists.** Under the SKU field: "This SKU already exists in the store (any status)."
|
|
||||||
Two paths appear: edit the SKU to a new value, or open the existing listing. This version does not
|
|
||||||
update the other product in place. The draft stays in the browser; nothing is lost.
|
|
||||||
- **A value no longer valid.** If a category, attribute, or price was removed from the store between
|
|
||||||
sync and publish, that field shows "This value is no longer valid. Pick from the current list," with
|
|
||||||
the current options. The owner re-picks and retries.
|
|
||||||
- **Store unreachable or other failure.** A plain message on the screen says the listing could not be
|
|
||||||
created and to try again. No status number, no stack trace, no raw error code reaches the owner.
|
|
||||||
|
|
||||||
The server keeps a log of every attempt either way, so a failed publish can be retried from the same
|
|
||||||
screen without re-photographing.
|
|
||||||
|
|
||||||
|
|
||||||
## Browser compatibility
|
|
||||||
|
|
||||||
Ty signed this walk on 2026-09-06 PT with one amendment: the compatibility matrix includes PC
|
|
||||||
browsers as well as phones. This app is not mobile-only.
|
|
||||||
|
|
||||||
Supported families (matrix):
|
|
||||||
|
|
||||||
- **Phone:** iOS Safari, Android Chrome
|
|
||||||
- **PC:** desktop Chrome, desktop Edge, desktop Firefox (Windows and macOS at minimum)
|
|
||||||
|
|
||||||
Exact minimum version pins are still tracked under issue #4. The matrix above is the product lock
|
|
||||||
for which classes of client are in scope.
|
|
||||||
|
|
||||||
Unsupported browser behavior: hard stop. Show a clear message that this browser is not supported,
|
|
||||||
with a link to update or switch to a supported browser. No polyfill
|
|
||||||
strategy in this version.
|
|
||||||
|
|
||||||
Load-bearing client surfaces that must remain: canvas-based mask overlay and live knob re-run,
|
|
||||||
image crop/prep to 3:4 transparent PNG, file/photo intake for inventory shots, and the online API
|
|
||||||
calls for draft upload, review, and publish. Depth for APIs stays in `docs/TECH-SPEC-PIPELINE.md`
|
|
||||||
and `docs/OPENAPI.md`.
|
|
||||||
|
|
||||||
## Deferred features
|
|
||||||
|
|
||||||
Photo quality, OCR, ruler detection, server-side measuring, U2Net control, and offline capture are
|
|
||||||
deferred post-POC. The overlay edge plus the owner's eye is the only quality gate. SKU is typed by
|
|
||||||
hand. Length is entered by hand; the browser derives its own pixel-to-inch scale. The browser owns
|
|
||||||
the happy path for measuring and cropping. The U2Net one-photo contract stays in the architecture
|
|
||||||
for later. Capture is online only.
|
|
||||||
|
|
||||||
## Where each job lives
|
|
||||||
|
|
||||||
| Job | Screen(s) | Governing lock |
|
|
||||||
|---|---|---|
|
|
||||||
| Photo to listing | Capture through review to publish | AGENTS §1, TECH-SPEC, ARCHITECTURE swimlane |
|
|
||||||
| Practice drafts (`SLAB-UAT-*`) | Review (SKU field), Publish outcome | AGENTS §5, CONTENT-WOO payload status |
|
|
||||||
| Retake on bad cut | Capture mask overlay | TECH-SPEC §3.4–3.5, issue #15 |
|
|
||||||
| Fill or override fields | Review | DATA-MODEL `slabs`, AGENTS §6/7, issue #9 |
|
|
||||||
| Publish and recovery | Publish outcome states | CONTENT-WOO §2.5–2.6, OPENAPI 409/422, issue #18 |
|
|
||||||
Reference in New Issue
Block a user