m0hammadgh92/laravel-core-platform

A production-grade, business-agnostic, multi-tenant Core platform for Laravel 11

Maintainers

Package info

github.com/m0hammadgh/Multi-Vendor-Sale-System

pkg:composer/m0hammadgh92/laravel-core-platform

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.1 2025-12-28 10:54 UTC

This package is auto-updated.

Last update: 2026-03-28 11:39:17 UTC


README

A production-grade, business-agnostic, multi-tenant Core platform for Laravel 11, designed to be extracted into a Composer package.

๐ŸŽฏ Overview

This Core platform provides a complete foundation for building multi-tenant SaaS applications with complex business logic. It handles:

  • Multi-tenancy with domain-based resolution
  • Customer & User separation (authentication โ‰  commercial entity)
  • Order management with complete lifecycle
  • Billing & Invoicing with immutable financial records
  • Payment processing with gateway abstraction
  • Customer wallet system
  • Queue-driven architecture for all side-effects
  • Event-driven design for extensibility
  • Scoped settings with inheritance
  • Activity logging for audit trails
  • File management with polymorphic attachments

โœจ Key Principles

1. Queue-First Architecture

ALL external operations, slow I/O, emails, notifications, PDFs, payment processing happen via queued jobs ONLY.

2. Event-Driven Core

Business operations emit domain events. Listeners (all queued) respond to events for side-effects.

3. Strict Financial Discipline

  • Money stored as INTEGER minor units (cents) - NO FLOATS
  • Currency always stored alongside amounts
  • Immutable invoice numbers via transactional sequences
  • Wallet ledger with balance snapshots

4. Multi-Tenancy by Design

  • Every tenant-owned table has tenant_id
  • Tenant resolved by request domain
  • Global Eloquent scopes prevent cross-tenant data leak
  • All queries automatically scoped

5. Customer โ‰  User

  • Users: Authentication, activity causers
  • Customers: Commercial entities, own orders/invoices/payments/wallet
  • Orders, invoices, payments NEVER reference users directly

6. Package-Ready from Day One

  • No hardcoded business logic
  • No direct env() calls in logic
  • Everything configurable
  • Clear service contracts

๐Ÿ“ Structure

app/
โ”œโ”€โ”€ Core/
โ”‚   โ”œโ”€โ”€ Tenancy/          # Multi-tenant infrastructure
โ”‚   โ”œโ”€โ”€ Identity/         # Users (in app/Models/User.php)
โ”‚   โ”œโ”€โ”€ CRM/              # Customer management
โ”‚   โ”œโ”€โ”€ Catalog/          # Products & Variants
โ”‚   โ”œโ”€โ”€ Sales/            # Orders
โ”‚   โ”œโ”€โ”€ Billing/          # Invoices, Payments, Wallet, Sequences
โ”‚   โ”œโ”€โ”€ Pricing/          # Tax Rates, Coupons
โ”‚   โ”œโ”€โ”€ Settings/         # Scoped settings
โ”‚   โ”œโ”€โ”€ Notifications/    # Templates & Outbound Messages
โ”‚   โ”œโ”€โ”€ Files/            # File management
โ”‚   โ””โ”€โ”€ Audit/            # (uses spatie/activitylog)
โ”œโ”€โ”€ Support/
โ”‚   โ”œโ”€โ”€ Money/            # Money value object
โ”‚   โ”œโ”€โ”€ States/           # (To be created)
โ”‚   โ””โ”€โ”€ SettingsResolver/ # Settings inheritance resolver
โ”œโ”€โ”€ Events/               # Domain events (to be created)
โ”œโ”€โ”€ Listeners/            # Queued event listeners (to be created)
โ”œโ”€โ”€ Jobs/                 # Async jobs (to be created)
โ””โ”€โ”€ Policies/             # Authorization (to be created)

modules/                  # Future vertical modules (empty)

๐Ÿš€ Getting Started

Installation

This is already installed! The platform is ready to use.

Environment Setup

  1. Configure Database (already using SQLite for development)

  2. Configure Redis for queues (production):

QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
  1. Configure Mail (for notifications):
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

Running the Application

# Run migrations (already done)
php artisan migrate

# Start Horizon (queue worker)
php artisan horizon

# Start development server
php artisan serve

# Access Filament admin panel
open http://localhost:8000/admin

๐Ÿข Multi-Tenancy

How It Works

  1. Request arrives with domain (e.g., acme.example.com)
  2. ResolveTenantMiddleware extracts the host
  3. TenantContext queries tenant_domains table
  4. Tenant bound to container as 'tenant'
  5. All models with BelongsToTenant trait auto-scope to this tenant

