Skip to main content

Backend Structure

backend/
├── app/
│ ├── Filament/
│ │ ├── Resources/
│ │ │ ├── SystemAdmins/…
│ │ │ ├── Tenants/…
│ │ │ ├── Users/…
│ │ │ ├── Clients/…
│ │ │ ├── Pets/…
│ │ │ ├── Appointments/…
│ │ │ ├── Invoices/…
│ │ │ ├── Payments/…
│ │ │ └── Reminders/…
│ │ └── Widgets/OverviewDashboard.php
│ ├── Http/
│ │ ├── Controllers/Api/V1/
│ │ │ ├── AuthController.php
│ │ │ ├── SystemController.php
│ │ │ ├── TenantController.php
│ │ │ ├── Clinic/
│ │ │ │ ├── DashboardController.php
│ │ │ │ ├── ClientController.php
│ │ │ │ ├── PetController.php
│ │ │ │ ├── AppointmentController.php
│ │ │ │ ├── InvoiceController.php
│ │ │ │ └── PatientOnboardingController.php
│ │ │ └── Owner/OwnerPortalController.php
│ │ ├── Middleware/
│ │ │ └── ResolveTenantMembership.php
│ │ ├── Requests/Api/V1/ # FormRequests (validation)
│ │ └── Resources/Api/V1/ # Response shaping
│ ├── Models/
│ │ ├── User.php
│ │ ├── SystemAdmin.php
│ │ ├── Tenant.php
│ │ ├── Client.php
│ │ ├── Pet.php
│ │ ├── Appointment.php
│ │ ├── Invoice.php
│ │ ├── Payment.php
│ │ └── Reminder.php
│ ├── OpenApi/OpenApiSpec.php # Global OpenAPI metadata
│ └── Providers/
│ ├── AppServiceProvider.php
│ └── Filament/SystemadminPanelProvider.php
├── bootstrap/
├── config/
│ ├── auth.php # Guards and providers
│ ├── sanctum.php # Token auth
│ ├── filament.php # Filament defaults
│ └── … (app, cache, database, filesystems, logging, mail, queue, services, session)
├── database/
│ ├── factories/
│ ├── migrations/ # Timestamped schema migrations
│ ├── seeders/DatabaseSeeder.php
│ └── database.sqlite # Optional dev DB
├── public/ # Front controller + index.php
├── resources/ # Views (Filament assets copied here)
├── routes/
│ ├── api.php
│ ├── web.php
│ └── console.php
├── storage/
│ └── app/api-docs/openapi.json # Generated output
├── tests/
├── composer.json
├── composer.lock
├── artisan
├── .env.example
└── phpunit.xml

Folder-by-folder

app/Http/Controllers/Api/V1

Controllers are thin: they invoke FormRequest::validated(), call Eloquent, and return a Resource. Business rules that don't fit in a model live here for now (see Clinic/InvoiceController::recordPayment updating status/balance).

Sub-folders group controllers by audience:

  • Root (AuthController, SystemController, TenantController) — public and cross-cutting endpoints.
  • Clinic/ — endpoints consumed by clinic staff (dashboards, pets, clients, appointments, invoices).
  • Owner/ — endpoints for the pet-owner portal, scoped to the logged-in owner only.

app/Http/Requests/Api/V1

One FormRequest per write endpoint. Naming pattern: StoreXRequest, UpdateXRequest, UpdateXStatusRequest etc. Each defines:

  • authorize() — returns true (delegated to route middleware) unless the endpoint needs custom policy.
  • rules() — the validation schema.
  • prepareForValidation() — optional normalization (e.g. cast empty strings to null).

app/Http/Resources/Api/V1

One JsonResource per model. Resources know which fields are safe to expose. They use whenLoaded() to avoid touching relationships the caller didn't request.

app/Http/Middleware

  • ResolveTenantMembership — the gatekeeper for every /tenant/{tenant}/* request. It:
    1. Binds {tenant} to a Tenant model (via route-model binding).
    2. Ensures the authenticated user has an active tenant_user row for this tenant.
    3. Attaches the tenant to the request attributes.

app/Models

Each model declares $fillable + typed $casts + relationships. Conventions:

  • Every model (except User, SystemAdmin) has a tenant_id FK and a tenant() relationship.
  • Timestamps left at Laravel defaults.
  • password cast to 'hashed' on User and SystemAdmin.

app/Filament

Each Filament resource has three pieces:

  • *Resource.php — entry point that declares the model and the pages it exposes (index, create, edit).
  • Schemas/*Form.php — form definition (fields and layout).
  • Tables/*Table.php — list-view definition (columns, filters, actions).
  • Pages/List*.php, Create*.php, Edit*.php — thin page classes that Filament renders.

app/OpenApi/OpenApiSpec.php

Holds:

  • #[OA\Info(title: 'Vetty Backend API', version: '1.0.0')]
  • #[OA\Server(url: '/')]
  • #[OA\Tag(...)] tags for System, Auth, Tenants, Clinic, Owner.
  • The shared ErrorResponse schema.

Methods on individual controllers annotate their own paths.

routes/

  • api.php — the whole API contract (see Routes for the full map).
  • web.php — two routes: GET / (health/info landing) and GET /docs/openapi.json (serves the generated spec).
  • console.php — the openapi:generate artisan command that writes storage/app/api-docs/openapi.json.

database/

  • migrations/ — 12+ files, timestamped. The first two (0001_01_01_000000_*) create users and system_admin. The rest, dated 2026_04_15_*, create the Vetty-specific tables.
  • seeders/DatabaseSeeder.php — deterministic sample data for local dev.
  • factories/ — Eloquent factories that power tests.

tests/

Feature and unit tests. Uses database/verify.sqlite so the main dev DB isn't touched.