# Homepage — Módulo Integrativo de Seções da Página Inicial

## Propósito

Gerencia a página inicial do portal como uma **implementação especializada do LandingSectionsEditor (LSE)**. Em vez de HTML estático ou templates fixos, a homepage é montada por **seções modulares** que podem ser configuradas individualmente via CMS, integrando dados de outros módulos (Notícias, Agenda, Parceiros) quando configurado.

## Arquitetura

```
LandingSectionsEditor (core)
  ├── 22 tipos genéricos (hero, cards-links, icons-text, …)
  └── WidgetRegistry (registro externo de widgets)

Módulo Homepage
  ├── 9 widgets SUCESU registrados no WidgetRegistry
  │     cada widget → Schema + FormView + RenderView própria
  ├── HomepageDataIntegrator
  │     injeta dados reais de News/Eventos/Parceiros nas seções
  └── Storage: v2_layout_base_configs (key: landing_sections)
```

### Widgets SUCESU

| Tipo | Schema | Form | Render | Ícone |
|------|--------|------|--------|-------|
| `sucesu-hero` | `SucesuHeroSchema` | `lse/forms/hero` | `lse/render/hero` | `bi-star-fill` |
| `sucesu-services` | `SucesuServicesSchema` | `lse/forms/services` | `lse/render/services` | `bi-grid-3x3-gap-fill` |
| `sucesu-about` | `SucesuAboutSchema` | `lse/forms/about` | `lse/render/about` | `bi-file-earmark-image` |
| `sucesu-brands` | `SucesuBrandsSchema` | `lse/forms/brands` | `lse/render/brands` | `bi-images` |
| `sucesu-events` | `SucesuEventsSchema` | `lse/forms/events` | `lse/render/events` | `bi-calendar3` |
| `sucesu-regionais` | `SucesuRegionaisSchema` | `lse/forms/regionais` | `lse/render/regionais` | `bi-geo-alt` |
| `sucesu-news` | `SucesuNewsSchema` | `lse/forms/news` | `lse/render/news` | `bi-newspaper` |
| `sucesu-associados` | `SucesuAssociadosSchema` | `lse/forms/associados` | `lse/render/associados` | `bi-building` |
| `sucesu-noticias` | `SucesuNoticiasSchema` | `lse/forms/noticias` | `lse/render/noticias` | `bi-newspaper` |
| `sucesu-agenda` | `SucesuAgendaSchema` | `lse/forms/agenda` | `lse/render/agenda` | `bi-calendar-event` |

Cada widget:
- **Schema**: define regras de validação dos parâmetros (Laravel validation rules)
- **Form View**: formulário no modal de edição (prefixo `parameters[...]` no formato LSE)
- **Render View**: template de exibição no portal (mantém o HTML/CSS original da SUCESU)
- **Widget Class**: implementa `getAttachmentIds()` e `prepare()` para resolver `image_id` → `file_path` via GalleryMedia

## Registro de Widgets

Os widgets são registrados automaticamente no boot do `ModuleProvider`:

```php
// V2/Modules/Layouts/Homepage/ModuleProvider.php
public function __construct()
{
    WidgetRegistry::register('sucesu-hero',       new SucesuHeroWidget());
    WidgetRegistry::register('sucesu-services',    new SucesuServicesWidget());
    WidgetRegistry::register('sucesu-about',       new SucesuAboutWidget());
    WidgetRegistry::register('sucesu-brands',      new SucesuBrandsWidget());
    WidgetRegistry::register('sucesu-events',      new SucesuEventsWidget());
    WidgetRegistry::register('sucesu-regionais',   new SucesuRegionaisWidget());
    WidgetRegistry::register('sucesu-news',        new SucesuNewsWidget());
    WidgetRegistry::register('sucesu-associados',  new SucesuAssociadosWidget());
    WidgetRegistry::register('sucesu-noticias',    new SucesuNoticiasWidget());
    WidgetRegistry::register('sucesu-agenda',      new SucesuAgendaWidget());
}
```

Isso faz com que **todos os tipos registrados** apareçam no dropdown "ADICIONAR SEÇÃO" do editor, agrupados visualmente na categoria **Personalizados** (separados dos 22 tipos padrão do LSE).

## Rotas

### CMS (administrativo)

| Método | URI | Nome | Ação |
|--------|-----|------|------|
| GET | `/cms/homepage` | `v2.homepage.sections` | `HomepageCmsController@sections` |
| POST | `/cms/homepage/save` | `v2.homepage.sections.save` | `HomepageCmsController@saveSections` |

Middleware: `web`, `CmsAuthenticate`, `module.active:Homepage`

### Portal (público)

| Método | URI | Nome | Ação |
|--------|-----|------|------|
| GET | `/` | `v2.portal.home` | `HomepagePortalController@index` |

Middleware: `web`, `MaintenanceMiddleware`

## Fluxo de Dados

### CMS (salvar seções)

1. Editor carrega seções de `LayoutBaseConfig` key `landing_sections`
2. Usuário edita via modal do LSE → JS atualiza hidden input `landing_sections_json`
3. Form POST para `/cms/homepage/save`
4. `HomepageCmsController@saveSections` → decodifica JSON → salva em `LayoutBaseConfig`
5. Log de auditoria via `ActivityLoggerService`

