Part 5 of 7 · Product image cleaner series ~6 min read

How a cleaned image gets published

The work is done; now it has to land somewhere the owner can actually use it. This post is about the last step: where the finished variants are written, how they get back to the person who dropped the photo in, and the small guarantees — versioning, a manifest, an untouched original — that make the output safe to trust.

Key takeaways

  • Each variant is written back to S3 under a per-channel prefix — out/web/, out/market/, out/social/ — alongside a manifest.
  • The manifest records exactly what was produced: every file, its channel, its dimensions, and the job it came from.
  • One notification per job tells the owner the set is ready, with links — or that a cutout needs review, with the original attached.
  • The original photo is never touched and never overwritten; every output is a new object, and the bucket is versioned.
  • A daily sweep re-surfaces jobs stuck in review so a doubtful cutout doesn’t quietly age out and get forgotten.

Where the finished set goes

By the time publishing runs, the work is done: a clean cutout passed the gate and the variant step produced the full set. All that’s left is to put the images somewhere the owner can actually reach them and to say so. The publish function writes each variant back to the same S3 bucket under a per-channel prefix — the 1600×1600 web image to out/web/<job_id>.png, the 2,000-pixel marketplace square to out/market/<job_id>.jpg, the social square to out/social/<job_id>.jpg. The layout is deliberately predictable: anyone, or anything, that wants the marketplace images for a batch knows to look under one prefix, and the filenames trace straight back to the job that made them.

Because the watched-folder lane runs in both directions, the same prefixes can be mirrored back into a Drive folder, so the finished images land next to where the owner dropped the original — no logging into a console, no downloading from a bucket. The system produces files and puts them where they’re useful; it never logs into the store or the marketplace and never publishes a listing. What goes live is always the owner’s call.

The manifest

Alongside the images, publish writes a small manifest.json for the job: the source filename, the job id, the cutout’s confidence score, and one entry per output — its channel, its S3 key, its pixel dimensions, its format, and whether it was watermarked. The manifest is what turns a pile of files into a record. It lets the owner see at a glance that a product really did get all three variants and not two; it lets a re-run detect what already exists; and it’s the thing you’d read in six months to answer “which images did we generate for this product, and from which photo?” The job row in DynamoDB is moved to status done at the same moment, so the manifest on S3 and the status in the table always agree.

Publishing the finished set back to S3 with a manifest and one notification On the left, a box for the built variants arriving from the variant step. An arrow leads to the picr-publish Lambda. From publish, several outputs fan out. To the right, three S3 prefix boxes stacked: out slash web, out slash market, and out slash social, each receiving its variant. Below them, a manifest dot json box recording every file produced. Publish also updates the DynamoDB job table picr-jobs to status done. Publish then sends one notification through SES or SNS to the owner, saying the set is ready with links. Separately, on the original photo, an arrow shows it remains untouched in its versioned bucket, never overwritten. At the bottom, an EventBridge daily sweep box re-checks jobs stuck in the needs-review state and re-notifies the owner. A bottom note reads: every output is a new object, the original is never touched, and nothing in review is forgotten. Variants built set picr-publish write + record + tell out/web/ out/market/ out/social/ manifest.json picr-jobs status = done Notify owner SES / SNS, links Original untouched, versioned EventBridge daily sweep re-notify jobs in review Every output is a new object, the original is never touched, and nothing left in review is forgotten.
Fig 5. picr-publish writes each variant under its channel prefix, drops a manifest, moves the job to done, and sends one notification. The original stays untouched in the versioned bucket; a daily sweep re-surfaces anything stuck in review.

One notification per job

The owner gets exactly one message per photo, and it says one of two things. On success: “Sea Salt candle: 3 images ready,” with links to the three variants. On a held cutout: “Glass vase: needs review,” with the original and the attempted cutout attached so the problem is obvious at a glance. The channel is whatever suits — an email through SES, or a push to an SNS topic the owner’s phone or a team channel subscribes to. What matters is that it’s one message with a clear outcome, not a stream of per-stage chatter. The owner doesn’t need to know the cutout ran or the variants were resized; they need to know the set is ready, or that one needs a second look.

Why nothing overwrites the original

Two rules keep the output safe to trust. First, the original is sacred: the photo that landed in inbox/ is the source of truth and is never modified. Every working file and every variant is a new object under its own key, so a re-run, a config change, or a bug can never corrupt the one thing you can’t regenerate — the photo itself. Second, the bucket is versioned, so even an output that does get rewritten — you tweak the watermark and re-run a product — keeps its previous version rather than vanishing. If a new run produces something worse, the old version is still there to roll back to.

The last guarantee is about the things that didn’t finish. A cutout sent to review is a job left deliberately incomplete, and the easiest way for it to go wrong is to be forgotten — the owner misses the notification, gets busy, and the half-done product quietly never makes it online. So an EventBridge daily sweep walks the job table for anything stuck in needs review past a day and re-notifies, the same way the other systems in this series re-surface anything left hanging. The pipeline is judged not only by the sets it ships but by its refusal to let a held one disappear.

Design rules for publishing

  • Predictable layout. Per-channel prefixes and job-id filenames make the output easy to find and trace.
  • A manifest per job. Every file, channel, size, and the cutout’s confidence, recorded as the job’s receipt.
  • One notification, one outcome. Ready with links, or needs review with the original — never a stream of stage updates.
  • The original is never touched. Outputs are new objects; the bucket is versioned so nothing is lost.
  • Nothing in review ages out. A daily sweep re-surfaces held jobs until a human deals with them.
All posts