Backend Architecture
Saucebase is built on Laravel 12 with a modular architecture. This guide covers what's unique to Saucebase — for standard Laravel patterns, see the Laravel Documentation.
Architecture Overview
Service Providers
Service providers are the central place for bootstrapping application and module components.
AppServiceProvider
Handles core application configuration:
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Force HTTPS in production/staging
if (in_array(config('app.env'), ['production', 'staging'])) {
URL::forceScheme('https');
$this->enableHttpsSecurityHeaders();
}
// Fix module event discovery
Event::clearResolvedInstance(DiscoverEvents::class);
}
protected function enableHttpsSecurityHeaders(): void
{
Response::macro('withSecurityHeaders', function () {
return $this
->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
->header('Content-Security-Policy', "upgrade-insecure-requests")
->header('X-Content-Type-Options', 'nosniff');
});
}
}
MacroServiceProvider
Centralized macro management:
class MacroServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->registerInertiaMacros();
}
protected function registerInertiaMacros(): void
{
// Enable SSR for specific response
InertiaResponse::macro('withSSR', function () {
Config::set('inertia.ssr.enabled', true);
return $this;
});
// Disable SSR for specific response
InertiaResponse::macro('withoutSSR', function () {
Config::set('inertia.ssr.enabled', false);
return $this;
});
}
}
ModuleServiceProvider (Abstract)
Base class for module service providers:
abstract class ModuleServiceProvider extends ServiceProvider
{
protected string $name;
protected string $nameLower;
protected array $commands = [];
protected array $providers = [];
public function boot(): void
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->name, 'database/migrations'));
// Share module data with Inertia
Inertia::share([
"{$this->nameLower}.config" => fn() => config($this->nameLower),
]);
}
public function register(): void
{
$this->registerProviders();
$this->registerCommands();
}
}
Module Provider Example
Every module extends ModuleServiceProvider, which handles translations, config, migrations, and Inertia data sharing automatically:
// modules/Auth/app/Providers/AuthServiceProvider.php
class AuthServiceProvider extends ModuleServiceProvider
{
protected string $name = 'Auth';
protected string $nameLower = 'auth';
protected array $commands = [
Commands\SetupOAuthCommand::class,
];
protected array $providers = [
RouteServiceProvider::class,
];
// Optional: Override boot for module-specific setup
public function boot(): void
{
parent::boot(); // Always call parent
// Add module-specific boot logic
$this->registerEventListeners();
$this->configureThirdPartyServices();
}
}
When a module is enabled, its service provider automatically registers routes, migrations, translations, config, commands, and nested providers.
HandleInertiaRequests Middleware
The key middleware that connects Laravel to Vue — it disables SSR by default and shares global data with all Inertia pages:
class HandleInertiaRequests extends Middleware
{
public function handle(Request $request, Closure $next): Response
{
// Disable SSR by default (opt-in per route)
Config::set('inertia.ssr.enabled', false);
return parent::handle($request, $next);
}
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'locale' => app()->getLocale(),
'modules' => fn () => collect(Module::allEnabled())
->mapWithKeys(fn ($module, $key) => [$key => $module->getName()])
->all(),
'navigation' => fn () => app(Navigation::class)->treeGrouped(),
'breadcrumbs' => $this->getBreadcrumbs(),
'toast' => fn () => $request->session()->pull('toast'),
'ziggy' => fn () => [
...(new Ziggy)->toArray(),
'location' => $request->url(),
],
]);
}
}
This shared data is available in every Vue component via usePage().props.
Next Steps
- Frontend Architecture - How the Vue frontend consumes this data
- Modules Guide - Working with modules in practice
- SSR Guide - How the SSR opt-in system works