2026-01-28 14:15:33 +00:00
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
2026-01-26 20:39:56 +00:00
## Architecture
2026-01-28 14:15:33 +00:00
Modular monolith using Core PHP Framework (Laravel 12). Modules live in `app/Mod/{Name}/Boot.php` and register via events.
2026-01-26 20:39:56 +00:00
2026-03-13 13:38:03 +00:00
**Bootstrap chain:** `bootstrap/app.php` loads four Core providers in order:
1. `Core\LifecycleEventProvider` — fires lifecycle events that modules listen to
2. `Core\Website\Boot` — website layer
3. `Core\Front\Boot` — frontend/middleware layer
4. `Core\Mod\Boot` — discovers and registers all modules from paths in `config/core.php`
2026-01-26 20:39:56 +00:00
**Event-driven registration:**
```php
class Boot
{
public static array $listens = [
WebRoutesRegistering::class => 'onWebRoutes',
ApiRoutesRegistering::class => 'onApiRoutes',
AdminPanelBooting::class => 'onAdminPanel',
];
2026-01-28 14:15:33 +00:00
public function onWebRoutes(WebRoutesRegistering $event): void
{
$event->routes(fn() => require __DIR__ .'/Routes/web.php');
$event->views('blog', __DIR__ .'/Views');
}
2026-01-26 20:39:56 +00:00
}
```
2026-03-13 13:38:03 +00:00
**Module paths (three layers):**
- `app/Core/` — framework-level overrides (EUPL-1.2 copyleft)
- `app/Mod/` — feature modules (your licence)
- `app/Website/` — website-specific features (your licence)
**Routing:** The top-level `routes/web.php` and `routes/api.php` are boilerplate stubs. All real routes are registered by modules via `Boot.php` event listeners.
2026-01-28 14:15:33 +00:00
2026-01-26 20:39:56 +00:00
## Commands
```bash
2026-01-28 14:15:33 +00:00
# Development
php artisan serve # Laravel dev server
npm run dev # Vite with HMR
composer dev:packages # Use local packages (composer.local.json)
# Module creation
php artisan make:mod Blog --all # Full module (web, api, admin)
php artisan make:mod Blog --web # Web routes only
php artisan make:mod Blog --api # API routes only
# Testing
2026-03-17 09:10:30 +00:00
composer test # Run all tests (Pest)
2026-01-28 14:15:33 +00:00
vendor/bin/pest tests/Feature # Run feature tests only
vendor/bin/pest --filter="test name" # Run single test by name
vendor/bin/pest path/to/TestFile.php # Run single test file
# Code quality
2026-03-17 09:10:30 +00:00
composer lint # Fix code style (Pint)
2026-01-28 14:15:33 +00:00
vendor/bin/pint --dirty # Format changed files only
2026-01-26 20:39:56 +00:00
```
## Module Structure
```
app/Mod/Blog/
2026-01-28 14:15:33 +00:00
├── Boot.php # Event listeners (required)
2026-01-26 20:39:56 +00:00
├── Models/ # Eloquent models
├── Routes/
│ ├── web.php # Web routes
│ └── api.php # API routes
2026-01-28 14:15:33 +00:00
├── Views/ # Blade templates (namespaced as 'blog::')
2026-01-26 20:39:56 +00:00
├── Livewire/ # Livewire components
2026-01-28 14:15:33 +00:00
├── Migrations/ # Auto-discovered migrations
2026-01-26 20:39:56 +00:00
└── Tests/ # Module tests
```
## Packages
2026-01-28 14:15:33 +00:00
| Package | Namespace | Purpose |
|---------|-----------|---------|
2026-03-13 13:38:03 +00:00
| `lthn/php` | `Core\` | Framework core, events, module discovery |
| `lthn/php-admin` | `Core\Admin\` | Admin panel, Livewire modals |
2026-03-17 09:10:30 +00:00
| `lthn/api` | `Core\Api\` | REST API, scopes, rate limiting, webhooks |
2026-03-13 13:38:03 +00:00
| `lthn/php-mcp` | `Core\Mcp\` | Model Context Protocol for AI agents |
## Testing
- Pest 3 (not PHPUnit syntax)
- `RefreshDatabase` is auto-applied to all Feature tests via `tests/Pest.php`
- Tests use in-memory SQLite (`phpunit.xml` )
- CI runs against PHP 8.2, 8.3, 8.4
2026-01-26 20:39:56 +00:00
## Conventions
2026-01-28 14:15:33 +00:00
**Language:** UK English (colour, organisation, centre, behaviour, licence/license)
**PHP:**
- `declare(strict_types=1);` in all files
- Full type hints on parameters and return types
2026-03-13 13:38:03 +00:00
- Final classes by default unless inheritance is intended
2026-01-28 14:15:33 +00:00
- PSR-12 formatting (Laravel Pint)
2026-03-13 13:38:03 +00:00
- Don't create controllers for Livewire pages
2026-01-28 14:15:33 +00:00
**Naming:**
- Models: Singular PascalCase (`Post` )
- Tables: Plural snake_case (`posts` )
- Livewire Pages: `{Feature}Page`
- Livewire Modals: `{Feature}Modal`
**UI Stack:**
- Livewire 3 for reactive components
- Flux Pro for UI components (not vanilla Alpine)
- Font Awesome Pro for icons (not Heroicons)
- Tailwind CSS for styling
2026-01-26 20:39:56 +00:00
2026-03-13 13:38:03 +00:00
**Indentation** (`.editorconfig` ): 4 spaces for PHP, 2 spaces for JS/TS/JSON/YAML.
## Known Limitations
- `tailwind.config.js` only scans `resources/` — module view paths (`app/Mod/*/Views/` ) are not yet included
## Licence
2026-01-26 20:39:56 +00:00
- `Core\` namespace and vendor packages: EUPL-1.2 (copyleft)
2026-01-28 14:15:33 +00:00
- `app/Mod/*` , `app/Website/*` : Your choice (no copyleft)