# Libra - Coding Standards > Extracted from `docs/architecture.md` Section 20 ## Critical Rules | Rule | Description | |------|-------------| | **Volt Pattern** | Use class-based Volt components (per CLAUDE.md) | | **Flux UI** | Use Flux components when available | | **Form Validation** | Always use Form Request or Livewire form objects | | **Eloquent** | Prefer `Model::query()` over `DB::` facade | | **Actions** | Use single-purpose Action classes for business logic | | **Testing** | Every feature must have corresponding Pest tests | | **Pint** | Run `vendor/bin/pint --dirty` before committing | ## Naming Conventions | Element | Convention | Example | |---------|------------|---------| | Models | Singular PascalCase | `Consultation` | | Tables | Plural snake_case | `consultations` | | Columns | snake_case | `booking_date` | | Controllers | PascalCase + Controller | `ConsultationController` | | Actions | Verb + Noun + Action | `CreateConsultationAction` | | Jobs | Verb + Noun | `SendBookingNotification` | | Events | Past tense | `ConsultationApproved` | | Listeners | Verb phrase | `SendApprovalNotification` | | Volt Components | kebab-case path | `admin/consultations/index` | | Enums | PascalCase | `ConsultationStatus` | | Enum Cases | PascalCase | `NoShow` | | Traits | Adjective or -able | `HasConsultations`, `Bookable` | | Interfaces | Adjective or -able | `Exportable` | ## Volt Component Template ```php resetPage(); } public function updatedStatus(): void { $this->resetPage(); } public function with(): array { return [ 'consultations' => Consultation::query() ->with('user:id,full_name,email') ->when($this->search, fn ($q) => $q->whereHas('user', fn ($q) => $q->where('full_name', 'like', "%{$this->search}%") )) ->when($this->status, fn ($q) => $q->where('status', $this->status)) ->orderBy('booking_date', 'desc') ->paginate(15), 'statuses' => ConsultationStatus::cases(), ]; } }; ?>
{{ __('models.consultations') }}
@foreach($statuses as $s) @endforeach
@forelse($consultations as $consultation) {{-- Card content --}} @empty @endforelse
{{ $consultations->links() }}
``` ## Action Class Template ```php hasBookingOnDate($data['booking_date'])) { throw new BookingLimitExceededException( __('messages.booking_limit_exceeded') ); } return DB::transaction(function () use ($user, $data) { $consultation = Consultation::create([ 'user_id' => $user->id, 'booking_date' => $data['booking_date'], 'booking_time' => $data['booking_time'], 'problem_summary' => $data['problem_summary'], 'status' => ConsultationStatus::Pending, 'payment_status' => PaymentStatus::NotApplicable, ]); SendBookingNotification::dispatch($consultation); return $consultation; }); } } ``` ## Testing Standards - Use **Pest 4** with `Volt::test()` for Livewire components - Every feature must have corresponding tests - Use factories with custom states when creating test models - Follow existing test structure in `tests/Feature/` and `tests/Unit/` ### Test Example ```php use Livewire\Volt\Volt; test('consultation list can be filtered by status', function () { $user = User::factory()->admin()->create(); Volt::test('admin.consultations.index') ->actingAs($user) ->set('status', ConsultationStatus::Pending->value) ->assertHasNoErrors(); }); ``` ## Bilingual Support - All user-facing strings must use Laravel's `__()` helper - Translations stored in `resources/lang/{ar,en}/` - Use JSON translations for simple strings, PHP arrays for structured data - RTL layout handled via Tailwind CSS classes