Two routes on the item, and a small admin config route so the inventory screen can know whether to offer them. Both answer 200 once the id is valid, even when the sidecar fails, and that is a deliberate departure from the per-photo endpoints in #281. Those act on one image, so the request either worked or it did not and 502 says which. These act on several, so "did it work" has no single answer — two of four is the normal shape of a bad day here, not an exception — and a 502 would throw away the count that is the only thing making the outcome actionable. Non-200 is reserved for not being able to try at all, which here means an unreadable or absent id. No status check on either. A sold item's photos are still the shop's photos and improving them changes nothing about the sale; the guards on unpublish protect a checkout in progress and a completed sale, neither of which is at stake in a photograph's background. The config route follows adminVersion's precedent rather than extending the public /api/config: admin-only, one purpose, and the reason written down. The inventory screen had no other way to learn the feature exists, because GET /api/admin/items answers a bare array with several consumers and reshaping it for one boolean is the worse trade. Also extends the admin item select to carry original_image_path on each image, behind a new ADMIN_IMAGES_SUBQUERY kept separate from the shared IMAGES_SUBQUERY the public select uses. Task 3 needs to derive its restore-button label from that field, and the server never sent it for items before this — only the drafts endpoint carried it, added by #281 for the review queue. It stays admin-only for the same reason itemSelect.ts already names PUBLIC_ITEM_SELECT's columns explicitly: an internal original filename is nobody's business on the storefront, and sharing one subquery would put it in every public item response. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
28 lines
1.1 KiB
TypeScript
28 lines
1.1 KiB
TypeScript
import { Router, Request, Response } from 'express';
|
|
import { isRembgConfigured } from '../intake/rembgClient';
|
|
|
|
const router = Router();
|
|
|
|
/**
|
|
* What the admin screens can offer in this environment.
|
|
*
|
|
* Behind `requireAdminGate` like every other admin router, and deliberately not
|
|
* folded into `/api/config` — the same reasoning `adminVersion.ts` records.
|
|
* That endpoint is public and the storefront fetches it on every load; nothing
|
|
* here is any of a customer's business.
|
|
*
|
|
* It exists because the inventory screen has no other way to learn this.
|
|
* `GET /api/admin/item-drafts` carries the flag for the review queue, but
|
|
* `GET /api/admin/items` answers a bare array with several consumers, and
|
|
* changing its shape for one boolean would be a worse trade than one small
|
|
* route.
|
|
*
|
|
* Not wrapped in `asyncRoute` because the handler is synchronous: it reads an
|
|
* environment variable, so there is no promise to reject.
|
|
*/
|
|
router.get('/', (_req: Request, res: Response) => {
|
|
res.json({ backgroundRemoval: isRembgConfigured() });
|
|
});
|
|
|
|
export default router;
|