Skip to main content

High-Level Architecture

This is the C4 Level 2 view — the containers inside the Vetty platform and how they collaborate.

Containers

Component responsibilities

React SPA (ui/)

Runs entirely in the browser, served as static assets (built with react-scripts).

  • Global state — two React Contexts: AuthContext (current user, session) and TenantContext (active clinic + list of available clinics). Wraps the tree at src/App.js.
  • Service layersrc/services/ contains an HTTP adapter and a Mock adapter that both satisfy the same interface (auth, patients, appointments, invoices, pharmacy, suppliers, purchaseOrders, reminders, clinical, admin, tenants). Which adapter is used is decided at build/runtime through REACT_APP_API_MODE.
  • Normalizerssrc/lib/normalizers.js converts raw Laravel responses into UI-friendly shapes (e.g. calculating pet age from date_of_birth).
  • Module switcherApp.js keeps the active module in state (dashboard, patients, appointments, billing, inventory, etc.) and renders the corresponding *Module component. A lightweight path check (/reset-password) routes the password-reset gate without introducing a full client router.

Mobile apps — vetty (vetyy/) and vetdoctor (vetdoctor/)

Two Flutter apps sharing the same architectural shape:

  • core/api/api_client.dart — native http wrapper that attaches the bearer token from AuthStore, parses JSON envelopes ({data: …} or raw), and throws a typed ApiException with statusCode on non-2xx.
  • core/auth/auth_store.dart — a ChangeNotifier-backed store that persists token + user (and tenant in vetdoctor) via shared_preferences. Screens rebuild via listenable: auth or a Root that watches auth.isAuthenticated.
  • Feature foldersfeatures/auth, features/pets (vetty only), features/shares, features/providers (vetty), features/appointments (vetdoctor), features/home. Each feature owns its thin service class plus a handful of screens.
  • Themingcore/theme.dart uses ColorScheme.fromSeed with different seeds per app so the two are instantly distinguishable: vetty is emerald (0xFF059669), vetdoctor is indigo (0xFF4F46E5).

vetty is a consumer pet-owner app (bottom-nav: Pets + Nearby, profile sheet for sign-out). vetdoctor is a clinician companion: today's schedule, a big Scan-share FAB that opens mobile_scanner, and recently-scanned pets on the dashboard.

Laravel API (backend/routes/api.php)

  • Flat v1 API at /api/v1.
  • Routes split into three blocks: system, auth, and tenant-scoped (/tenant/{tenant}/…) plus an owner portal block (/owner/me/*).
  • Tenant-scoped routes are wrapped with the ResolveTenantMembership middleware which resolves the {tenant} parameter into a model and attaches it to the request.

Filament admin (app/Filament/ + SystemadminPanelProvider)

  • Mounted at /systemadmin, uses the systemadmin auth guard (separate SystemAdmin model and table).
  • Provides CRUD UIs for every core entity: SystemAdmins, Tenants, Users, Clients, Pets, Appointments, Invoices, Payments, Reminders.
  • Has an OverviewDashboard widget with high-level platform metrics.

OpenAPI documentation

  • Controllers are annotated with Swagger-PHP attributes (#[OA\…]).
  • App\OpenApi\OpenApiSpec defines the top-level spec (tags: System, Auth, Tenants, Clinic, Owner).
  • php artisan openapi:generate writes storage/app/api-docs/openapi.json.
  • The file is served at GET /docs/openapi.json (see routes/web.php).

Request lifecycle

Here's what happens when the React SPA calls POST /api/v1/tenant/17/appointments:

Data flow — dashboard fetch

Why this shape

  • Versioned URI API (/api/v1) — gives a clean break if the contract changes without breaking existing pet-owner clients.
  • Filament side-car — Vetty operators and power users get a full CRUD UI "for free", without the React team having to build an admin console.
  • Thin React router via state — modules are large and self-contained, so state-driven switching is simpler than a route-per-module client router. (A future migration to react-router is straightforward because the modules are already decoupled.)
  • Adapter-pattern service layer — the same UI can run fully offline against mock services for demos, testing and frontend-first development.