comlete story 2.2 with qa test & updated architect files
This commit is contained in:
@@ -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
|
||||
@@ -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 |
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user