Pet Safety
Three related surfaces help an owner protect a pet outside the clinic:
- Collar tag — a public profile reachable via a slug (
/p/{slug}) the owner can print on a physical tag. - Lost-pet mode — toggled on the same profile; broadcasts a "Help me get home" message to anyone who scans the tag.
- Pet passport PDF — a portable PDF with photo, vital stats, vaccinations, and a QR pointing back to the public profile.
Collar tag (public profile)
Every pet has an optional public_slug and a public_profile_enabled boolean. When the owner enables the profile from vetty:
POST /api/v1/owner/me/pets/{pet}/public-profilemints a slug if missing and setspublic_profile_enabled=true.- The owner can disable any time:
DELETE /api/v1/owner/me/pets/{pet}/public-profile.
Public surfaces
GET /p/{slug}(HTML, inroutes/web.php) renders a landing page with the pet's name, photo, owner-supplied notes, and a contact CTA.GET /api/v1/p/{slug}(JSON) is the same data as a structured payload — used by deep-linked app screens.
Privacy stance
The public profile only surfaces fields the owner explicitly opts into. Today the controller falls back to pet->client->phone when no profile-level phone is set — the audit calls this out as a P0 leak (see AUDIT.md §7) and the recommended fix is:
- Require
lost_mode_enabled_atbefore exposing any phone number. - Remove the fallback to the client's phone.
- Rate-limit
/p/{slug}and the JSON variant.
Lost-pet mode
Same profile, two extra columns: lost_mode_enabled_at and lost_mode_message.
Owner flow
POST /api/v1/owner/me/pets/{pet}/public-profile/lost— toggles lost-mode on, accepts amessagebody. The public landing page now shows the message in red, a "Last seen" date if supplied, and a click-to-reveal contact button.DELETE /api/v1/owner/me/pets/{pet}/public-profile/lost— owner marks the pet as found.
Finder flow
A passerby finds the pet, scans the QR on the collar tag, lands on /p/{slug}. They see the lost-pet message and a contact action (phone link / email link). The owner gets the inbound contact via their own number / email — Vetty doesn't intermediate the conversation.
Pet passport PDF
GET /api/v1/owner/me/pets/{pet}/passport.pdf (auth'd). Generated with dompdf. Single-shot — no caching — so the latest vaccinations / photo always appear.
The PDF includes:
- Pet header (name, species, breed, sex, DOB, weight, color, microchip if recorded).
- A QR code that resolves to
/p/{slug}(only whenpublic_profile_enabled=true). - A vaccination table (administered, manufacturer/batch, next due) read from
pet_vaccinations. - Owner contact (only when the public profile is enabled).
- Allergies and medical flags.
Owners typically download this for international travel or when boarding a pet at a new facility.
Vaccination certificate (related)
A different but adjacent PDF: GET /api/v1/owner/me/pets/{pet}/vaccination-certificate.pdf. Optional ?vaccination_id= for a single-vaccine certificate (e.g. rabies for travel) or omit it for the full history. Generated by the same OwnerPortalController.
Architectural notes
- Storage — none of these surfaces store generated PDFs to disk; they stream the generated bytes per request.
- Audit hooks — toggling lost-mode and enabling/disabling the public profile go through
Auditableso the timeline shows who changed what. - Tenants are uninvolved — these are owner-level features. Even though the pet always has a
tenant_id(the most recent clinic that wrote a record for it), public visibility is decided by the owner's toggle alone.
Roadmap
- Geo-fenced lost-pet alerts — community opt-in radius pings to nearby Vetty owners.
- Cross-tenant medical-record portability with explicit owner consent (so a passport PDF includes Rx history from any clinic the pet has visited).
- Photo carousel on the public profile.
- Print-ready collar-tag QR sticker template.