Skip to main content
The backend is built on Laravel 12 with a multi-tenant architecture using the Stancl Tenancy package. Each tenant operates in an isolated database while sharing the same application codebase.

Architecture Overview

Multi-Tenancy

Database-per-tenant strategy with automatic tenant identification

Domain-Based Routing

Separate route files for system and tenant domains

Service Layer

Business logic encapsulated in service classes

Inertia Integration

Server-side rendering with Vue components

Multi-Tenancy

The application uses Stancl Tenancy to provide database isolation for each customer.

How It Works

1

Tenant Identification

The tenancy middleware identifies tenants by subdomain:
2

Database Switching

Stancl automatically switches database connections based on the current tenant:
3

Isolated Data

Each tenant’s data is completely isolated:

Tenant Model

app/Models/System/Tenant.php

Models

Models are organized into System and Tenant namespaces:

System Models (Central Database)

app/Models/System/Tenant.php

Tenant Models (Tenant Databases)

app/Models/Tenant/User.php
Important: Tenant models use the tenant database connection, automatically set by Stancl Tenancy middleware.

Controllers

Controllers are organized by domain (System vs Tenant) and responsibility:

System Controllers

app/Http/Controllers/System/DashboardController.php

Resource Controllers

Use Laravel’s resource controller pattern:
app/Http/Controllers/System/TenantController.php

Services

Business logic is encapsulated in service classes:
app/Services/System/TenantService.php

Service Benefits

Business logic is centralized, making controllers thin and focused on HTTP concerns.
Services can be used from controllers, commands, jobs, and tests.
Services are easy to test in isolation with dependency injection.
Complex operations with multiple database calls are wrapped in transactions.

Routing

Routes are organized by domain:

System Routes

routes/web.php

Tenant Routes

routes/tenant.php

Middleware

Key middleware in the application:

InitializeTenancyByDomain

Identifies tenant by subdomain and switches database connection

HandleInertiaRequests

Shares data across all Inertia pages (auth user, flash messages)

auth

Ensures user is authenticated before accessing protected routes

verified

Ensures user has verified their email address

Database Migrations

Central Database Migrations

database/migrations/create_plans_table.php

Tenant Database Migrations

database/migrations/tenant/create_users_table.php
Migrations in database/migrations/tenant/ run automatically when a new tenant is created.

Authentication

The application uses Laravel Fortify for authentication:
  • Login / Logout
  • Registration
  • Password Reset
  • Email Verification
  • Two-Factor Authentication
  • Password Confirmation

API Development

API routes are defined in routes/api.php:
routes/api.php
Laravel Sanctum provides API token authentication for SPAs and mobile apps.

Commands

Custom Artisan commands for administrative tasks:

Best Practices

  • Keep controllers thin, delegate to services
  • Use resource controllers for CRUD operations
  • Validate requests with Form Request classes
  • Return Inertia responses for frontend views
  • Encapsulate complex business logic
  • Use dependency injection
  • Return models or collections, not views
  • Wrap multi-step operations in transactions
  • Never query tenant data from system context
  • Always use tenant() helper to get current tenant
  • Test tenant isolation thoroughly
  • Use $tenant->run() to execute code in tenant context
  • Use eager loading to prevent N+1 queries
  • Index foreign keys and frequently queried columns
  • Use database transactions for data consistency
  • Leverage Eloquent relationships

Next Steps

Testing

Learn how to test Laravel controllers and services

Frontend Development

Integrate backend with Vue components