Adding a Tenant

php artisan tinker
// Create tenant
$tenant = \App\Core\Tenancy\Tenant::create([
    'name' => 'Acme Corporation',
    'slug' => 'acme',
    'status' => 'active',
    'metadata' => [],
]);

// Add domain
$tenant->domains()->create([
    'domain' => 'acme.test',
    'is_primary' => true,
]);

// Create default brand (optional)
$tenant->brands()->create([
    'name' => 'Acme Brand',
    'slug' => 'default',
    'is_default' => true,
]);

// Create admin user for this tenant
$user = \App\Models\User::create([
    'tenant_id' => $tenant->id,
    'name' => 'Admin User',
    'email' => 'admin@acme.test',
    'password' => bcrypt('password'),
    'role' => 'admin',
    'is_active' => true,
]);

Testing Multi-Tenancy Locally

Add to /etc/hosts:

127.0.0.1 acme.test
127.0.0.1 demo.test

Then access: http://acme.test:8000

๐Ÿ’ฐ Money Handling

All monetary values use the Money value object:

use App\Support\Money\Money;

// From minor units (cents)
$price = Money::fromMinor(1999, 'USD'); // $19.99

// From major units (dollars)
$price = Money::fromMajor(19.99, 'USD'); // $19.99

// Operations
$total = $price->multiply(3); // $59.97
$discount = $price->percentage(2000); // 20% = $3.998 โ†’ $4.00
$final = $total->subtract($discount); // $55.97

// Display
echo $price->format(); // "$19.99"

๐Ÿ“‹ Order Lifecycle

draft
 โ†“ (OrderSubmitted event)
pending_payment
 โ†“ (PaymentCaptured event โ†’ OrderPaid event)
paid
 โ†“ (items fulfilled)
closed

OR

canceled (from draft/pending_payment)
refunded (from paid)

Creating an Order

use App\Core\Sales\Order;
use App\Core\Billing\Sequence;

$order = Order::create([
    'tenant_id' => $tenant->id,
    'customer_id' => $customer->id,
    'order_number' => Sequence::nextFor($tenant->id, 'order', 'ORD-'),
    'status' => 'draft',
    'currency' => 'USD',
    // Amounts calculated by OrderCalculator service
]);

// Add items
$order->items()->create([
    'tenant_id' => $tenant->id,
    'product_variant_id' => $variant->id,
    'product_name' => $variant->product->name,
    'variant_name' => $variant->name,
    'quantity' => 1,
    'unit_price_minor' => $variant->price_minor,
    'currency' => 'USD',
    // Calculate totals
]);

๐Ÿ“„ Invoice System

Invoices are immutable financial documents with:

  • Unique sequential numbers (thread-safe generation via Sequence)
  • Customer snapshot (for legal record)
  • Cannot be deleted (only voided)

Creating an Invoice

use App\Core\Billing\Invoice;
use App\Core\Billing\Sequence;

$invoice = Invoice::create([
    'tenant_id' => $tenant->id,
    'customer_id' => $customer->id,
    'order_id' => $order->id,
    'invoice_number' => Sequence::nextFor($tenant->id, 'invoice', 'INV-'),
    'status' => 'draft',
    'currency' => 'USD',
    'customer_snapshot' => $customer->toArray(), // Immutable record
]);

// Generate PDF via queued job
GenerateInvoicePdfJob::dispatch($invoice);

๐Ÿ‘› Wallet System

Customers can have wallet balances (one per currency):

$wallet = $customer->walletAccounts()->firstOrCreate([
    'currency' => 'USD',
], [
    'balance_minor' => 0,
]);

// Credit wallet (via WalletService for transactional safety)
app(\App\Core\Billing\Services\WalletService::class)
    ->credit($wallet, Money::fromMajor(50.00, 'USD'), 'Initial credit');

// Debit wallet
app(\App\Core\Billing\Services\WalletService::class)
    ->debit($wallet, Money::fromMajor(10.00, 'USD'), 'Payment');

โš™๏ธ Settings System

Settings follow this precedence: user โ†’ customer โ†’ brand โ†’ tenant โ†’ global

use App\Support\SettingsResolver\SettingsResolver;

$resolver = app(SettingsResolver::class);

// Get setting with context
$value = $resolver->get(
    key: 'theme.color',
    default: 'blue',
    userId: $user->id,
    customerId: $customer->id
);

// Set setting
$resolver->set(
    key: 'theme.color',
    value: 'red',
    scopeType: 'customer',
    scopeId: $customer->id
);

๐Ÿ”” Notifications

All notifications are queued jobs that create OutboundMessage records:

