Skip to main content

Product Domain

The Vetty ubiquitous language.

Core entities

TermModelDescription
TenantTenantA veterinary clinic. Everything business-y lives under a tenant.
UserUserA person who can log in — either clinic staff (account_type = staff) or a pet owner (account_type = owner).
System AdminSystemAdminVetty employee who operates the platform. Separate table and guard.
ClientClientA pet owner from the clinic's perspective. May or may not have a users row linked through owner_user_id.
Pet (aka Patient)PetThe animal being treated. Owned by a Client.
AppointmentAppointmentA scheduled visit. Ties a Pet + Client + optional Veterinarian.
InvoiceInvoiceA billable document. May span multiple appointments; currency is per-invoice.
PaymentPaymentA single receipt/transaction against one invoice.
ReminderReminderAn 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. PatientOnboardingController is the controller you'd expect; Pet is the Eloquent model.
  • "Owner" can mean either a users row with account_type = owner, or a clients row 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 users row with tenant_user.role = 'veterinarian'. There's no separate vets table.

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) → confirmedchecked_incompleted. 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:

  1. Creating migrations (medicines, stock_movements, prescriptions, prescription_items).
  2. Adding Eloquent models with tenant_id.
  3. Adding controllers, routes, FormRequests and Resources.
  4. Swapping the frontend's mock services for HTTP ones.