# Quickstart: Feature 002 - Filament JSON UI

**Feature**: 002-filament-json  
**Date**: 2025-12-13  
**Status**: Implementation Guide

---

## Installation

### 1. Install Package (T001) ✅ Complete

```bash
cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas
./vendor/bin/sail composer require pepperfm/filament-json:^4
```

**Result**: Package installed, assets published to `public/css/pepperfm/filament-json/`

---

## Usage Examples

### Basic Integration (MVP - Phase 3)

**Location**: `app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php`

#### Option A: Simple Pretty-Print JSON (Fastest MVP)

```php
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Components\Section;

protected function getSchema(): array
{
    return [
        Section::make('Policy Details')
            ->schema([
                TextEntry::make('name'),
                TextEntry::make('platform'),
                // ... other fields
            ]),
        
        Section::make('Policy Snapshot')
            ->schema([
                TextEntry::make('snapshot')
                    ->label('JSON Configuration')
                    ->formatStateUsing(fn ($state) => 
                        $state 
                            ? '<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96 overflow-y-auto">' 
                                . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) 
                                . '</pre>'
                            : 'No snapshot available'
                    )
                    ->html()
                    ->columnSpanFull()
                    ->copyable()
                    ->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT))
                    ->copyMessage('JSON copied to clipboard!')
                    ->helperText('Click the copy icon to copy the full JSON configuration.'),
            ])
            ->collapsible()
            ->collapsed(false),
    ];
}
```

**Features**:
- ✅ Pretty-printed JSON with monospace font
- ✅ Copy-to-clipboard via Filament's built-in copyable()
- ✅ Scrollable container (max height 24rem)
- ✅ Dark mode support
- ✅ Collapsible section
- ✅ Helper text for user guidance

---

### With Tabs (Phase 4 - Settings Catalog)

```php
use Filament\Infolists\Components\Tabs;
use Filament\Infolists\Components\Tabs\Tab;

protected function getSchema(): array
{
    return [
        Tabs::make('Policy Data')
            ->tabs([
                Tab::make('Settings')
                    ->visible(fn ($record) => $record->odatatype === 'settingsCatalogPolicy')
                    ->schema([
                        // Existing settings table component
                        ViewEntry::make('settings_table')
                            ->view('filament.infolists.entries.settings-table'),
                    ]),
                
                Tab::make('JSON')
                    ->schema([
                        TextEntry::make('snapshot')
                            ->label('Full Policy JSON')
                            ->formatStateUsing(fn ($state) => 
                                '<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96">' 
                                    . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT)) 
                                    . '</pre>'
                            )
                            ->html()
                            ->columnSpanFull()
                            ->copyable()
                            ->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT)),
                    ]),
            ]),
    ];
}
```

---

### Large Payload Warning (Phase 4 - T014)

```php
use Filament\Infolists\Components\TextEntry;
use Filament\Support\Colors\Color;

protected function getSchema(): array
{
    return [
        Section::make('Policy Snapshot')
            ->schema([
                // Warning badge for large payloads
                TextEntry::make('snapshot_size')
                    ->label('Payload Size')
                    ->state(fn ($record) => strlen(json_encode($record->snapshot ?? [])))
                    ->formatStateUsing(fn ($state) => 
                        $state > 512000 
                            ? '<span class="text-warning-600 dark:text-warning-400 font-semibold">⚠️ Large payload (' . number_format($state / 1024, 0) . ' KB) - May impact performance</span>'
                            : number_format($state / 1024, 1) . ' KB'
                    )
                    ->html()
                    ->visible(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 512000),
                
                TextEntry::make('snapshot')
                    ->label('JSON Configuration')
                    ->formatStateUsing(fn ($state) => 
                        '<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96">' 
                            . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT)) 
                            . '</pre>'
                    )
                    ->html()
                    ->columnSpanFull()
                    ->copyable(),
            ])
            ->collapsed(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 512000), // Auto-collapse if large
    ];
}
```

**Features**:
- ✅ Size detection: `strlen(json_encode($record->snapshot))` > 512,000 bytes (500 KB)
- ✅ Warning badge for large payloads
- ✅ Auto-collapse section if payload is large
- ✅ Formatted size display (KB)

---

## Configuration

### Payload Size Thresholds (NFR-036.1)

```php
// In PolicyResource ViewPolicy page
const INLINE_VIEWER_MAX_BYTES = 512000; // 500 KB soft limit

protected function isLargePayload($record): bool
{
    return strlen(json_encode($record->snapshot ?? [])) > self::INLINE_VIEWER_MAX_BYTES;
}
```

### Styling Consistency (NFR-036.5)

Match Filament section padding using Tailwind classes:

```php
'<pre class="
    text-xs           // Small font for readability
    font-mono         // Monospace for JSON
    overflow-x-auto   // Horizontal scroll
    bg-gray-50        // Light background
    dark:bg-gray-900  // Dark mode background
    p-4               // Padding (matches Filament sections)
    rounded-lg        // Rounded corners
    max-h-96          // Max height (24rem)
    overflow-y-auto   // Vertical scroll
">'
```

