## Context

Phase 1/2 built the app with a DEV-only tag registry (TEST codes). The real product — 100 preset physical tags — was manufactured with URLs carrying opaque base64 `productid` values (the old system's double-encoded IDs). Those IDs are confirmed real (the user generated the URLs and sent them to the manufacturer) and are now in `db/preset_tag_ids.txt`. This change seeds them as the real registry and adds the products/orders linkage that the 2014 system used for stronger validation and billing.

## Goals / Non-Goals

**Goals:**
- The 100 real preset IDs are claimable (seeded registry).
- `products`, `orders` schema + `tags.product_id`/`order_id` exist for the admin (Phase 4) and billing (Phase 5).
- Idempotent migrations and seeds; no regressions to existing flows.

**Non-Goals:**
- Laravel admin UI to assign products/orders (Phase 4).
- Billing enforcement (Phase 5).
- Changing the claim flow (still registry-by-code; the product link does not gate binding yet).
- Decoding the opaque product IDs (they are intentionally opaque; tag_code IS the identifier).

## Decisions

1. **Registry file = single source of truth.** `db/preset_tag_ids.txt` (committed) holds the 100 IDs; the seed reads it. Manufacturing new tags = append to this file + re-seed. *Alternative:* hardcode in Go — rejected, file is data not code.
2. **`seed-registry` is a separate command from `seed`.** `make seed` keeps TEST codes for dev; `make seed-registry` adds the real IDs. Both idempotent (`InsertTag` + unique-violation skip, same pattern as the existing seed). *Alternative:* replace TEST entirely — rejected, dev needs stable TEST codes until production seeding is the only path (Phase 7).
3. **Schema mirrors the 2014 model with modern naming.** `products` ≈ old `products`/`id_products`; `orders` ≈ old `online_orders`; `tags.product_id`+`order_id` ≈ old `online_order_product_details` + `product_id_hashes` mapping. The old `product_id_hashes` table is unnecessary here because `tag_code` IS the hash in our system — registry presence is the validation.
4. **No new sqlc queries yet.** Schema + models only (sqlc regenerates `Product`/`Order` models and extends `Tag`); queries come with the Phase 4 admin. This keeps the change small and behaviour-stable.
5. **Idempotent ALTERs** for existing DBs: `ALTER TABLE tags ADD COLUMN IF NOT EXISTS product_id ...` etc. — same pattern as `sms_enabled` (Phase 2).

## Risks / Trade-offs

- [TEST codes + real IDs coexist in dev] → accepted; production seeding documented as registry-only (Phase 7 gate).
- [Opaque IDs can't be human-decoded] → by design (anti-enumeration); the file maps ID → URL format for reference.
- [products/orders unused until Phase 4] → schema-only now, no dead code paths; avoids a breaking migration later.

## Migration Plan

1. `make db-up` (idempotent ALTERs + new tables on the existing dev DB).
2. `make seed-registry` (100 real IDs) — verify idempotent on re-run.
3. sqlc `make generate` (new models). No data migration needed (new nullable columns).

## Open Questions

- Whether the 100 IDs map 1:1 to physical tags currently in circulation (assumed yes — user created the URLs for the manufacturer).
- Product template contents (sku/name) — seeded later with the Phase 4 admin.