### Portal (renderizar)

1. `HomepagePortalController@index` carrega de `LayoutBaseConfig`
2. `HomepageDataIntegrator@integrate` → substitui dados estáticos por dinâmicos quando `source_type` está configurado
3. `LandingSectionsEditorRendererService@prepareSections` → cada widget resolve `image_id` → `file_path`
4. `landing-sections-viewer` renderiza cada seção via `WidgetRegistry::get($type)->getRenderView()`

## Widgets com Auto-Query (Padrão Associados/Notícias)

Alguns widgets **não dependem de dados inseridos manualmente no formulário LSE**. Em vez disso, fazem **query direta ao banco** no método `prepare()`, seguindo o padrão do widget `SucesuAssociadosWidget`:

| Widget | Model | Query | Filtros no form |
|--------|-------|-------|----------------|
| `sucesu-associados` | `AssociadoInstituicao` | `convenios()->active()->ordered()` | `visible_slugs[]` (checkboxes) |
| `sucesu-noticias` | `News` | `published()->recent()` | `categories[]` (checkboxes) + `limit` |
| `sucesu-agenda` | `Evento` | `published()->active()->upcoming()->upcomingOrdered()` | `event_limit` + `months_ahead` |

### Como funciona

1. O **formulário** (`lse/forms/noticias.blade.php`) permite apenas configurar filtros (categorias, limite)
2. O **widget** (`SucesuNoticiasWidget::prepare()`) executa a query no banco e prepara os dados estruturados
3. A **render view** (`lse/render/noticias.blade.php`) recebe os dados prontos e exibe

### Exemplo: `SucesuNoticiasWidget`

```php
public function prepare(array $parameters, Collection $anexos = null): array
{
    $query = News::published()->recent();

    if (!empty($parameters['categories'])) {
        $query->whereIn('category_id', $parameters['categories']);
    }

    $allNews = $query->take($limit + 1)->get();

    // Super-destaque: apenas se marcado como is_super_highlighted no módulo
    $superHighlighted = $allNews->first(function ($item) {
        return $item->is_super_highlighted;
    });

    $parameters['super_highlighted'] = $superHighlighted ? $this->prepareItem($superHighlighted) : null;
    $parameters['items'] = $items->map(function ($item) {
        return $this->prepareItem($item);
    })->toArray();

    return $parameters;
}
```

### Regras de negócio do super-destaque

- O banner de super-destaque **só aparece** se houver uma notícia com `is_super_highlighted = true`
- Não há fallback para a notícia mais recente
- O super-destaque é controlado exclusivamente pelo CMS do módulo Notícias (botão "Super-destaque" na listagem)

## Integrações com o Core V2

| Serviço | Uso no módulo |
|---------|--------------|
| `v2_can('Homepage', 'read/write')` | Permissão via middleware `CmsAuthenticate` + `V2PermissionMiddleware` (GET=read, POST=write) |
| `ActivityLoggerService` | Auditoria em `saveSections` |
| `GalleryService` / `GalleryMedia` | Resolução de `image_id` → `file_path` nos widgets (`getAttachmentIds` + `prepare`) |
| `v2-service-media::components.media-input` | Seletor de mídia nos formulários LSE dos widgets |
| `StorageService` / `Storage::url()` | Geração de URLs de imagens nas render views |
| `SEOService` | SEO no portal (`setTitle`, `setDescription`, `setKeywords`, `addSchema`) |
| `LayoutBaseConfig` | Persistência das seções em `v2_layout_base_configs` key `landing_sections` |

## Como Adicionar um Novo Widget SUCESU

1. **Schema**: Criar `LseWidgets/Schemas/NovoSchema.php` com método `rules()`
2. **Widget Class**: Criar `LseWidgets/Widgets/NovoWidget.php` estendendo `BaseWidget`, implementando `getAttachmentIds()` e `prepare()`
3. **Form View**: Criar `Views/lse/forms/novo.blade.php` com campos prefixados `parameters[...]`
4. **Render View**: Criar `Views/lse/render/novo.blade.php` com HTML de exibição
5. **Registrar**: Adicionar `WidgetRegistry::register('sucesu-novo', new NovoWidget())` no `ModuleProvider`

### Padrão: widget manual vs auto-query

- **Widget manual** (ex: `sucesu-news`, `sucesu-hero`): o usuário insere dados manualmente no formulário. O `prepare()` apenas resolve `image_id` → `file_path`.
- **Widget auto-query** (ex: `sucesu-associados`, `sucesu-noticias`): o formulário só tem filtros. O `prepare()` faz query ao banco e monta os dados automaticamente. O `getAttachmentIds()` retorna `[]`.

## Seed

O `SucesuHomepageSeeder` (em `V2/Seeds/BasicPages/`) popula a `v2_layout_base_configs` com 7 seções SUCESU iniciais com dados completos de apresentação.

```bash
docker compose exec app php artisan db:seed --class=V2\\Seeds\\BasicPages\\SucesuHomepageSeeder
```
