comlete story 2.2 with qa test & updated architect files

This commit is contained in:
Naser Mansour
2025-12-26 15:43:06 +02:00
parent 0ec089bbb1
commit b9009ca1df
13 changed files with 2281 additions and 57 deletions
+186
View File
@@ -0,0 +1,186 @@
# 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
<?php
// resources/views/livewire/admin/consultations/index.blade.php
use App\Models\Consultation;
use App\Enums\ConsultationStatus;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new class extends Component {
use WithPagination;
public string $search = '';
public string $status = '';
public function updatedSearch(): void
{
$this->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(),
];
}
}; ?>
<div>
<x-slot name="header">
<flux:heading size="xl">{{ __('models.consultations') }}</flux:heading>
</x-slot>
<div class="flex gap-4 mb-6">
<flux:input
wire:model.live.debounce.300ms="search"
placeholder="{{ __('messages.search') }}"
icon="magnifying-glass"
/>
<flux:select wire:model.live="status">
<option value="">{{ __('messages.all_statuses') }}</option>
@foreach($statuses as $s)
<option value="{{ $s->value }}">{{ $s->label() }}</option>
@endforeach
</flux:select>
</div>
<div class="space-y-4">
@forelse($consultations as $consultation)
<x-ui.card wire:key="consultation-{{ $consultation->id }}">
{{-- Card content --}}
</x-ui.card>
@empty
<x-ui.empty-state :message="__('messages.no_consultations')" />
@endforelse
</div>
<div class="mt-6">
{{ $consultations->links() }}
</div>
</div>
```
## Action Class Template
```php
<?php
// app/Actions/Consultation/CreateConsultationAction.php
namespace App\Actions\Consultation;
use App\Models\Consultation;
use App\Models\User;
use App\Enums\ConsultationStatus;
use App\Enums\PaymentStatus;
use App\Jobs\SendBookingNotification;
use App\Exceptions\BookingLimitExceededException;
use Illuminate\Support\Facades\DB;
class CreateConsultationAction
{
public function execute(User $user, array $data): Consultation
{
// Validate booking limit
if ($user->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
+265
View File
@@ -0,0 +1,265 @@
# Libra - Source Tree & Directory Structure
> Extracted from `docs/architecture.md` Section 6
## Project Structure
```
libra/
├── app/
│ ├── Actions/ # Business logic (single-purpose)
│ │ ├── Fortify/ # Auth actions (existing)
│ │ │ ├── CreateNewUser.php
│ │ │ ├── ResetUserPassword.php
│ │ │ └── UpdateUserPassword.php
│ │ ├── Consultation/
│ │ │ ├── CreateConsultationAction.php
│ │ │ ├── ApproveConsultationAction.php
│ │ │ ├── RejectConsultationAction.php
│ │ │ ├── CompleteConsultationAction.php
│ │ │ └── CancelConsultationAction.php
│ │ ├── Timeline/
│ │ │ ├── CreateTimelineAction.php
│ │ │ ├── AddTimelineUpdateAction.php
│ │ │ └── ArchiveTimelineAction.php
│ │ ├── User/
│ │ │ ├── CreateClientAction.php
│ │ │ ├── UpdateClientAction.php
│ │ │ ├── DeactivateClientAction.php
│ │ │ ├── ReactivateClientAction.php
│ │ │ ├── DeleteClientAction.php
│ │ │ └── ConvertClientTypeAction.php
│ │ ├── Post/
│ │ │ ├── CreatePostAction.php
│ │ │ ├── UpdatePostAction.php
│ │ │ ├── PublishPostAction.php
│ │ │ └── DeletePostAction.php
│ │ └── Export/
│ │ ├── ExportUsersAction.php
│ │ ├── ExportConsultationsAction.php
│ │ └── GenerateMonthlyReportAction.php
│ ├── Enums/ # PHP 8.1+ enums
│ │ ├── UserType.php
│ │ ├── UserStatus.php
│ │ ├── ConsultationType.php
│ │ ├── ConsultationStatus.php
│ │ ├── PaymentStatus.php
│ │ ├── TimelineStatus.php
│ │ └── PostStatus.php
│ ├── Http/
│ │ ├── Controllers/ # Minimal controllers
│ │ │ ├── LanguageController.php
│ │ │ └── CalendarDownloadController.php
│ │ └── Middleware/
│ │ ├── SetLocale.php
│ │ ├── EnsureUserIsAdmin.php
│ │ └── EnsureUserIsActive.php
│ ├── Jobs/ # Queue jobs
│ │ ├── SendWelcomeEmail.php
│ │ ├── SendBookingNotification.php
│ │ ├── SendConsultationReminder.php
│ │ ├── SendTimelineUpdateNotification.php
│ │ └── GenerateExportFile.php
│ ├── Livewire/ # Full-page Livewire components (if any)
│ │ └── Forms/ # Livewire form objects
│ │ ├── ConsultationForm.php
│ │ ├── ClientForm.php
│ │ ├── TimelineForm.php
│ │ └── PostForm.php
│ ├── Mail/ # Mailable classes
│ │ ├── WelcomeMail.php
│ │ ├── BookingSubmittedMail.php
│ │ ├── BookingApprovedMail.php
│ │ ├── BookingRejectedMail.php
│ │ ├── ConsultationReminderMail.php
│ │ ├── TimelineUpdatedMail.php
│ │ └── NewBookingRequestMail.php
│ ├── Models/ # Eloquent models
│ │ ├── User.php
│ │ ├── Consultation.php
│ │ ├── Timeline.php
│ │ ├── TimelineUpdate.php
│ │ ├── Post.php
│ │ ├── WorkingHour.php
│ │ ├── BlockedTime.php
│ │ ├── Notification.php
│ │ ├── AdminLog.php
│ │ └── Setting.php
│ ├── Observers/ # Model observers
│ │ ├── ConsultationObserver.php
│ │ ├── TimelineUpdateObserver.php
│ │ └── UserObserver.php
│ ├── Policies/ # Authorization policies
│ │ ├── ConsultationPolicy.php
│ │ ├── TimelinePolicy.php
│ │ ├── PostPolicy.php
│ │ └── UserPolicy.php
│ ├── Providers/
│ │ ├── AppServiceProvider.php
│ │ └── FortifyServiceProvider.php
│ └── Services/ # Cross-cutting services
│ ├── AvailabilityService.php
│ ├── CalendarService.php
│ └── ExportService.php
├── config/
│ └── libra.php # App-specific config
├── database/
│ ├── factories/
│ │ ├── UserFactory.php
│ │ ├── ConsultationFactory.php
│ │ ├── TimelineFactory.php
│ │ ├── TimelineUpdateFactory.php
│ │ └── PostFactory.php
│ ├── migrations/
│ └── seeders/
│ ├── DatabaseSeeder.php
│ ├── AdminSeeder.php
│ ├── WorkingHoursSeeder.php
│ └── DemoDataSeeder.php
├── docs/
│ ├── architecture.md # Main architecture document
│ ├── architecture/ # Sharded architecture docs
│ │ ├── tech-stack.md
│ │ ├── source-tree.md
│ │ └── coding-standards.md
│ ├── prd.md # Product requirements
│ ├── epics/ # Epic definitions
│ └── stories/ # User stories
├── resources/
│ ├── views/
│ │ ├── components/ # Blade components
│ │ │ ├── layouts/
│ │ │ │ ├── app.blade.php # Main app layout
│ │ │ │ ├── guest.blade.php # Guest/public layout
│ │ │ │ └── admin.blade.php # Admin layout
│ │ │ └── ui/ # Reusable UI components
│ │ │ ├── card.blade.php
│ │ │ ├── stat-card.blade.php
│ │ │ ├── status-badge.blade.php
│ │ │ └── language-switcher.blade.php
│ │ ├── emails/ # Email templates
│ │ │ ├── welcome.blade.php
│ │ │ ├── booking-submitted.blade.php
│ │ │ ├── booking-approved.blade.php
│ │ │ ├── booking-rejected.blade.php
│ │ │ ├── consultation-reminder.blade.php
│ │ │ ├── timeline-updated.blade.php
│ │ │ └── new-booking-request.blade.php
│ │ ├── livewire/ # Volt single-file components
│ │ │ ├── admin/ # Admin area
│ │ │ │ ├── dashboard.blade.php
│ │ │ │ ├── users/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ ├── create.blade.php
│ │ │ │ │ └── edit.blade.php
│ │ │ │ ├── consultations/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ ├── pending.blade.php
│ │ │ │ │ ├── calendar.blade.php
│ │ │ │ │ └── show.blade.php
│ │ │ │ ├── timelines/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ ├── create.blade.php
│ │ │ │ │ └── show.blade.php
│ │ │ │ ├── posts/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ ├── create.blade.php
│ │ │ │ │ └── edit.blade.php
│ │ │ │ ├── settings/
│ │ │ │ │ ├── working-hours.blade.php
│ │ │ │ │ ├── blocked-times.blade.php
│ │ │ │ │ └── content-pages.blade.php
│ │ │ │ └── reports/
│ │ │ │ └── index.blade.php
│ │ │ ├── client/ # Client area
│ │ │ │ ├── dashboard.blade.php
│ │ │ │ ├── consultations/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ └── book.blade.php
│ │ │ │ ├── timelines/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ └── show.blade.php
│ │ │ │ └── profile.blade.php
│ │ │ ├── pages/ # Public pages
│ │ │ │ ├── home.blade.php
│ │ │ │ ├── posts/
│ │ │ │ │ ├── index.blade.php
│ │ │ │ │ └── show.blade.php
│ │ │ │ ├── terms.blade.php
│ │ │ │ └── privacy.blade.php
│ │ │ ├── auth/ # Auth pages (existing)
│ │ │ └── settings/ # User settings (existing)
│ │ ├── pdf/ # PDF templates
│ │ │ ├── users-export.blade.php
│ │ │ ├── consultations-export.blade.php
│ │ │ └── monthly-report.blade.php
│ │ └── errors/ # Error pages
│ │ ├── 404.blade.php
│ │ ├── 403.blade.php
│ │ └── 500.blade.php
│ ├── css/
│ │ └── app.css # Tailwind entry point
│ ├── js/
│ │ └── app.js # Minimal JS
│ └── lang/ # Translations
│ ├── ar/
│ │ ├── auth.php
│ │ ├── validation.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ ├── messages.php
│ │ ├── models.php
│ │ ├── enums.php
│ │ └── emails.php
│ └── en/
│ └── ... (same structure)
├── routes/
│ ├── web.php # Web routes
│ └── console.php # Scheduled commands
├── tests/
│ ├── Feature/
│ │ ├── Admin/
│ │ │ ├── DashboardTest.php
│ │ │ ├── UserManagementTest.php
│ │ │ ├── ConsultationManagementTest.php
│ │ │ ├── TimelineManagementTest.php
│ │ │ ├── PostManagementTest.php
│ │ │ └── SettingsTest.php
│ │ ├── Client/
│ │ │ ├── DashboardTest.php
│ │ │ ├── BookingTest.php
│ │ │ ├── TimelineViewTest.php
│ │ │ └── ProfileTest.php
│ │ ├── Public/
│ │ │ ├── HomePageTest.php
│ │ │ ├── PostsTest.php
│ │ │ └── LanguageSwitchTest.php
│ │ └── Auth/
│ │ └── ... (existing tests)
│ └── Unit/
│ ├── Actions/
│ ├── Models/
│ ├── Services/
│ └── Enums/
├── storage/
│ └── app/
│ └── exports/ # Generated export files
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI
└── public/
└── build/ # Compiled assets
```
## Key Modules & Their Purpose
| Module | Location | Purpose |
|--------|----------|---------|
| **User Management** | `app/Actions/User/` | CRUD for clients (individual/company) |
| **Consultation Booking** | `app/Actions/Consultation/` | Booking lifecycle management |
| **Timeline/Case Tracking** | `app/Actions/Timeline/` | Case progress tracking |
| **Posts/Blog** | `app/Actions/Post/` | Legal content publishing |
| **Export Generation** | `app/Actions/Export/` | PDF/CSV report generation |
| **Authentication** | `app/Actions/Fortify/` | Fortify auth customization |
| **Email Notifications** | `app/Mail/`, `app/Jobs/` | Queued email delivery |
| **Authorization** | `app/Policies/` | Access control policies |
+52
View File
@@ -0,0 +1,52 @@
# Libra - Technology Stack
> Extracted from `docs/architecture.md` Section 3
## Core Technologies
| Category | Technology | Version | Purpose | Rationale |
|----------|------------|---------|---------|-----------|
| **Runtime** | PHP | 8.4.x | Server-side language | Latest stable; required by Laravel 12 |
| **Framework** | Laravel | 12.x | Application framework | Industry standard; excellent ecosystem |
| **Reactive UI** | Livewire | 3.7.x | Interactive components | No JS build complexity; server-state |
| **Components** | Volt | 1.10.x | Single-file components | Cleaner organization; class-based |
| **UI Library** | Flux UI Free | 2.10.x | Pre-built components | Consistent design; accessibility |
| **CSS** | Tailwind CSS | 4.x | Utility-first styling | Rapid development; RTL support |
| **Auth** | Laravel Fortify | 1.33.x | Headless auth | Flexible; 2FA support |
| **Database (Prod)** | MariaDB | 10.11+ | Production database | MySQL-compatible; performant |
| **Database (Dev)** | SQLite | Latest | Development database | Zero config; fast tests |
| **Testing** | Pest | 4.x | Testing framework | Elegant syntax; Laravel integration |
| **Code Style** | Laravel Pint | 1.x | Code formatting | Consistent style |
| **Queue** | Database Driver | - | Job processing | Simple; no Redis dependency |
## Frontend Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| Alpine.js | (via Livewire) | Minimal JS interactivity |
| Vite | 6.x | Asset bundling |
| Google Fonts | - | Cairo (Arabic), Montserrat (English) |
| Heroicons | (via Flux) | Icon library |
## Backend Dependencies (To Add)
| Package | Version | Purpose |
|---------|---------|---------|
| `barryvdh/laravel-dompdf` | ^3.0 | PDF export generation |
| `league/csv` | ^9.0 | CSV export generation |
| `spatie/icalendar-generator` | ^2.0 | .ics calendar file generation |
## Development Dependencies
| Package | Purpose |
|---------|---------|
| Laravel Sail | Docker development environment (optional) |
| Laravel Telescope | Debug assistant (dev only) |
| Laravel Pint | Code formatting |
## Key Architectural Decisions
- **Livewire 3 + Volt** selected over React/Vue SPA for simplicity and Laravel native integration
- **MariaDB** for production (client preference), **SQLite** for development (fast tests)
- **Laravel Fortify** for flexible headless auth with 2FA support
- **Database queue driver** sufficient for expected volume (~100 jobs/day)