feat(intake): swap a photo for a cut-out, keeping the original (#281)
Adds backend/src/intake/backgroundRemoval.ts, the shared module the drafting worker and the admin endpoints both call so a cut-out obtained either way is undoable the same way. cutoutPathFor is pure and writes a new file beside the original rather than overwriting it, which is what keeps the original restorable and makes the JPEG-to-PNG change free. removeImageBackground only points the row at the new file after it is already on disk, and is idempotent via the original_image_path IS NOT NULL check — load-bearing twice, since it also stops a second pass from recording the cut-out as the original and losing the real one for good. restoreImageOriginal swaps the paths back and deliberately leaves the cut-out file on disk. Extends the Task 1 integration test file with a stub sidecar bound to an ephemeral port and covers the no-op-on-repeat case plus three failure modes (500, non-image body, unreachable), asserting the row is left untouched in every failure case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import { cutoutPathFor } from '../../src/intake/backgroundRemoval';
|
||||
|
||||
describe('where a cut-out is written', () => {
|
||||
// A new file rather than a rewrite of the original, which is what makes the
|
||||
// original restorable at all — and what makes the JPEG-to-PNG change free,
|
||||
// since no existing path is renamed.
|
||||
it('sits beside the original with a -cutout suffix and a .png extension', () => {
|
||||
expect(cutoutPathFor('/uploads/abc-123.jpg')).toBe('/uploads/abc-123-cutout.png');
|
||||
});
|
||||
|
||||
// image_path is a contract, not a string: #103 made the stored value the
|
||||
// path uploadUrl joins an origin onto.
|
||||
it('keeps the /uploads/ prefix', () => {
|
||||
expect(cutoutPathFor('/uploads/x.webp')).toBe('/uploads/x-cutout.png');
|
||||
});
|
||||
|
||||
// The extension is replaced rather than appended, so a second pass cannot
|
||||
// produce `.png.png`.
|
||||
it('replaces the extension rather than appending to it', () => {
|
||||
expect(cutoutPathFor('/uploads/x.png')).toBe('/uploads/x-cutout.png');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user