ensureServerSlab sent calibration_photo_id at create, but slab_photos rows are
only created by POST /slabs/{id}/photos, which the frontend never called - so
the INSERT hit FOREIGN KEY (calibration_photo_id REFERENCES slab_photos(id))
and every create failed with a generic 400, blocking the whole create->publish
walk.
- stop sending calibration_photo_id at create
- upload every draft photo (original + processed PNG) right after the slab row
exists, via new review/photoUpload.ts (multipart FormData, same error
envelope so failures surface through fail(e))
- link calibration_photo_id in the existing review PUT, once the row exists
- extract the role rule into lineup.photoRole() so the review strip and the
uploader cannot disagree
Two fixes in the review form:
- figTags/featTags filtered on tag.name.startsWith('fig-'), but the live store
marks the family on the SLUG (slug 'fig-chat', name 'Chatoyant'), so the
figure/feature tag groups rendered empty. Match slug OR name.
- Echo Figure selections transparently: picking a Figure attribute term
auto-selects the same-named fig-* tag and vice versa, so the Woo product
carries the figure in both the pa_fig attribute and the fig-* tag without
the owner picking it twice.
attributeByName lowercased the store attribute name but compared it to the
raw lookup string, so 'figure' !== 'Figure' and Edge/Figure/Grade/Thickness/
Moisture all matched nothing - the Figure chip group (and the other attribute
pickers) rendered empty, so 'Mark Ready' could never enable against the live
store. Lowercase both sides so the synced attributes resolve.