No description
Livewire and Alpine inject inline scripts/styles at runtime without nonce attributes. Nonce-based CSP breaks all Livewire apps out of the box. Change defaults: - nonce_enabled: false (opt-in via SECURITY_CSP_NONCE_ENABLED=true) - production env: add 'unsafe-inline' for script-src and style-src - Add host_analytics external source (SECURITY_CSP_HOST_ANALYTICS) Co-Authored-By: Virgil <virgil@lethean.io> |
||
|---|---|---|
| .claude/skills | ||
| .claude-plugin | ||
| .core | ||
| .forgejo/workflows | ||
| .github | ||
| bin | ||
| changelog/2026/jan | ||
| cmd/core-php | ||
| config | ||
| database/migrations | ||
| docker | ||
| docs | ||
| locales | ||
| src | ||
| stubs | ||
| tests | ||
| .gitattributes | ||
| .gitignore | ||
| bridge.go | ||
| CLAUDE.md | ||
| cmd.go | ||
| cmd_build.go | ||
| cmd_ci.go | ||
| cmd_commands.go | ||
| cmd_deploy.go | ||
| cmd_dev.go | ||
| cmd_packages.go | ||
| cmd_serve_frankenphp.go | ||
| composer.json | ||
| container.go | ||
| container_test.go | ||
| CONTRIBUTING.md | ||
| coolify.go | ||
| coolify_test.go | ||
| deploy.go | ||
| deploy_internal_test.go | ||
| deploy_test.go | ||
| detect.go | ||
| detect_test.go | ||
| dockerfile.go | ||
| dockerfile_test.go | ||
| env.go | ||
| extract.go | ||
| go.mod | ||
| go.sum | ||
| handler.go | ||
| i18n.go | ||
| infection.json5 | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| packages.go | ||
| packages_test.go | ||
| php-commands.yaml | ||
| php.go | ||
| php_test.go | ||
| phpstan.neon | ||
| phpunit.xml | ||
| psalm.xml | ||
| qa.yaml | ||
| quality.go | ||
| README.md | ||
| rector.php | ||
| ROADMAP.md | ||
| security-checks.yaml | ||
| SECURITY.md | ||
| services.go | ||
| services_extended_test.go | ||
| services_test.go | ||
| services_unix.go | ||
| services_windows.go | ||
| ssl.go | ||
| ssl_extended_test.go | ||
| ssl_test.go | ||
| testing.go | ||
| TODO.md | ||
| workspace.go | ||
Core PHP Framework
A modular monolith framework for Laravel with event-driven architecture, lazy module loading, and built-in multi-tenancy.
Documentation
📚 Read the full documentation →
Features
- Event-driven module system - Modules declare interest in lifecycle events and are only loaded when needed
- Lazy loading - Web requests don't load admin modules, API requests don't load web modules
- Multi-tenant isolation - Workspace-scoped data with automatic query filtering
- Actions pattern - Single-purpose business logic classes with dependency injection
- Activity logging - Built-in audit trails for model changes
- Seeder auto-discovery - Automatic ordering via priority and dependency attributes
- HLCRF Layout System - Hierarchical composable layouts (Header, Left, Content, Right, Footer)
Installation
composer require lthn/php
The service provider will be auto-discovered.
Quick Start
Creating a Module
php artisan make:mod Commerce
This creates a module at app/Mod/Commerce/ with a Boot.php entry point:
<?php
namespace Mod\Commerce;
use Core\Events\WebRoutesRegistering;
use Core\Events\AdminPanelBooting;
class Boot
{
public static array $listens = [
WebRoutesRegistering::class => 'onWebRoutes',
AdminPanelBooting::class => 'onAdmin',
];
public function onWebRoutes(WebRoutesRegistering $event): void
{
$event->views('commerce', __DIR__.'/Views');
$event->routes(fn () => require __DIR__.'/Routes/web.php');
}
public function onAdmin(AdminPanelBooting $event): void
{
$event->routes(fn () => require __DIR__.'/Routes/admin.php');
}
}
Lifecycle Events
| Event | Purpose |
|---|---|
WebRoutesRegistering |
Public-facing web routes |
AdminPanelBooting |
Admin panel routes and navigation |
ApiRoutesRegistering |
REST API endpoints |
ClientRoutesRegistering |
Authenticated client routes |
ConsoleBooting |
Artisan commands |
McpToolsRegistering |
MCP tool handlers |
FrameworkBooted |
Late-stage initialisation |
Core Patterns
Actions
Extract business logic into testable, reusable classes:
use Core\Actions\Action;
class CreateOrder
{
use Action;
public function handle(User $user, array $data): Order
{
// Business logic here
return Order::create($data);
}
}
// Usage
$order = CreateOrder::run($user, $validated);
Multi-Tenant Isolation
Automatic workspace scoping for models:
use Core\Mod\Tenant\Concerns\BelongsToWorkspace;
class Product extends Model
{
use BelongsToWorkspace;
}
// Queries are automatically scoped to the current workspace
$products = Product::all();
// workspace_id is auto-assigned on create
$product = Product::create(['name' => 'Widget']);
Activity Logging
Track model changes with minimal setup:
use Core\Activity\Concerns\LogsActivity;
class Order extends Model
{
use LogsActivity;
protected array $activityLogAttributes = ['status', 'total'];
}
HLCRF Layout System
Data-driven layouts with infinite nesting:
use Core\Front\Components\Layout;
$page = Layout::make('HCF')
->h('<nav>Navigation</nav>')
->c('<article>Main content</article>')
->f('<footer>Footer</footer>');
echo $page;
Variant strings define structure: HCF (Header-Content-Footer), HLCRF (all five regions), H[LC]CF (nested layouts).
See HLCRF.md for full documentation.
Configuration
Publish the config file:
php artisan vendor:publish --tag=core-config
Configure module paths in config/core.php:
return [
'module_paths' => [
app_path('Core'),
app_path('Mod'),
],
];
Artisan Commands
php artisan make:mod Commerce # Create a module
php artisan make:website Marketing # Create a website module
php artisan make:plug Stripe # Create a plugin
Module Structure
app/Mod/Commerce/
├── Boot.php # Module entry point
├── Actions/ # Business logic
├── Models/ # Eloquent models
├── Routes/
│ ├── web.php
│ ├── admin.php
│ └── api.php
├── Views/
├── Migrations/
└── config.php
Documentation
- Patterns Guide - Detailed documentation for all framework patterns
- HLCRF Layout System - Composable layout documentation
Testing
composer test
Requirements
- PHP 8.2+
- Laravel 11+
License
EUPL-1.2 - See LICENSE for details.