---

## Testing

### Manual QA Checklist

```bash
# 1. Open Policy View page
php artisan serve  # or ./vendor/bin/sail up

# Navigate to: /admin/policies/{id}
```

**Test Scenarios**:

1. **Small Policy (<500 KB)**:
   - ✅ JSON renders inline without scroll
   - ✅ Copy button copies full JSON
   - ✅ Section not collapsed by default

2. **Large Policy (>500 KB)**:
   - ✅ Warning badge shows
   - ✅ Section collapsed by default
   - ✅ Copy button still functional

3. **Settings Catalog Policy**:
   - ✅ "Settings" tab shows table
   - ✅ "JSON" tab shows full snapshot
   - ✅ Tab switching works without layout breaks

4. **Dark Mode**:
   - ✅ Switch to dark mode
   - ✅ JSON background is dark gray
   - ✅ Text is readable (light color)

### Feature Tests (Optional)

```bash
./vendor/bin/sail artisan test --filter=PolicyResourceViewTest
```

**Test Example**:

```php
// tests/Feature/Filament/PolicyResourceViewTest.php

it('displays JSON viewer on policy view page', function () {
    $policy = Policy::factory()->create([
        'snapshot' => ['test' => 'data'],
    ]);
    
    livewire(ViewPolicy::class, ['record' => $policy->id])
        ->assertSeeHtml('<pre')
        ->assertSeeHtml('font-mono')
        ->assertSee('JSON Configuration');
});

it('shows large payload warning for policies over 500 KB', function () {
    $largeSnapshot = array_fill(0, 10000, ['key' => str_repeat('x', 100)]);
    $policy = Policy::factory()->create(['snapshot' => $largeSnapshot]);
    
    livewire(ViewPolicy::class, ['record' => $policy->id])
        ->assertSeeHtml('⚠️ Large payload')
        ->assertSeeHtml('KB');
});
```

### Browser Tests (Pest 4)

```php
// tests/Browser/PolicyJsonViewerTest.php

it('allows copying JSON to clipboard', function () {
    $policy = Policy::factory()->create();
    
    visit('/admin/policies/' . $policy->id)
        ->assertSee('JSON Configuration')
        ->click('[wire:click="copyJsonToClipboard"]')
        ->assertSee('JSON copied to clipboard!');
});
```

---

## Deployment Notes

### Assets

✅ **Assets committed to repository** (12 KB total):
- `public/css/pepperfm/filament-json/filament-json-styles.css`

**No build steps required** - assets are already published and ready.

### Staging Validation

```bash
# On Staging server (Dokploy deployment)
1. Deploy via git push
2. Run migrations (if any): php artisan migrate
3. Clear cache: php artisan config:clear && php artisan view:clear
4. Test: Open /admin/policies/{id} and verify JSON viewer renders
```

### Rollback Plan

If issues occur:

```bash
# Remove package
./vendor/bin/sail composer remove pepperfm/filament-json

# Revert ViewPolicy.php changes
git checkout HEAD -- app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php

# Clear cache
php artisan config:clear
```

---

## Performance Considerations

### Rendering 500 KB JSON

- **Inline rendering**: Browser handles JSON display natively (fast)
- **Copy action**: JavaScript clipboard API (async, non-blocking)
- **No server overhead**: JSON is already in `$record->snapshot`

### Large Payload Strategy

For payloads >1 MB:
- Auto-collapse section (requires manual expand)
- Optional: Add download action instead of copy

```php
use Filament\Infolists\Components\Actions\Action;

Actions\Action::make('downloadSnapshot')
    ->label('Download JSON')
    ->icon('heroicon-o-arrow-down-tray')
    ->action(function ($record) {
        return response()->streamDownload(function () use ($record) {
            echo json_encode($record->snapshot, JSON_PRETTY_PRINT);
        }, "policy-{$record->id}-snapshot.json");
    })
    ->visible(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 1048576), // >1 MB
```

---

## Next Steps

1. ✅ Phase 1 complete: Package installed, assets documented
2. ✅ Phase 2 complete: Research findings documented
3. **Phase 3**: Implement User Story 1 (T007-T012) - Basic JSON viewer
4. **Phase 4**: Implement User Story 2 (T013-T015) - Tabs for Settings Catalog
5. **Phase 5**: Implement User Story 3 (T016-T018) - Copy/download actions

**Estimated time remaining**: 3-4 hours for Phases 3-8

---

## Troubleshooting

### Issue: JSON not rendering

**Solution**: Verify `$record->snapshot` is not null:
```php
->formatStateUsing(fn ($state) => $state ? /* render JSON */ : 'No snapshot available')
```

### Issue: Copy button not working

**Solution**: Ensure `->copyable()` and `->copyableState()` are both set:
```php
->copyable()
->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT))
```

### Issue: Horizontal overflow

**Solution**: Add `overflow-x-auto` class to `<pre>` tag:
```php
'<pre class="overflow-x-auto">'
```

---

**Status**: ✅ Phase 2 Complete - Ready for Phase 3 implementation
