Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.
Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details
Co-Authored-By: Charon <charon@lethean.io>
|
||
|---|---|---|
| .. | ||
| Actions | ||
| Activity | ||
| Bouncer | ||
| Cdn | ||
| Config | ||
| Console | ||
| Crypt | ||
| Database/Seeders | ||
| Events | ||
| Front | ||
| Headers | ||
| Helpers | ||
| Input | ||
| Lang | ||
| Media | ||
| Rules | ||
| Search | ||
| Seo | ||
| Storage | ||
| Tests | ||
| Webhook | ||
| Boot.php | ||
| CLAUDE.md | ||
| config.php | ||
| Init.php | ||
| LazyModuleListener.php | ||
| LifecycleEventProvider.php | ||
| ModuleRegistry.php | ||
| ModuleScanner.php | ||
| Pro.php | ||
| README.md | ||
| RELEASE-BLOCKERS.md | ||
| TODO.md | ||
| views.md | ||
Core Architecture: The Core Module Protocol
================================================
- A highly opinionated, encapsulated module structure for Laravel.
- Designed to prevent monolithic spaghetti by enforcing strict boundaries.
Philosophy
- Everything is a Module: If it's a feature, it belongs in
app/Mod/. - One Boot File: No complex Provider naming. Every module has a
Boot.phpat its root. - Strict Encapsulation: Modules should be self-contained.
Directory Structure (Per Module)
app/Mod/{ModuleName}/
├── Boot.php # The single ServiceProvider entry point
├── Console/ # Artisan Commands
├── Controllers/ # HTTP Controllers (Web & API)
├── Database/ # Migrations, Factories, Seeders
├── Events/ # Events & Listeners
├── Jobs/ # Queueable Jobs
├── Mail/ # Mailables
├── Mcp/ # MCP Tools & Servers
├── Models/ # Eloquent Models (Namespace: Mod\{Mod}\Models)
├── Services/ # Business Logic (The "Brain")
├── Tests/ # Pest Tests (Feature & Unit)
└── View/ # The UI Layer (See views.md)
├── Modal/ # Livewire Components (ViewModels)
│ ├── Admin/ # Admin-facing ViewModels
│ └── Web/ # Public-facing ViewModels
├── Blade/ # Dumb Blade Templates
│ ├── admin/ # Admin templates
│ └── web/ # Public templates
├── Components/ # Reusable Blade Components
└── routes/ # Route definitions
Component Details
Boot.php
The entry point. Must extend Illuminate\Support\ServiceProvider.
It registers routes, views, migrations, and binds services.
Namespace: Mod\{Name}
Class: Boot
Models
All Eloquent models live here.
Namespace: Mod\{Name}\Models
Table Name: [module_snake_case]_[table_name] (e.g., agentic_plans).
View (Modern Flexy)
See views.md for the strict separation of Logic (Modal) and Layout (Blade).
Tests
Tests must exist within the module.
Run via: php artisan test app/Mod/{Name}/Tests
Best Practices
- Skinny Controllers: Controllers only delegate to Services or return View Modals.
- Explicit Boundaries: Do not query another module's database tables directly using raw SQL. Use Service contracts or Events if modules need to talk.
- Self-Contained: A module should be able to be extracted into a composer package with minimal effort.
Core Architecture: The Core View Protocol (Modern Flexy)
=========================================================
- A strict architectural guideline for implementing Server-Side MVVM in Laravel.
- Part of the Core PHP Framework.
Philosophy
- The Controller is a Traffic Cop: It accepts input, delegates to the Domain, and selects a View Modal. It never touches HTML or data formatting.
- The View Modal is the Interface: All presentation logic, formatting, state management, and data preparation happen here. This is the "ViewModel" (implemented as Livewire Components).
- The Template is Dumb: The template file (.blade.php) contains ONLY HTML and simple variable interpolation. No complex logic, no database calls, no calculations.
Directory Structure
Inside a Core Module (app/Mod/{Name}/):
View/
├── Modal/ # The View Modals (Livewire Components)
│ ├── Admin/ # (Namespace: Mod\{Mod}\View\Modal\Admin)
│ │ └── {Resource}Manager.php
│ ├── Web/ # (Namespace: Mod\{Mod}\View\Modal\Web)
│ │ └── {Resource}Page.php
│ └── {Resource}Page.php
└── Blade/ # The Dumb HTML Templates
├── admin/ # (View Namespace: {mod}::admin)
│ └── {resource}-manager.blade.php
└── web/ # (View Namespace: {mod}::web)
└── {resource}-page.blade.php
Implementation Guide
1. The Controller (Optional with Livewire)
Role: Accept request, fetch raw Domain Entity (if needed), return View Modal. Constraint: Must return an instance of a View Modal or render it via Livewire route binding.
// Example: InvoiceController.php
namespace Mod\Billing\Controllers\Web;
use Mod\Billing\View\Modal\InvoicePage;
class InvoiceController
{
public function show(int $id)
{
// Delegate directly to the View Modal
// Livewire handles the hydration
return new InvoicePage($id);
}
}
2. The View Modal (The "Flexy" Layer)
Role: Prepare data for display. Format currencies, dates, handle conditional UI logic, and manage state. Constraint: Public properties/methods correspond 1:1 with what the template needs.
// Example: InvoicePage.php
namespace Mod\Billing\View\Modal;
use Livewire\Component;
use Mod\Billing\Models\Invoice;
class InvoicePage extends Component
{
public Invoice $invoice;
public function mount(Invoice $invoice)
{
$this->invoice = $invoice;
}
// Logic lives HERE, not in the HTML.
public function getInvoiceIdProperty(): string
{
return '#' . str_pad($this->invoice->id, 6, '0', STR_PAD_LEFT);
}
public function getFormattedTotalProperty(): string
{
return number_format($this->invoice->total / 100, 2);
}
public function getIsOverdueProperty(): bool
{
return $this->invoice->due_date->isPast() && !$this->invoice->paid;
}
public function render()
{
// Points to the dumb template in the module
// Structure: app/Mod/Billing/View/Blade/invoice-page.blade.php
return view('billing::invoice-page');
}
}
3. The Template (The Dumb Layer)
Role: Layout and structure only.
Constraint: No method calls with arguments. No @php blocks. No complex @if conditions (use boolean getters from the View Modal instead).
<!-- invoice-page.blade.php -->
<div class="invoice-container">
<h1>Invoice {{ $this->invoiceId }}</h1>
<div class="status">
<!-- Logic is hidden behind the boolean getter -->
@if($this->isOverdue)
<span class="badge-danger">Overdue</span>
@else
<span class="badge-success">Active</span>
@endif
</div>
<div class="amount">
Total: ${{ $this->formattedTotal }}
</div>
</div>
Enforcement Rules
- No Logic in Blade: Regex check for logic operators (
&&,||,>) inside{{ }}tags in .blade.php files. - No Eloquent in Blade: The template should interact with the View Modal's getters/properties, not the raw Eloquent model relationships.
- Strict Typing: View Modals must strictly type their dependencies.