# AGENTS.md — Where Woof (resume brief) > The **source of truth is `where_woof.md`** (product plan + roadmap) and the **`openspec/` changes**. This file is a quick-resume overview for any agent or session picking the project back up. ## What this is Where Woof — a **return-tag platform** (not a tracker): pre-coded QR/NFC tags on items; a finder scans → sees return details → owner gets an SMS alert (with finder location when permitted). Branding: "Where Woof !" (werewolf wordplay). ## How we work (the pipeline) - **Master/worker**: the main pi session (cwd = repo root) orchestrates; subagents do chunks — `database` (schema/queries), `coder-pro` (Go code), `devops-pro` (infra/secrets), `code-analysis` (review). User reviews via plannotator's browser UI when it cooperates; otherwise inline approval. - Per change: **openspec** (propose → design/specs → tasks, `openspec validate`) → **plannotator** plan (`plans/.md`, submit → approve) → execute with `[DONE:n]` → run `/tmp` verify suites → `code-analysis` review → commit + push to Gitea. - This is a **learning exercise for the user** — explain decisions, don't just execute. ## Where we are (2026-08-05) - **Phase 1 `frontend-foundation` — DONE** (22/22 scenarios verified) - **Phase 2 `scan-flow` — CODE DONE + verified (19/19)**; **step 9 (real SMS) PENDING** — needs the user's SMSGlobal (MXT) API key/secret; verify `frontend/internal/sms/smsglobal.go` auth against their prior globalsms integration before the real send - **Phase 2.5 queued (tuxedo, priority B):** ① re-alert when a *different* finder phone arrives within the 250 m / 10-min window; ② JS browser fingerprint + 24 h block (store fingerprint in DB) - **Phases 3–9 pending** (see roadmap in `where_woof.md`): HTMX/Alpine polish → Laravel admin → billing (Stripe AU) → photo uploads → deploy frontend (.13 + Caddy .35 + InMotion redirect) → deploy admin → anti-abuse hardening ## Key locations | What | Where | |---|---| | Product plan + roadmap (source of truth) | `where_woof.md` | | OpenSpec specs & changes | `openspec/` (`frontend-foundation` ✅, `scan-flow` ✅) | | Plannotator plans | `plans/frontend-foundation.md`, `plans/scan-flow.md` | | Go front-end | `frontend/` (stdlib `net/http`, `internal/{db,auth,handlers,sms}`) | | Schema | `db/schema.sql` (canonical until Laravel owns migrations) | | Build/run targets | `Makefile` — `db-up`, `seed`, `run`, `build`, `generate`, `psql` | | Dev DB | `wherewoof-db` Postgres 16 container on **.13:5434** (user/db `wherewoof`; compose + `.env` in `/home/sam/Docker/Containers/wherewoof-db/` on .13) | | Run locally | `make db-up && make seed && make run` → `http://localhost:3020` (SMS in **log mode** until creds set) | | Verify suites | `/tmp/verify.sh` (Phase 1, 22 checks), `/tmp/verify2.sh` (Phase 2, 19 checks) — ephemeral, they reset the DB | | Prod target | `.13:/var/www/where-woof` — **NOT deployed yet (Phase 7)**; Caddy on .35; InMotion redirect → `where-woof.com` | | Gitea | `sam/where_woof` — `ssh://git@gitea.lab.audasmedia.com.au:2222/sam/where_woof.git` | ## Tools - `openspec` 1.3.1 (spec-driven dev), `plannotator` (plan + browser review), pi subagents (master/worker), `sqlc` 1.31.1 at `~/go/bin` (not on PATH — `make generate` handles it), `pgx` v5, `gorilla/sessions`, `bcrypt` - **Secrets are env-only, never committed**: `DATABASE_URL`, `SESSION_SECRET`; SMS via **HTTP API** `SMS_USER`/`SMS_PASSWORD`/`SMS_FROM` (proven live 2026-08-07) with REST key/secret (`SMS_API_KEY`/`SMS_API_SECRET`) as unverified fallback - SMS is a swappable `internal/sms.Sender` — `LogSender` (default) / `smsglobal.Client` (real) ## Gotchas worth remembering - `.pi/` is gitignored (agent memory + extension tooling are machine-local) - NixOS box: **no gcc** (`CGO_ENABLED=0` set via `go env -w`), `make` via `nix profile`, no `psql` (use `make psql` → docker exec on .13) - `html/template` escapes `+` as `+` in hrefs (`tel:`/`sms:` links still work in a browser) - `pkill -f` can match your own shell — use `pkill -x where-woof` - Reset the DB between the two verify suites (both bind `TEST000001`) - Postgres identity columns advance on failed inserts (duplicate-email test consumes an id)