Phase 2 — Mel's Drive-In: Studio tag-block authoring
23 JUL AT 10:52 PM

Phase 2 — Mel's Drive-In: Studio tag-block authoring

0 LOVES 3 VIEWS
Where orders get placed: the White Rabbit picker lifted verbatim into a block-scoped modal — pick existing tags, drag-reorder the pills, save atomically. The legacy post-form picker removed; usage counts learn about posts; delete-in-use refused. Shipped 2026-06-09.

Mel's is where everyone pulls in and places an order — and Phase 2 is where editors place theirs. The sidebar grew an Add Tags row; it opens the White Rabbit picker lifted verbatim into a block-scoped modal: selected pills up top, an add-group bar, black group pills, and the collapsible group panels with the two-level checkbox tree. Picking existing tags and hitting Save to Block mints a tag block and its ordered TagBlockItems — atomically, in one transaction. Pills drag-reorder (native HTML5 DnD) and the order persists on save.

The picker, as designed

Studio mockup: the Edit Tags block modal with the Origin group panel open and Nicaragua checked

The Add/Edit Tags modal — the White Rabbit picker in a block scope: selected pills, add-group bar, group pills, and the two-level checkbox tree. Mockup rendered with the live Studio CSS.

What shipped — and the deltas

  • The legacy picker was removed, not disabled. The old post-form pt-* card, its CSS, and its JS came out entirely — its element IDs collide with the new block-scoped modal, so it could not survive as a live duplicate. Stronger than the plan's "disable."
  • The data-loss guard. With the picker gone, a normal save submits no tag_ids — and UpdatePost used to clear the tag edge unconditionally. It now syncs only when tag_ids are submitted, preserving Post.tags untouched for the Phase 7 migration.
  • Atomic create. CreateTagBlock opens its own transaction (the generic Create() is not transactional): block + N ordered items commit together or not at all — with the same audit row.
  • FK-safe delete. Tag items are Required + NoAction, so the generic block delete would FK-fail on a tag block; it now clears the items first, in a tx. (Collection blocks never hit this — their edges are SetNull.)
  • Heading edits stay in the gear. SetTagBlockItems is items-only; the block settings modal owns heading/divider and leaves items untouched — no crossed wires between the two edit surfaces.

Guardrails & proof

  • The cross-tenant IDOR, closed. The picker tree was always site-scoped, but the legacy submit trusted the POSTed tag_ids. CreateTagBlock and SetTagBlockItems validate every picked id via BelongsToSite — a forged id from another site's tag is refused.
  • Usage learned about posts. The tag usage count now includes posts-via-blocks, and a nested Used In page lists the referencing posts with links — so an editor can unlink before deleting. Deleting a tag still in use is refused (ErrTagInUse).
  • Proof: the named test matrix green (create-assert, foreign-site IDOR, the legacy-picker-preserves-Post.tags regression, request binds, reorder route); full Studio suite green; then an operator-present live smoke — create, re-pick, delete, both reorders, gear/heading, pill and group removal, empty-validation, hidden toggle, multi-group pre-check, multiple blocks per post, Used-In, delete-in-use refusal — all passed.
  • Honest gap: the "no tag groups configured" empty state was never live-tested (no dev site has a post and zero tag groups). It is template-guarded, identical to the proven legacy picker's guard.
American Graffiti — Tags as a Content Block (master)
American Graffiti — Tags as a Content Block (master)
Jul 23, 2026 American Graffiti
← Back to American Graffiti