T
Tenanto
Documentation / README

README

Updated Jan 25, 2026

Tenanto

Production-ready Laravel Multi-Tenant SaaS Boilerplate

A comprehensive Laravel 12 boilerplate for building multi-tenant SaaS applications with built-in billing, team management, and admin panels.


Features

Multi-Tenancy

Authentication & Authorization

Billing & Subscriptions

Admin Panels (FilamentPHP 3)

API

Marketplace & Distribution

Internationalization (i18n)

Developer Experience


Requirements


Quick Start

1. Clone the Repository

# Replace with your repository URL
git clone https://your-git-host.com/your-org/tenanto.git
cd tenanto

2. Start Docker Environment

docker compose up -d

3. Install Dependencies

docker compose exec app composer install
docker compose exec app npm install && npm run build

4. Configure Environment

cp .env.example .env
docker compose exec app php artisan key:generate

Edit .env with your settings:

5. Run Migrations & Seed

docker compose exec app php artisan migrate --seed

6. Configure Local DNS

Add to your hosts file:

127.0.0.1 tenanto.local
127.0.0.1 admin.tenanto.local
127.0.0.1 demo.tenanto.local

7. Access the Application

URL Redirects To Credentials
http://tenanto.local Landing page -
http://admin.tenanto.local /admin (System Admin) [email protected] / password
http://demo.tenanto.local /app (Tenant App) [email protected] / password
http://demo.tenanto.local/api/v1 API Bearer token
http://admin.tenanto.local/horizon Queue Dashboard System admin only
http://localhost:8025 Email Testing No auth required

URL Structure:


Docker Services

The docker compose up -d command starts all 7 services automatically:

Service Container Port Description
app tenanto_app - PHP-FPM 8.4 application server
nginx tenanto_nginx 80, 443 Web server with SSL support
db tenanto_db 5432 PostgreSQL 16 database
redis tenanto_redis 6379 Cache, sessions, and queue broker
queue tenanto_queue - Laravel Horizon (background jobs)
scheduler tenanto_scheduler - Laravel task scheduler (cron jobs)
mailhog tenanto_mailhog 1025, 8025 SMTP server + Email testing UI

Service Details

Useful Commands

# View all container logs
docker compose logs -f

# View specific service logs
docker compose logs -f queue

# Restart all services
docker compose restart

# Rebuild containers (after Dockerfile changes)
docker compose up -d --build

# Stop all services
docker compose down

Project Structure

app/
├── Domain/                 # Business logic (DDD-lite)
│   ├── Authorization/      # Roles & permissions
│   ├── Billing/            # Stripe/subscription logic
│   ├── Demo/               # Demo tenant automation
│   ├── ExampleApp/         # Demo module (Projects/Tasks)
│   ├── Licensing/          # License key management
│   ├── Onboarding/         # Customer onboarding wizard
│   ├── Support/            # Support ticket system
│   ├── Tenancy/            # Multi-tenant core
│   └── Updates/            # Version update notifications
├── Filament/
│   ├── Admin/              # System admin panel
│   └── Tenant/             # Per-tenant admin panel
└── Http/
    ├── Controllers/Api/    # API controllers
    └── Middleware/         # Tenant middleware

docs/
├── api.md                  # API documentation
├── authorization.md        # Roles & permissions guide
├── backup-restore.md       # Backup & recovery guide
├── deployment.md           # Deployment guide
├── example-module.md       # Module development guide
├── filament.md             # FilamentPHP customization
├── i18n.md                 # Internationalization guide
├── launch-checklist.md     # Production launch checklist
├── marketplace.md          # Marketplace features documentation
├── multi-tenancy.md        # Multi-tenancy architecture
├── performance.md          # Performance optimization
└── security.md             # Security checklist

tests/
├── Feature/                # Integration tests
└── Unit/                   # Unit tests

e2e/                        # Playwright E2E tests (484 tests)
├── admin/                  # Admin panel tests
├── auth/                   # Authentication tests
├── api/                    # API tests
├── errors/                 # Error page tests
├── helpers/                # Test utilities (auth, api)
├── isolation/              # Tenant isolation tests
├── navigation/             # Navigation tests
├── onboarding/             # Onboarding wizard tests
└── tenant/                 # Tenant panel tests

Getting Started for Developers

