Service image authoring and recovery
Web service editing and the Business-app API companion now share one venue-scoped image writer. Authorized admins with bookings.manage can upload JPG, PNG or WebP (up to5 MiB, at least1200 by675 pixels), then save a16:9 catalog image. Existing service-catalog franchise locks also apply. The writer validates owned original paths and bytes, creates immutable1600/800/400 WebP versions, and compares t
Web service editing and the Business-app API companion now share one venue-scoped image writer. Authorized admins with bookings.manage can upload JPG, PNG or WebP (up to5 MiB, at least1200 by675 pixels), then save a16:9 catalog image. Existing service-catalog franchise locks also apply. The writer validates owned original paths and bytes, creates immutable1600/800/400 WebP versions, and compares the existing image and media before attaching changes. Other media keys and existing appointments are preserved.
The developer registry describes POST `/api/v1/admin/services/{id}/image/upload-url`, POST `/api/v1/admin/services/{id}/image/finalize` and DELETE `/api/v1/admin/services/{id}/image`. Finalize/removal require an actor/venue/resource/body-scoped Idempotency-Key. Confirmed saves can return warnings when history, tracking, cache refresh or old-file cleanup fails; an uncertain result is not a failed save that can safely be repeated with a new key. Refresh authoritative state or recover the exact operation. Storage conflicts do not prove that existing bytes match, and cleanup never deletes an entire service prefix or another upload generation.
The web editor blocks competing changes while working, retains unknown-outcome recovery and ignores late results after leaving or switching venues. A local unreadable file can be corrected without locking the editor as though a server save had occurred. The real service form supplies the loaded service's organization to the uploader.
The native companion includes Business image authoring and Consumer/Branded display of the existing public `image_url` field. The client display omits missing, removed or unreadable images; a late failure from a replaced image does not hide its replacement. A catalog image refresh does not replace the selected booking or payment snapshot. Consumer and Branded receive no staff image controls or private upload capabilities; published Sites keep their existing public image/derived-size contract.
The public native display packet has local focused regression and TypeScript evidence; final combined Business/client integration remains required. These changes do not establish device or store parity, or whole-flow booking-session switch acceptance. Existing lazy bucket provisioning remains source behavior, but hosted storage provisioning and real uploads were not performed for this change. No client communication, payment, booking mutation or app publication was exercised. Native owner-defined terminology remains a separate unimplemented capability.Service assignments and variants: shared administration contracts
This isolated source candidate gives web and Business app clients one server authority for assigning professionals to services and managing duration/price variants. It is not deployed and does not establish full setup parity or Nailtech handover readiness.