Patients
The Patients module is the clinic-side view of pets and their owners. It runs through the Clients → Pets → Patient profile trio, with the patient profile carrying every clinical artefact attached to the pet.
Owner-side documents (passport, public profile, lost-pet mode) are documented in Pet Safety. Sharing flows (caregiver invites, share codes) live in Caregivers.
Clients
A clients row is the clinic's record of a pet owner. Captures full_name, contact details, status. May or may not be paired with a users row — walk-in cash clients have no users link; vetty users get auto-paired via owner_user_id on signup.
Endpoint: GET /api/v1/tenant/{tenant}/clients. (Show / update / destroy are on the audit roadmap.)
Pets
pets belong to a client and a tenant. The model carries:
- Identity — name, species, breed, sex, DOB, weight, color markings.
- Medical context —
allergies,medical_flags. - Public surfaces —
public_slug,public_profile_enabled,lost_mode_*.
Endpoints: full CRUD via the clinic onboarding controller for create/update; reading happens through GET /api/v1/tenant/{tenant}/pets and GET /api/v1/tenant/{tenant}/patients/{pet} (the latter returns a "consultation room briefing" — basics + active prescriptions + last visit + allergies in one round-trip, used by vetdoctor when a share code is scanned).
Patient profile (clinical artefacts)
The profile aggregates everything attached to a pet: visits, prescriptions, lab results, attachments, vaccinations, health logs, documents.
Visits (SOAP)
A visit carries the consultation header plus the SOAP narrative (subjective, objective, assessment, plan) and vitals (weight, temp, HR, RR). Optional prescription envelope and 0..N lab results hang off it. Ending the visit produces a discharge summary PDF (/visits/{visit}/discharge-summary.pdf).
Prescriptions
prescriptions carry an Rx envelope; prescription_items carry each medicine line with dosage, frequency, duration, route, quantity, refills. The consumeRefill() helper on PrescriptionItem decrements refills_remaining when a pharmacy fulfils a refill request.
Status enum: draft → active → completed | cancelled.
Lab results
lab_results are stored per-analyte (panel, analyte, value, unit, reference_range, flag). The flag enum (normal | low | high | critical) drives result colouring in the UI.
Medical attachments
medical_attachments are polymorphic — they hang off any clinical row (visit / prescription / lab result). Files live on the private disk; download streams through the controller so each fetch re-runs the tenant + permission check (no signed URLs at the clinical layer).
Vaccinations
pet_vaccinations is shared with the owner side. The same controller serves both surfaces:
- Owner:
/api/v1/owner/me/pets/{pet}/vaccinations.source=owneris stamped on creation. - Clinic:
/api/v1/tenant/{tenant}/patients/{pet}/vaccinations.source=clinicis stamped.
Each row carries administered_on, next_due_at, manufacturer, batch. The next_due_at field powers the "Due Soon" feed (/api/v1/owner/me/vaccinations/due) used by the vetty home tab.
Health journal
pet_health_logs is owner-friendly: weight, temperature, appetite (low / normal / high), free-text symptoms array, notes. Owner-written entries default to source=owner; clinic-written entries (e.g. a check-in weight) get source=clinic. Both surfaces share the controller.
Pet documents
pet_documents (insurance card, X-ray, lab PDF, ID) live on the private local disk. The owner uploads via POST /api/v1/owner/me/pets/{pet}/documents and downloads via a signed URL (GET /…/documents/{document}/download with signed middleware) — see Caregivers for access-level rules.
Unified timeline
Both apps render off a single endpoint:
- Owner:
GET /api/v1/owner/me/pets/{pet}/timeline - Clinic:
GET /api/v1/tenant/{tenant}/patients/{pet}/timeline
Returns a chronological feed mixing visits, prescriptions, vaccinations, lab results, health-journal entries, and documents.
Permissions
Reads and writes are gated on the medical_record.*, prescription.*, lab_result.*, attachment.*, and patient.* keys in App\Auth\PermissionRegistry. Default role bundles seed sensible defaults per business_type.
Audit + roadmap
- Patient timeline is implemented; vetdoctor and vetty already render off it (
AUDIT.md§2 cleared). - Vaccination-due feed exists; auto-reminder dispatch + local notifications on vetty are still on the roadmap.
- A small set of IDOR fixes are on the audit punch-list for owner-side write endpoints (audit P1).