This section guides you through customizing Tenanto for your own SaaS product.

Step 1: Remove the Example Module

The ExampleApp module (Projects/Tasks) is included as a reference implementation. To remove it:

# Remove domain files
rm -rf app/Domain/ExampleApp

# Remove Filament resources
rm -rf app/Filament/Tenant/Resources/ProjectResource
rm -rf app/Filament/Tenant/Resources/TaskResource
rm -rf app/Filament/Tenant/Resources/ProjectResource.php
rm -rf app/Filament/Tenant/Resources/TaskResource.php
rm -rf app/Filament/Tenant/Widgets/ProjectStatsWidget.php
rm -rf app/Filament/Tenant/Widgets/TaskStatsWidget.php

# Remove API controllers
rm app/Http/Controllers/Api/V1/ProjectController.php
rm app/Http/Controllers/Api/V1/TaskController.php

# Remove migrations
rm database/migrations/*_create_projects_table.php
rm database/migrations/*_create_tasks_table.php

# Remove factories, seeders, and tests
rm database/factories/ProjectFactory.php
rm database/factories/TaskFactory.php
rm database/seeders/ExampleAppSeeder.php
rm -rf tests/Feature/Api/Project*
rm -rf tests/Feature/Api/Task*

# Clean up API routes
# Edit routes/api.php and remove Project/Task routes

Step 2: Create Your Own Module

Follow this pattern to add tenant-scoped models:

// 1. Create Model with BelongsToTenant trait
namespace App\Domain\YourModule\Models;

use App\Domain\Tenancy\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;

class YourModel extends Model
{
    use BelongsToTenant;

    protected $fillable = ['tenant_id', 'name', ...];
}

// 2. Create Migration with tenant_id
Schema::create('your_models', function (Blueprint $table) {
    $table->id();
    $table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
    $table->string('name');
    $table->timestamps();

    // Always add composite index for tenant queries
    $table->index(['tenant_id', 'created_at']);
});

// 3. Create Policy for authorization
namespace App\Policies;

use App\Domain\YourModule\Models\YourModel;
use App\Models\User;

class YourModelPolicy
{
    public function viewAny(User $user): bool
    {
        return $user->can('view your-models');
    }

    public function view(User $user, YourModel $model): bool
    {
        // Defense-in-depth: verify tenant ownership
        return $user->tenant_id === $model->tenant_id;
    }
}

// 4. Create Filament Resource
// See docs/example-module.md for complete guide

Step 3: Configure Your Plans

Edit config/billing.php to define your subscription tiers:

'plans' => [
    'starter' => [
        'name' => 'Starter',
        'stripe_price_id' => env('STRIPE_PRICE_STARTER'),
        'features' => [
            'users' => 3,
            'your_feature' => 100,
            'premium_feature' => false,
        ],
    ],
    // Add more plans...
],

Step 4: Customize Branding

Step 5: Set Up Stripe

  1. Create products/prices in Stripe Dashboard
  2. Copy Price IDs to .env:
    STRIPE_PRICE_STARTER=price_xxx
    STRIPE_PRICE_PROFESSIONAL=price_yyy
    
  3. Set up webhooks pointing to /stripe/webhook
  4. Test with Stripe CLI: stripe listen --forward-to localhost/stripe/webhook

Key Concepts

Concept Location Purpose
BelongsToTenant app/Domain/Tenancy/Traits/ Auto-scopes models to current tenant
TenantScope app/Domain/Tenancy/Scopes/ Filters all queries by tenant_id
TenantMiddleware app/Http/Middleware/ Resolves tenant from subdomain/domain
PlanFeatureService app/Domain/Billing/Services/ Checks feature limits per plan

For detailed documentation, see docs/example-module.md.


Development Commands

# Start development environment
make up

# Run tests
make test

# Run static analysis
make lint

# Fix code style
make fix

# Fresh database with seeds
make db-fresh

# Enter app container
make shell

See Makefile for all available commands.


API Overview

Base URL: /api/v1/

Authentication

POST /api/v1/auth/login
POST /api/v1/auth/logout
GET  /api/v1/auth/me

Resources

# Projects
GET    /api/v1/projects
POST   /api/v1/projects
GET    /api/v1/projects/{id}
PUT    /api/v1/projects/{id}
DELETE /api/v1/projects/{id}
POST   /api/v1/projects/{id}/archive
POST   /api/v1/projects/{id}/unarchive

# Tasks
GET    /api/v1/projects/{id}/tasks
POST   /api/v1/projects/{id}/tasks
GET    /api/v1/tasks/{id}
PUT    /api/v1/tasks/{id}
DELETE /api/v1/tasks/{id}
POST   /api/v1/tasks/{id}/complete

See docs/api.md for complete API documentation.


Testing

PHP Tests (PHPUnit/Pest)

# Run all PHP tests
docker compose exec app php artisan test

# Run with coverage
docker compose exec app php artisan test --coverage

# Run specific group
docker compose exec app php artisan test --group=tenant-isolation

Test Groups:

E2E Tests (Playwright)

# Install Playwright
npm install
npx playwright install chromium

# Run all E2E tests
npx playwright test --project=chromium

# Run specific test file
npx playwright test e2e/auth/login.spec.ts

# Run with UI mode
npx playwright test --ui

# View HTML report
npx playwright show-report

E2E Test Coverage (484 tests):

Category Tests Description
Auth 95 Login, logout, register, password reset, email verification
Admin Panel 76 Tenants, users, licenses, dashboard
Tenant Panel 101 Projects, tasks, teams, users, profile, billing
API 22 Authentication, CRUD operations
Isolation 44 Tenant isolation, permission enforcement
Navigation 26 Route testing, menu visibility
Onboarding 23 Wizard flow
Errors 23 Error pages (403, 404, 500)

Configuration: playwright.config.ts


Configuration

Environment Variables

Key variables in .env:

# Tenancy
TENANCY_MODE=subdomain
TENANT_CENTRAL_DOMAINS=tenanto.local,admin.tenanto.local

# Billing
STRIPE_KEY=pk_test_xxx
STRIPE_SECRET=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

# Plans
STRIPE_PRICE_BASIC=price_xxx
STRIPE_PRICE_PRO=price_xxx
STRIPE_PRICE_ENTERPRISE=price_xxx

See .env.example for all options with documentation.

Subscription Plans

Configure in config/billing.php:

'plans' => [
    'basic' => [
        'name' => 'Basic',
        'stripe_price_id' => env('STRIPE_PRICE_BASIC'),
        'features' => [
            'users' => 5,
            'teams' => 1,
            'projects' => 10,
        ],
    ],
    // ...
],

Deployment

See docs/deployment.md for production deployment instructions.

Quick Checklist


Security

Built-in Protections

See docs/security.md for security checklist.


Documentation

Document Description
Multi-Tenancy Architecture Tenant isolation and scoping
Authorization & Permissions RBAC and policies
FilamentPHP Customization Admin panel configuration
API Documentation Complete API reference
Deployment Guide Production deployment
Security Checklist Security best practices
Example Module Building custom modules
Performance Guide Optimization strategies
i18n Guide Internationalization setup
Backup & Restore Backup strategies and recovery
Launch Checklist Production launch checklist
Marketplace Features Demo, licensing, onboarding, updates
CodeCanyon Guide Buyer guide for CodeCanyon purchases
Troubleshooting Common issues and solutions
UPGRADING Version upgrade instructions
CHANGELOG Version history and changes
Third-Party Licenses Dependency licenses

Tech Stack

Component Technology
Framework Laravel 12
PHP Version 8.4
Admin Panel FilamentPHP 3
Frontend Livewire 3 + Tailwind CSS
Database PostgreSQL 16
Cache/Queue Redis 7
API Auth Laravel Sanctum
Billing Laravel Cashier (Stripe)
Permissions spatie/laravel-permission
Testing PHPUnit + Pest (607 tests)
E2E Testing Playwright (484 tests)
Static Analysis PHPStan Level 8
Code Style Laravel Pint

Support

Email: [email protected]

Response Time:

What's Included:

What's Not Included:

For CodeCanyon buyers, support is provided according to Envato's Item Support Policy.

See docs/codecanyon.md for CodeCanyon-specific information. See docs/troubleshooting.md for common issues and solutions.


License

Tenanto is commercial software. See LICENSE for details.

Third-party dependencies are licensed under MIT, BSD-3-Clause, and Apache-2.0 licenses. See THIRD_PARTY_LICENSES.md for details.


Credits

Built with: