feat(intake): review queue for drafted items #225

Closed
opened 2026-08-29 08:10:32 -05:00 by bermudalamb · 1 comment
Owner

Slice 4 of #220, and the last. Depends on slice 2 for something to review; usable without slice 3.

Design: docs/superpowers/specs/2026-08-29-intake-pipeline-design.md

Scope

An admin screen listing drafts by state: the photos, the submitter's note, which link it came from, the drafted copy in editable fields, the price, and Publish / Regenerate / Discard. Publish writes the edited values onto the item and calls the existing mark-available. Reuses the existing admin item components where they fit rather than growing a second item editor.

The price field is the point of this screen

Because items are priced on arrival — the model's suggestion, or the 80.00 default — the schema no longer prevents a price nobody chose from reaching the storefront. This screen is where that protection now lives, so the price field is not an ordinary input:

  • It is labelled with where the number came from, reading price_source — the model, the default, or the admin.
  • Anything that is not price_source='admin' is marked visibly as unconfirmed.
  • Editing it sets price_source='admin'.
  • Publishing something still unconfirmed is allowed, because that is the decision taken deliberately, but it says so plainly at the point of publishing rather than after.

80.00 is a plausible price rather than an obvious sentinel: 0 would render "$0.00" and read as a bug to anyone who saw it, whereas 80.00 reads as a decision, so a default left unnoticed sells the item instead of announcing itself. That is the whole argument for surfacing provenance loudly here.

Also

Discarded drafts are recoverable from this screen, since discard is reachable by one click from an inbox.

E2E assertions scoped to the item under test rather than the whole grid — the dev database never truncates, so a full-catalogue assertion outruns its timeout.

Part of #220

Slice 4 of #220, and the last. Depends on slice 2 for something to review; usable without slice 3. **Design:** `docs/superpowers/specs/2026-08-29-intake-pipeline-design.md` ## Scope An admin screen listing drafts by state: the photos, the submitter's note, which link it came from, the drafted copy in editable fields, the price, and Publish / Regenerate / Discard. Publish writes the edited values onto the item and calls the existing `mark-available`. Reuses the existing admin item components where they fit rather than growing a second item editor. ## The price field is the point of this screen Because items are priced on arrival — the model's suggestion, or the 80.00 default — the schema no longer prevents a price nobody chose from reaching the storefront. This screen is where that protection now lives, so the price field is not an ordinary input: - It is labelled with where the number came from, reading `price_source` — the model, the default, or the admin. - Anything that is not `price_source='admin'` is marked visibly as unconfirmed. - Editing it sets `price_source='admin'`. - Publishing something still unconfirmed is allowed, because that is the decision taken deliberately, but it says so plainly at the point of publishing rather than after. 80.00 is a plausible price rather than an obvious sentinel: `0` would render "$0.00" and read as a bug to anyone who saw it, whereas 80.00 reads as a decision, so a default left unnoticed sells the item instead of announcing itself. That is the whole argument for surfacing provenance loudly here. ## Also Discarded drafts are recoverable from this screen, since discard is reachable by one click from an inbox. E2E assertions scoped to the item under test rather than the whole grid — the dev database never truncates, so a full-catalogue assertion outruns its timeout. Part of #220
Author
Owner

Done and merged to main — it arrived via PR #263, because the #224 plan branch was stacked on top of this one, which is why nothing here closed automatically.

Shipped: GET /api/admin/item-drafts with a state filter, and publish, regenerate, discard and restore. The Review queue tab shows the photos, the sender's note, which link it came from, the drafted copy in editable fields, and the price.

The price behaves as the issue asked, with one thing worth spelling out. Editing the number is the only thing that sets price_source='admin'. Publishing without touching the field deliberately leaves it unconfirmed rather than quietly recording it as chosen — turning "I did not look at this" into "I approved this" is exactly the misrecording this screen exists to prevent. Publishing at an unconfirmed price is still allowed, and names the figure and its origin before it happens. The rule is a pure tested function applied on the server rather than trusted from the browser, with the row locked for the transaction so two admins cannot interleave one's price decision with another's name.

Discard deletes nothing — not the item, not the photographs. Restore returns a draft at the state its own contents justify rather than unconditionally ready, since a submission discarded before it was ever drafted has no copy and must not come back claiming otherwise.

One deviation, recorded rather than buried. The scope says to reuse the existing admin item components rather than grow a second item editor. I built a purpose-made card instead: the fields differ in kind rather than arrangement — this edits a proposal, beside the photographs and note that justify it, with a price input carrying a provenance label and a confirmation the ordinary editor has no concept of. The cost is real and worth naming: two places now render an item's name, description and price, so a change to how items are edited has to be made twice. Category and tag editing was left out for the same reason and is the natural moment to revisit it — the fields are returned by the API, so the screen can show them whenever that is picked up.

Verified: 346 backend unit, 317 backend integration, 157 e2e (up from 155), lint and build clean on both projects, zero warnings.

Closes #225

Done and merged to `main` — it arrived via PR #263, because the #224 plan branch was stacked on top of this one, which is why nothing here closed automatically. Shipped: `GET /api/admin/item-drafts` with a state filter, and publish, regenerate, discard and restore. The Review queue tab shows the photos, the sender's note, which link it came from, the drafted copy in editable fields, and the price. **The price behaves as the issue asked, with one thing worth spelling out.** Editing the number is the only thing that sets `price_source='admin'`. Publishing *without* touching the field deliberately leaves it unconfirmed rather than quietly recording it as chosen — turning "I did not look at this" into "I approved this" is exactly the misrecording this screen exists to prevent. Publishing at an unconfirmed price is still allowed, and names the figure and its origin before it happens. The rule is a pure tested function applied on the server rather than trusted from the browser, with the row locked for the transaction so two admins cannot interleave one's price decision with another's name. Discard deletes nothing — not the item, not the photographs. Restore returns a draft at the state its own contents justify rather than unconditionally `ready`, since a submission discarded before it was ever drafted has no copy and must not come back claiming otherwise. **One deviation, recorded rather than buried.** The scope says to reuse the existing admin item components rather than grow a second item editor. I built a purpose-made card instead: the fields differ in kind rather than arrangement — this edits a proposal, beside the photographs and note that justify it, with a price input carrying a provenance label and a confirmation the ordinary editor has no concept of. The cost is real and worth naming: two places now render an item's name, description and price, so a change to how items are edited has to be made twice. Category and tag editing was left out for the same reason and is the natural moment to revisit it — the fields are returned by the API, so the screen can show them whenever that is picked up. Verified: 346 backend unit, 317 backend integration, 157 e2e (up from 155), lint and build clean on both projects, zero warnings. Closes #225
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#225