# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Development (runs server, queue, logs, and vite concurrently)
composer dev

# Initial setup
composer setup

# Run tests
composer test

# Run single test
php artisan test --filter=TestClassName
php artisan test tests/Feature/ExampleTest.php

# Code formatting
./vendor/bin/pint

# Database
php artisan migrate
php artisan migrate:fresh --seed

# Generate OpenAPI spec (L5-Swagger)
php artisan l5-swagger:generate
```

## Architecture

This is a **Laravel 13 + Filament 5.5** backoffice application for document processing with a REST API.

### Filament Resources Structure

Resources follow a modular structure under `app/Filament/Resources/{ResourceName}/`:
- `{Name}Resource.php` - Main resource class with `form()` and `table()` delegating to separate classes
- `Schemas/{Name}Form.php` - Form schema configuration
- `Schemas/{Name}Infolist.php` - View page schema (for resources with view pages)
- `Tables/{Name}Table.php` - Table configuration using `->recordActions()` for row actions
- `Pages/` - List, Create, Edit, View pages

### Custom Filament Pages with Tables

Custom pages with tables (e.g., Inbox) must implement `HasForms` and `HasTable` interfaces:

```php
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;

class CustomPage extends Page implements HasForms, HasTable
{
    use InteractsWithForms;
    use InteractsWithTable;

    public function table(Table $table): Table
    {
        return $table
            ->records(fn () => collect([...])) // Closure returning Collection with 'key' field
            ->columns([...])
            ->recordActions([...]); // Use Filament\Actions\Action
    }
}
```

**Important for non-Eloquent tables:**
- `->records()` requires a **Closure** returning a Collection, not an array
- Each record must have a `'key'` field for identification
- Use `Filament\Actions\Action` for record actions (not `Filament\Tables\Actions\Action`)
- Render with `{{ $this->table }}` in Blade view

### Key Models

- **User** - Has `role` enum (Admin/Manager) via `App\Enums\UserRole`. Uses `#[Fillable]` and `#[Hidden]` PHP attributes. Check role with `$user->isAdmin()` or `$user->isManager()`
- **History** - Document processing records with `input_files`/`output_files` arrays (cast), `sent_to_ftp` boolean, and page count statistics

### Role-Based Access

Authorization is handled in Resource classes via `canCreate()`, `canEdit()`, `canDelete()` methods checking `auth()->user()->isAdmin()`.

### File Storage

PDF files stored using Laravel's local disk:
- Inbox: `storage/app/inbox/`
- History input files: `storage/app/history/input/`
- History output files: `storage/app/history/output/`

### Panel Configuration

Single admin panel at `/admin` configured in `app/Providers/Filament/AdminPanelProvider.php`. Resources and pages are auto-discovered from `app/Filament/`.

### Filament Icons

Use `Filament\Support\Icons\Heroicon` enum for navigation icons:
```php
protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedClock;
```

### REST API

API endpoints at `/api` using Laravel Sanctum authentication:
- `app/Http/Controllers/Api/` - AuthController, UserController, HistoryController
- `app/Http/Resources/` - UserResource, HistoryResource
- Protected routes require `Authorization: Bearer {token}` header
- Admin-only actions check `$request->user()->isAdmin()`

### API Documentation

OpenAPI/Swagger documentation via L5-Swagger:
- UI: `/api/documentation`
- JSON spec: `storage/api-docs/api-docs.json`
- Config: `config/l5-swagger.php`
- Uses `@OA\` annotations (OpenAPI 3.0) in controllers and resource classes
- BearerAuth security scheme configured for Sanctum tokens
- Generate spec: `php artisan l5-swagger:generate`
- Set `L5_SWAGGER_GENERATE_ALWAYS=true` in `.env` for auto-regeneration in development

### Multi-language Support

Native Laravel i18n with EN/ES:
- Middleware: `app/Http/Middleware/SetLocale.php` (registered in `AdminPanelProvider`)
- Translations: `lang/en/`, `lang/es/`, `lang/es.json`
- Language switcher in admin panel header via render hook
- Use `__('key')` for translatable strings in PHP and `{{ __('key') }}` in Blade
- Route `/locale/{locale}` switches language via session

### Inline Styles in Blade

Filament views may not compile custom Tailwind classes. Use inline styles for custom HTML components in Blade views.
