## Context

Physical tags break; owners need to retire a tag and move its data to a replacement. Also, legacy printed URLs (`?x=5&productid=…`) must still reach tag pages so old physical tags work with the new system.

## Goals / Non-Goals

**Goals:**
- Owner-facing Close and Move actions on the account page.
- Closed tags: page shows unavailable, no alerts.
- Legacy `productid` URL redirect.

**Non-Goals:**
- Tag transfer between accounts (admin can reassign owner later) — not in scope.
- NFC/QR re-printing (future production slice).

## Decisions

1. **Status `closed`** (new enum value): schema CHECK updated via `ALTER TABLE tags DROP CONSTRAINT IF EXISTS tags_status_check` + re-add including `closed` (idempotent; CREATE TABLE also updated for fresh DBs).
2. **Alert gating**: `shouldAlert` returns false when `tag.Status == "closed"` (and "suspended" — already handled? currently suspended isn't gated in shouldAlert either — add both for safety; the public page already handles suspended).
3. **Close**: `CloseTag` (POST /account/tags/{id}/close) — owner-only (loadOwnedTag) → `SetTagStatus(id, 'closed')` → HTMX account-panel response.
4. **Move**: `MoveTag` (POST /account/tags/{id}/move, form `new_tag_code`) — load source (owner) → `GetTagByCode(target)` must exist, be unset, not same → `BindTag(owner, target)` → `UpdateTagDetails(target, source fields)` → `SetTagStatus(source, 'closed')` → panel (with error on failure).
5. **Compat redirect**: in `Home`, `productid` query param → 302 to `/t/{productid}`. (The QR likely encodes `/?x=5&productid=…`; the `x=5` param is ignored.)
6. **UI**: tag-list rows gain "Close" (confirm) and a small "Move" form (new tag code input). Public page: `closed` renders the same "unavailable" treatment as suspended, with owner-specific copy.
7. **Admin**: TagResource status Select + badge include `closed`.

## Risks / Trade-offs

- [Constraint drop/re-add could race] → dev-only, single migrator; fine.
- [Move copies photo_url] → the photo object key is preserved (MinIO) — works.
- [Old URL path weirdness (`/x=5&…` without `?`)] → if the QR literally encodes that malformed path, it 404s; the standard `?x=5&productid=` form is handled. Verify with the physical tags.

## Migration Plan

1. Schema ALTER (constraint) + `make db-up`.
2. Go handlers + redirect + templates; build.
3. Admin status option.
4. Verify (close, move, redirect, gating); regressions; deploy.

## Open Questions

- None blocking.
