## 1. Schema & Queries - [ ] 1.1 Add idempotent `ALTER TABLE tags ADD COLUMN IF NOT EXISTS sms_enabled BOOLEAN NOT NULL DEFAULT TRUE;` to `db/schema.sql`; run `make db-up` (migrates existing DB) - [ ] 1.2 Add sqlc queries in `internal/db/queries.sql`: `InsertScan` (tag_id, lat/lng nullable, location_shared, scanner_phone nullable), `GetLastAlertByTag` (latest scan with alert_sent=true), `UpdateTagDetails` extended with `sms_enabled`; `make generate` - [ ] 1.3 New `internal/sms` package: `Sender` interface, `sms.NormalizeAU`, `sms.HaversineMeters`; `smslog` sender; `smsglobal` HTTP client (REST, key+secret, JSON; field names confirmed with MXT docs) ## 2. Scan Handlers - [ ] 2.1 `internal/handlers/scan.go`: `POST /t/{tag_code}/scan` — parse optional lat/lng, record scan, apply 250 m / 10-min throttle, send SMS per rules, set `alert_sent` - [ ] 2.2 `POST /t/{tag_code}/contact` — validate finder number, store on latest scan, SMS the owner with the finder's number - [ ] 2.3 Wire `internal/sms` sender into `App` (log sender when `SMS_API_KEY` unset) + register routes in `main.go` ## 3. Public Page JS & Templates - [ ] 3.1 `tag-public.html`: geolocation script (prompt on load, POST scan with coords, re-check button shown until shared, hidden after), `sms:` link with prefilled body, finder contact form + inline error - [ ] 3.2 Branding sweep: "WhereWoof" → "Where Woof" in all templates + README; `