Push & offline
VAPID-based web push with role-specific alert routing via a pending_alerts table. Service worker with offline banner. Installable as a PWA on iOS and Android. The install-to-homescreen banner fires contextually — not on first visit.
Stack
The technical substrate behind TailTracker — the libraries, the storage, the guardrails, and the deliberate choices about where determinism ends and the model begins.
VAPID-based web push with role-specific alert routing via a pending_alerts table. Service worker with offline banner. Installable as a PWA on iOS and Android. The install-to-homescreen banner fires contextually — not on first visit.
59 tables. 20+ controllers. No framework, no ORM — plain PHP 8 with a PDO singleton and a handful of static helpers. Every query is parameterized. The audit log is append-only with no UPDATE or DELETE path in the codebase. Adoption records are void-only — Texas Health & Safety Ch. 828 compliance is baked in, not bolted on.
61 PHPUnit tests (54 integration · 7 unit)
28 / 28 Playwright E2E tests ✓
42 / 43 OWASP security probes ✓
Lighthouse 100/100/100/100 ✓
Load: 177ms avg @ 50 concurrent ✓
Voice→care-log AI eval: 100% ✓
Multi-agent sim: 2,580 ops, 0 fails ✓
Dashboard · Scan / care log · Animal intake & edit · Zones · QR generation · Adoptions · Foster · Lost & Found · Vet hub · HR hub · Social caption tool · Maintenance · Purchasing · Development / donors · Grants pipeline · Cruelty investigations · Legal & audit log · Reports (11 types) · Admin panel · Public adoption portal · Public API
17 roles with granular guards — requireAuth(), requireAdmin(), requireManagement(), and role-specific checks on every protected route. Full WebAuthn/passkey implementation: conditional UI, biometric mode toggled via localStorage, 5-failure auto-fallback to password, rpId = tailtrackers.org (eTLD+1). Cache-Control: no-store on all authenticated responses — back-button after logout goes nowhere.
Only genuinely periodic work runs on a clock — because a shelter runs on shifts. Triage (04:00) and role-scoped briefings (06:00 / 12:00 / 18:00) fire from one token-protected endpoint; a kennel worker and the executive director get different narratives from the same underlying data. Everything else happens on request. Bobby G., the simulation engine, runs during development to keep the data realistic.
Multiple AI touchpoints, all using Claude: role-specific briefings (generated 3× daily via cron), clinical care summaries for shift handoffs, voice-to-care-log (Web Speech API → Claude → structured form pre-fill), social caption generation from animal photos, lost & found stray matching, and grant-narrative drafting. A provider-pluggable, demo-mockable Ai::call() helper is the model gateway; consolidating the remaining controllers that still hold their own client onto it is in progress. The exceptions report that ranks open issues by urgency is deterministic — six parallel SQL checks, no model — as is the rest of the deterministic work: length-of-stay math, hold-release prediction, and vet triage ranking, all deliberately kept off the model.