## 1. Schema & Queries - [x] 1.1 `db/schema.sql`: idempotent ALTERs `tags.sms_allocated/used/period_start`; `url_shortened` table; `make db-up` - [x] 1.2 `queries.sql`: `InsertShortCode`, `GetShortCode` (:one), `GetScanByID` (:one), `AddSmsUsed` (:exec, `sms_used = sms_used + 1`); `make generate`; build ## 2. Metering - [x] 2.1 `scan.go` shouldAlert: credit check (`SmsAllocated > 0 && SmsUsed >= SmsAllocated` → false); after successful alert send → `AddSmsUsed` - [x] 2.2 `FinderContact`: same credit check + increment on successful send ## 3. Location Link - [x] 3.1 Short-code generator + `InsertShortCode` at alert time (when location present); `alertMessage` uses `where-woof.com/s/{code}` - [x] 3.2 `ServeShort` handler (`GET /s/{code}` → scan → location page); `location.html` template (map iframe + finder phone + tag link + time); register route + template set ## 4. Admin - [x] 4.1 TagResource: `sms_allocated` (numeric, editable), `sms_used` (view), `sms_period_start` (view) ## 5. Verification - [x] 5.1 New suite: metered tag with credits → alert + credit consumed; exhausted → no alert (scan recorded); unmetered (0) → alerts; alert SMS contains `where-woof.com/s/`; short link → location page 200 with map + finder details; unknown code → not found - [x] 5.2 Regressions (22+19+12+6) green; deploy frontend + admin; live check - [x] 5.3 `openspec validate sms-metering-location-link`; commit