Product Domain
The Vetty ubiquitous language.
Core entities
| Term | Model | Description |
|---|---|---|
| Tenant | Tenant | A veterinary clinic. Everything business-y lives under a tenant. |
| User | User | A person who can log in — either clinic staff (account_type = staff) or a pet owner (account_type = owner). |
| System Admin | SystemAdmin | Vetty employee who operates the platform. Separate table and guard. |
| Client | Client | A pet owner from the clinic's perspective. May or may not have a users row linked through owner_user_id. |
| Pet (aka Patient) | Pet | The animal being treated. Owned by a Client. |
| Appointment | Appointment | A scheduled visit. Ties a Pet + Client + optional Veterinarian. |
| Invoice | Invoice | A billable document. May span multiple appointments; currency is per-invoice. |
| Payment | Payment | A single receipt/transaction against one invoice. |
| Reminder | Reminder | An automated nudge about an upcoming vaccination, follow-up, etc. |
Relationships in words
- A tenant has many clients, pets, appointments, invoices, payments and reminders.
- A client belongs to one tenant, owns many pets, and has many appointments/invoices.
- A pet belongs to exactly one client (which belongs to exactly one tenant). It can have many appointments and invoices.
- An appointment is always linked to a pet + client, optionally to a veterinarian, always in one tenant.
- An invoice is always linked to a client and a tenant, optionally to a pet. One invoice can have many payments, collectively reducing
balance_due. - A reminder is scoped to a tenant and optionally to a specific client or pet. Channel choice (
email/sms/push/in_app) determines how it's delivered.
Vocabulary notes
- The UI sometimes says "patient"; the DB/API calls it "pet". They're the same thing.
PatientOnboardingControlleris the controller you'd expect;Petis the Eloquent model. - "Owner" can mean either a
usersrow withaccount_type = owner, or aclientsrow from the clinic's perspective. When a pet owner logs into the SPA they authenticate as the user and read rows as the client. - "Veterinarian" is just a
usersrow withtenant_user.role = 'veterinarian'. There's no separatevetstable.
Enumerations
subscription_plan
trial, starter, growth, premium, enterprise — stored on the tenant, not yet gated in code.
tenants.status
active (default) | suspended | cancelled. Non-active tenants are blocked by ResolveTenantMembership.
users.account_type
staff | owner.
pets.sex
male | female | unknown. Default unknown.
pets.status
active (default) | inactive | deceased.
appointments.status
scheduled (default) → confirmed → checked_in → completed. Alternative terminal states: cancelled, no_show.
appointments.booking_source
clinic_portal (default) | owner_app | phone | walk_in. Purely informational — used for reporting to understand channel mix.
invoices.status
draft | pending (default) | partial | paid | void.
invoices.invoice_type
estimate | invoice (default). Estimates don't affect balance_due tracking yet — that's a known gap.
invoices.currency
ISO 4217 string. Defaults to INR. A future enhancement: tenant-wide default currency or per-invoice selection.
payments.payment_method
cash (default) | card | upi | bank_transfer | online.
payments.status
pending | captured (default) | failed | refunded.
reminders.reminder_type
vaccination | deworming | follow_up | payment_due | general.
reminders.channel
email | sms | push | in_app (default).
reminders.status
pending (default) | sent | dismissed | failed.
tenant_user.role
Convention: clinic_admin, veterinarian, staff (strings — no DB-level enum).
Why there is no prescriptions or inventory table yet
The React UI exposes a Prescriptions module and an Inventory module, but the Laravel backend doesn't yet have dedicated tables for them. Today those modules run against the mock adapter or stub services. Adding them is a matter of:
- Creating migrations (
medicines,stock_movements,prescriptions,prescription_items). - Adding Eloquent models with
tenant_id. - Adding controllers, routes, FormRequests and Resources.
- Swapping the frontend's mock services for HTTP ones.