Skip to main content

vetty — Pet-owner Mobile App

A Flutter (Dart) consumer app for pet owners. Lives at vetyy/ in the repo. Targets iOS, Android, web (Flutter web).

See the audit for the security and UX punch-list. This page is the feature catalogue.

Top-level navigation

The home shell carries five tabs:

  1. Home — pets carousel + quick actions (Add pet, Find a clinic, Lost pet toggle).
  2. Pets — list of owned pets + "Shared with me" caregiver section.
  3. Health — health journal entries across all pets, vaccinations-due feed.
  4. Orders & invoices — outstanding invoices + order request status.
  5. Profile — account settings, sessions, sign out.

Pet detail screen

The richest screen in the app. Tabs:

TabBacked by
Profilepet row + public-profile toggles
Vaccinationspet_vaccinations (CRUD), "due soon" inline
Documentspet_documents (upload, signed-URL download)
Health journalpet_health_logs (owner-write entries)
Caregiverspet_caregivers (invite / resend / revoke)
Timelineunified /timeline endpoint
Public profilecollar tag + lost-pet toggle

Auth

vetyy/lib/core/auth/:

  • auth_store.dart — token storage now uses flutter_secure_storage (keychain on iOS, encrypted SharedPreferences on Android). This was P0-11a in the Week 3 remediation.
  • api_client.dart — single HTTP wrapper. Bearer header attached per request. Talks to Env.apiBase which comes from --dart-define=VETTY_API_BASE=… at build time.

Release-build env-var guard

config/env.dart exposes Env.assertReleaseOverride() which main() calls before runApp. In release builds it throws a StateError unless VETTY_API_BASE_OVERRIDDEN=true was set at build time — a mis-configured CI ship gets caught on first launch rather than silently pointing customer devices at staging.

Features by domain

Marketplace

  • Find a clinic / pharmacy / groomer / breeder / trainer — hits GET /providers with business_type + geo filter (with location permission).
  • Detail screen → tap into provider profile.
  • "Place order" (pharmacy / retail) routes to the order-request flow.
  • "Book appointment" — top item on the pet-detail action menu. Owner picks reason + preferred date/time + optional note; POSTs to /owner/me/appointments with booking_source='owner_app'. The clinic sees the row as scheduled awaiting confirmation and confirms / reschedules through their standard queue.

Pet sharing & caregivers

  • Share pet → QR / code — generates a pet share token via POST /me/shares. The QR is the entry point for vetdoctor's scan flow.
  • Caregivers — primary owner can invite an email + access level. Resend / revoke from the same screen. The "Shared with me" tab on the pets list shows pets you've been invited to.

Lost pet & passport

  • Public profile toggle on each pet — mints a slug, shows the QR pointing to /p/{slug}.
  • Lost mode — bigger toggle on the public profile screen. Sets the lost message, exposes contact info on the public landing page.
  • Pet passport PDFGET /me/pets/{pet}/passport.pdf — downloadable. Includes the QR and vaccination history.

Vaccinations

  • Per-pet list + create / edit / delete.
  • Cross-pet "Due Soon" feed on the Health tab — pulled from /me/vaccinations/due (defaults to a 30-day horizon).
  • Vaccination certificate PDF (whole-pet or single-vaccine via ?vaccination_id=) for travel paperwork.

Health journal

  • Owner-written entries (weight, temperature, appetite, symptoms, notes).
  • Visible to active full-access caregivers.
  • Same controller surfaces clinic-recorded vitals (e.g. check-in weight) — those entries display with a clinic icon and the clinic name.

Documents

  • Upload categories: lab_report, xray, ultrasound, insurance, id, other.
  • Stored on the private disk; downloads use a short-lived signed URL.

Orders (commerce)

  • Refill — built from a past prescription via GET /me/pets/{pet}/prescriptions/{prescription}/refill-draft.
  • Reorder — repeat a non-Rx purchase from a tenant the owner has used before.
  • Custom — open ping to a marketplace pharmacy / retail tenant.
  • Status updates land on the Orders tab; the seller email contains a tracking link for the simple case.

Billing & payments

  • Invoice list + detail + receipt PDF.
  • Razorpay payment SDK launched from the invoice detail; verify runs after the SDK callback.
  • Cross-tenant statement PDF (/me/statement.pdf) for accountant exports.

Auth + password reset

  • Email + password login.
  • Self-serve registration (account_type='owner').
  • Forgot-password → reset flow over the same endpoints documented in Authentication.

Daily-use loops (per-pet)

Four screens designed for high-frequency owner tasks:

  • Medications — schedules (dose + time-slots) + per-dose log with mark-given/skip. Local notifications fire at each slot until the next dose is logged.
  • Feeding tracker — food catalog search + calorie summary with a target computed from the Resting Energy Requirement formula.
  • Activity — walk / play / swim log + 90-day heatmap.
  • Weight chart — full-screen fl_chart line chart plus a sparkline on the pet-detail summary card.

Quick wins

  • Pet share card — 1080×1080 PNG for Instagram / WhatsApp status. Rendered via RepaintBoundary.toImage, dispatched through share_plus.
  • Ask my vet — WhatsApp / SMS / call / copy sheet pre-filled with the clinic's contact info.
  • Confetti — birthday-today check on the pet, vaccination-add celebration.
  • Combined spend summary — 12-month bar strip on the invoices screen.
  • Quick-add FAB on home — walk / meal / weight without leaving home.
  • Per-pet notification mute — SharedPreferences-backed set that the notification scheduler and the pet-detail chip both read.

Health-journal photo

An owner-uploaded photo can attach to any journal entry. The FK column photo_document_id links to pet_documents; the journal card renders an inline 96×96 thumbnail (bearer-authed) with tap-to-open in the system viewer via ?token= query param (TokenFromQuery middleware promotes it to an Authorization header).

In-app notifications

The bell icon in the app bar polls /me/notifications/unread-count every 60 s and shows the badge. Tapping opens the inbox screen with swipe-to-delete + tap-to-mark- read. Deeplinks (vetty://pet/<id>, vetty://invoice/<id>, etc.) route into the matching screens. See Notifications for the full channel design.

Internationalization

Foundation lives at lib/core/i18n/i18n.dart. English and Hindi seed strings across common, auth, pets, and booking namespaces. main() calls await Vi18n.init() before render so the persisted locale hydrates from SharedPreferences. Full sweep across every screen is still a follow-up sprint.

State management

Provider + setState per screen. The audit's FutureBuilder race issue is fixed; list-key reuse was addressed in the vetyy #5–#8 sweep.

Known gaps (selected)

  • No offline mode / outbox queue.
  • No FCM / APNs push (in-app inbox is HTTP-pull only — see the notifications module doc for the roadmap).
  • Full i18n coverage on every screen (~30 strings seeded today).
  • Dark mode.

See AUDIT.md §8 for the full list.