# Cycle 0: Critical Bug Fixes

## Priority: BLOCKING — System does not function correctly without these fixes

---

## Bug 1: Scheduled Command Name Mismatch

### Problem
`routes/console.php` schedules `attendance:mark-auto-absent` but the actual command class `MarkAutoAbsent.php` registers signature `attendance:mark-absent`. The hourly auto-absent marking never executes.

### File to Fix
`routes/console.php`

### Fix
Change:
```php
Schedule::command('attendance:mark-auto-absent')->hourly();
```
To:
```php
Schedule::command('attendance:mark-absent')->hourly();
```

### Verification
```bash
php artisan schedule:list | grep absent
# Should show: attendance:mark-absent .......... Every minute (hourly)
php artisan attendance:mark-absent --dry-run
```

---

## Bug 2: Auditable Trait Not Applied to Any Model

### Problem
The `Auditable` trait at `app/Domain/Shared/Traits/Auditable.php` is fully implemented but ZERO models use it. No audit trail is being created for any entity.

### Models That MUST Use Auditable

**Financial (is_financial = true):**
- `app/Domain/Financial/Models/Invoice.php`
- `app/Domain/Financial/Models/Payment.php`
- `app/Domain/Financial/Models/Transaction.php`
- `app/Domain/Financial/Models/Wallet.php`
- `app/Domain/Financial/Models/WalletTransaction.php`
- `app/Domain/Financial/Models/CashSession.php`
- `app/Domain/Financial/Models/PaymentPlan.php`
- `app/Domain/Financial/Models/Installment.php`

**Training:**
- `app/Domain/Training/Models/TrainingProgram.php`
- `app/Domain/Training/Models/TrainingGroup.php`
- `app/Domain/Training/Models/TrainingSession.php`
- `app/Domain/Training/Models/Enrollment.php`
- `app/Domain/Training/Models/Evaluation.php`

**People:**
- `app/Domain/Participant/Models/Participant.php`
- `app/Domain/Identity/Models/Person.php`
- `app/Domain/Identity/Models/Guardian.php`
- `app/Domain/Identity/Models/Role.php`
- `app/Models/User.php`

**Facility:**
- `app/Domain/Facility/Models/Facility.php`
- `app/Domain/Facility/Models/SpaceReservation.php`

**Inventory:**
- `app/Domain/Inventory/Models/Product.php`
- `app/Domain/Inventory/Models/PurchaseOrder.php`
- `app/Domain/Inventory/Models/Kit.php`
- `app/Domain/Inventory/Models/StockCount.php`

**Scheduling:**
- `app/Domain/Scheduling/Models/Assignment.php`

**Notifications:**
- `app/Domain/Notification/Models/NotificationTemplate.php`

**Settings:**
- `app/Domain/Shared/Models/SystemSetting.php`

### Fix Pattern (for each model)
```php
use App\Domain\Shared\Traits\Auditable;

class Invoice extends Model
{
    use BelongsToAcademy, HasUuid, SoftDeletes, Auditable;

    // For financial models, override:
    public function isFinancialAudit(): bool
    {
        return true;
    }
}
```

### Verification
```php
// In tinker:
$invoice = Invoice::first();
$invoice->update(['notes' => 'test audit']);
AuditLog::latest()->first(); // Should have action='updated', new_values=['notes' => 'test audit']
```

---

## Bug 3: Academy::branches() Wrong Namespace

### Problem
`app/Domain/Shared/Models/Academy.php` line 38:
```php
return $this->hasMany(\App\Domain\Shared\Models\Branch::class, 'academy_id');
```
But Branch lives at `App\Domain\Identity\Models\Branch`. This causes a runtime error when accessing `$academy->branches`.

### Fix
```php
use App\Domain\Identity\Models\Branch;

public function branches(): HasMany
{
    return $this->hasMany(Branch::class, 'academy_id');
}
```

### Verification
```php
// In tinker:
$academy = Academy::first();
$academy->branches->count(); // Should return number, not crash
```

---

## Bug 4: Events Missing ShouldDispatchAfterCommit

### Problem
Project rules require ALL domain events implement `ShouldDispatchAfterCommit`. Currently:
- `InvoiceCreated` — MISSING
- `InvoicePaid` — MISSING
- `PaymentReceived` — MISSING
- `POSTransactionCompleted` — HAS it (correct)

If events dispatch before commit and the transaction rolls back, listeners react to data that doesn't exist.

### Fix Pattern (apply to all 3 events)
```php
<?php

namespace App\Domain\Financial\Events;

use App\Domain\Financial\Models\Invoice;
use App\Models\User;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class InvoiceCreated implements ShouldDispatchAfterCommit
{
    use Dispatchable, SerializesModels;

    public function __construct(
        public Invoice $invoice,
        public User $actor,
    ) {}
}
```

### Services to Update (pass $actor)
- `InvoiceService::create()` — change `InvoiceCreated::dispatch($invoice)` → `InvoiceCreated::dispatch($invoice, $actor)`
- `PaymentService::recordPayment()` — same pattern
- All services that dispatch events must receive and pass the User actor

### Verification
```bash
php -l app/Domain/Financial/Events/InvoiceCreated.php
php -l app/Domain/Financial/Events/InvoicePaid.php
php -l app/Domain/Financial/Events/PaymentReceived.php
grep -r "ShouldDispatchAfterCommit" app/Domain --include="*.php" | wc -l
# Should be 4+ (one per event)
```

---

## Bug 5: Transaction Model Has updated_at (Immutability Violation)

### Problem
Rule 05 states: "No `updated_at` on transactions table — never soft-delete." The migration uses `$table->timestamps()` which creates both `created_at` AND `updated_at`. While the service never updates rows, the column's existence allows accidental mutation.

### Fix
Add to Transaction model:
```php
const UPDATED_AT = null;
```

This tells Eloquent to never write `updated_at` even though the column exists. Dropping the column would require a new migration and is lower priority.

---

## Completion Criteria

All 5 bugs fixed when:
1. `php artisan schedule:list` shows correct command names
2. Creating/updating any auditable model writes to `audit_logs`
3. `Academy::with('branches')->first()` returns without error
4. All event classes implement `ShouldDispatchAfterCommit`
5. All event constructors accept both entity and actor
6. Transaction model has `const UPDATED_AT = null`