// Listen to event
class OrderConfirmationListener
{
    public function handle(OrderSubmitted $event)
    {
        SendOrderConfirmationJob::dispatch($event->order);
    }
}

๐Ÿ“ฆ Queue Lanes

Three priority lanes:

  1. critical: Payment callbacks, critical operations (3 workers, timeout 300s)
  2. default: Notifications, emails (5 workers, timeout 180s)
  3. low: PDFs, exports, background tasks (2 workers, timeout 600s)

Dispatch to specific queue:

GenerateInvoicePdfJob::dispatch($invoice)->onQueue('low');
PaymentCallbackJob::dispatch($payment)->onQueue('critical');

๐Ÿงฉ Extending with Modules

Future vertical modules for your specific business needs should:

  1. Live in modules/ModuleName/
  2. Have own Models, Services, Events, Jobs
  3. Can extend Core models (Order, Customer, Product)
  4. Listen to Core events for integration
  5. Never depend on other modules

Example:

// modules/YourModule/Models/CustomEntity.php
class CustomEntity extends Model
{
    public function order()
    {
        return $this->belongsTo(\App\Core\Sales\Order::class);
    }
}

// modules/YourModule/Listeners/HandleOrderPaid.php
class HandleOrderPaid
{
    public function handle(OrderPaid $event)
    {
        if ($event->order->hasProductType('your_product_type')) {
            YourCustomJob::dispatch($event->order);
        }
    }
}

๐Ÿ” Security

Policies (To Be Created)

All Filament resources should use policies:

  • Tenant scoping enforced
  • Role-based permissions
  • Super admin bypass for tenant management

Authentication

Users access Filament admin panel if:

  • is_active = true
  • role IN ('super_admin', 'admin')

๐Ÿงช Testing

# Run all tests
php artisan test

# Run specific test suite
php artisan test --testsuite=Feature

# Run with coverage
php artisan test --coverage

Critical test areas:

  • Tenant isolation (no cross-tenant data leakage)
  • Money calculations (precision)
  • Sequence generation (thread-safety)
  • Wallet transactions (balance integrity)
  • Event/listener flow

๐Ÿ“Š Admin Panel (Filament)

Access at /admin with admin credentials.

Resources to create:

  • Tenants (super_admin only)
  • Users
  • Customers
  • Products & Variants
  • Orders
  • Invoices
  • Payments
  • Wallet Accounts
  • Coupons
  • Tax Rates
  • Settings
  • Files
  • Outbound Messages
  • Activity Log

๐Ÿ”„ Development Workflow

Creating a New Domain Feature

  1. Create migration in database/migrations/
  2. Create model in app/Core/{Domain}/
  3. Create event(s) in app/Events/
  4. Create listener(s) in app/Listeners/ (queued!)
  5. Create job(s) in app/Jobs/
  6. Create service/action in app/Core/{Domain}/Actions/
  7. Create Filament resource in app/Filament/Resources/
  8. Write tests in tests/Feature/{Domain}/

Example: Adding Refund Support

// 1. Update migrations (already has refunded_minor)

// 2. Create event
class RefundCreated
{
    public function __construct(public Payment $payment) {}
}

// 3. Create listener
class UpdateInvoiceAfterRefund
{
    public function handle(RefundCreated $event)
{
        $invoice = $event->payment->invoice;
        $invoice->increment('refunded_minor', $event->payment->amount_minor);
        $invoice->save();
    }
}

// 4. Create job
class ProcessRefundJob implements ShouldQueue
{
    public $queue = 'critical';
    
    public function handle()
    {
        // Process refund via gateway
        // Fire RefundCreated event
    }
}

๐ŸŽฏ Roadmap

Completed โœ…

  • Database schema (all 24 migrations)
  • Multi-tenancy infrastructure
  • Core models (Tenant, Customer, User, Product, Order, Invoice, Payment, Wallet)
  • Money value object
  • Settings resolver
  • Filament & Horizon integration

In Progress ๐Ÿ”จ

  • Domain events
  • Queued listeners
  • Background jobs
  • Filament resources
  • Policies

Planned ๐Ÿ“‹

  • API layer (optional)
  • Webhook system
  • PDF generation service
  • Payment gateway drivers
  • Fulfillment system abstraction
  • Test suite
  • Package extraction

๐Ÿ“š Resources

๐Ÿ“„ License

Proprietary. Not for redistribution.

๐Ÿ™ Credits

Built with:

  • Laravel 11
  • Filament 3
  • Laravel Horizon
  • Spatie Laravel Activity Log

Built for production. Designed for extensibility. Ready for extraction.

Testing webhook