# REBUILD ROADMAP — Mangolê

> **Data:** 2026-07-21
> **Projecto:** Reconstrução completa do portal institucional Mangolê
> **Stack:** Laravel 13 + Filament 5.7 + Tailwind v4 + MySQL

---

## FASE 0 — Auditoria e Baseline ✅ (CONCLUÍDA)

### Objectivo
Conhecer o estado actual do projecto e da base de dados antes de qualquer modificação.

### Entregáveis
- [x] Auditoria da base de dados → `docs/DATABASE_CURRENT_STATE_AUDIT.md`
- [x] Baseline do projecto → `docs/PROJECT_BASELINE.md`
- [x] Roadmap → `docs/REBUILD_ROADMAP.md` (este ficheiro)
- [x] Backup da base de dados (pendente — executar antes da FASE 1)

### Decisões tomadas
- Rota `/` → `welcome.blade.php` (homepage única)
- Painel admin em `/admin` (Filament)
- Paleta de cores: azul (estrutural), amarelo (energia/CTA), vermelho (promocional), branco (fundo)
- Arquitectura: Controllers → Services → Models → Views

### Pendente
- [ ] Executar `mysqldump` completo da base `mangole` para `backups/mangole_pre_rebuild.sql`

---

## FASE 1 — Arquitectura de Dados

### Objectivo
Definir a arquitectura de dados final antes de criar Models ou migrations.

### Tarefas
- [ ] Mapear todas as tabelas existentes para Models Eloquent
- [ ] Decir quais tabelas merecem FK normalizada (ex: `products → product_families`)
- [ ] Decir se `provinces` e `municipalities` serão tabelas separadas
- [ ] Decir estratégia de soft delete (uniformizar para todas as tabelas CMS)
- [ ] Decir estratégia de sluggable (já implementado em várias tabelas)
- [ ] Decir estratégia de timestamps (created_at/updated_at em todas)
- [ ] Documentar todas as relações no diagrama final
- [ ] Decir se `store_messages` com store_id NULL é aceitável
- [ ] Criar documento `docs/DATA_ARCHITECTURE.md`

### Decisões a tomar
- FK products → product_families: SIM ou NÃO?
- Tabelas de geolocalização: SIM (provinces, municipalities) ou manter em stores?
- ENUM vs VARCHAR + validation: qual padrão adoptar?
- Soft delete em todas as tabelas ou apenas nas que já têm?

### Critério de conclusão
Documento de arquitectura de dados aprovado, sem migrations escritas ainda.

---

## FASE 2 — Models e Migrations

### Objectivo
Criar todos os Models Eloquent e migrations compatíveis com a base existente.

### Tarefas
- [ ] Backup da BD (`mysqldump`) antes de qualquer migration
- [ ] Criar migration de sincronização `0000_00_00_000000_sync_existing_schema.php`
  - Marca todas as 23 tabelas existentes como migradas
  - Prevenção de colisão com `php artisan migrate`
- [ ] Criar Models nesta ordem:
  - [ ] `User` (adicionar traits Filament: `Filament\Panel`, `CanResetPassword`)
  - [ ] `Setting`
  - [ ] `Store`
  - [ ] `ProductFamily`
  - [ ] `Product` (com FK product_family_id)
  - [ ] `StoreMessage`
  - [ ] `TeamMember`
  - [ ] `Campaign`
  - [ ] `CampaignAsset`
  - [ ] `CampaignCta`
  - [ ] `NewsArticle`
  - [ ] `Partner`
  - [ ] `Vacancy`
  - [ ] `SeoMetadata`
- [ ] Criar `ProductFamily` e `Product` Factories
- [ ] Criar `DatabaseSeeder` que usa os dados existentes como base

### Atenção
- NÃO executar `php artisan migrate` sem a migration de sincronização
- As novas migrations devem usar `Schema::hasTable()` para verificar existência

### Critério de conclusão
`php artisan migrate` executa sem erros. `php artisan tinker` consegue ler dados das tabelas existentes.

---

## FASE 3 — Filament CMS

### Objectivo
Criar os painéis de administração Filament para gestão de todo o conteúdo.

### Tarefas
- [ ] Reconfigurar cores do painel admin para azul Mangolê
- [ ] Criar Dashboard personalizada com métricas reais
- [ ] Criar Resources:
  - [ ] `StoreResource` (CRUD, geolocalização, mapas)
  - [ ] `ProductFamilyResource` (CRUD básico)
  - [ ] `ProductResource` (CRUD, preço, badge, imagem)
  - [ ] `TeamMemberResource` (CRUD, categorias board/leadership)
  - [ ] `SettingResource` (editor key-value agrupado)
  - [ ] `CampaignResource` (CRUD com Assets e CTAs aninhados)
  - [ ] `NewsArticleResource` (CRUD, sluggable, status draft/published)
  - [ ] `PartnerResource` (CRUD, logo, nível)
  - [ ] `VacancyResource` (CRUD, status, deadline)
  - [ ] `SeoMetadataResource` (CRUD por página)
  - [ ] `StoreMessageResource` (leitura, gestão de leads)
- [ ] Adicionar Widgets no dashboard:
  - Total de lojas, produtos, mensagens, notícias
  - Últimas mensagens de contacto

### Critério de conclusão
Filament a funcionar em `/admin` com login funcional e todos os Resources acessíveis.

---

## FASE 4 — Design System

### Objectivo
Criar o sistema de design Mangolê com Tailwind v4.

### Tarefas
- [ ] Configurar paleta de cores no `app.css`:
  - `--color-mw-blue: #0055a5`
  - `--color-mw-yellow: #ffcc00`
  - `--color-mw-red: #e30613`
  - `--color-mw-white: #ffffff`
- [ ] Definir tipografia (font-family principal)
- [ ] Criar componentes Blade base:
  - [ ] `x-mw-button` (primário, secundário, outline)
  - [ ] `x-mw-card`
  - [ ] `x-mw-badge` (promocional, destaque)
  - [ ] `x-mw-section-title`
  - [ ] `x-mw-grid`
- [ ] Criar `resources/css/mw.css` para estilos Mangolê (separado do Tailwind genérico)

### Critério de conclusão
Componentes de design system visíveis e testáveis isoladamente.

---

## FASE 5 — Layout Global

### Objectivo
Criar o layout base que envolve todas as páginas públicas.

### Tarefas
- [ ] Criar `resources/views/layouts/public.blade.php`
  - [ ] `<head>` com meta tags, Open Graph, favicon
  - [ ] Navbar (logo Mangolê, navegação principal)
  - [ ] Footer (contactos, redes sociais, links)
  - [ ] Scripts globais
- [ ] Criar componente `x-mw-navbar`
- [ ] Criar componente `x-mw-footer`
- [ ] Remover código antigo da `welcome.blade.php` (preparar para homepage)
- [ ] Aplicar layout nas rotas públicas

### Critério de conclusão
Layout global funcional em todas as páginas públicas.

---

## FASE 6 — Homepage (welcome.blade.php)

### Objectivo
Construir a homepage institucional da Mangolê.

### Tarefas
- [ ] Criar `App\Http\Controllers\HomepageController`
  - Método `__invoke()` que agrega dados via Services
- [ ] Criar `App\Services\HomepageService`
  - Buscar hero settings
  - Buscar stores em destaque
  - Buscar product_families para vitrine
  - Buscar campaigns activas
  - Buscar news_articles recentes
- [ ] Actualizar `routes/web.php`:
  ```php
  Route::get('/', HomepageController::class);
  ```
- [ ] Construir secções da welcome.blade.php:
  1. [ ] **Navbar** (reutilizar componente da FASE 5)
  2. [ ] **Hero principal** (título, subtítulo, CTA "Ver Lojas")
  3. [ ] **Localizador de lojas** (províncias, destaques)
  4. [ ] **Campanhas / Destaques** (carrossel ou grid)
  5. [ ] **Universo de produtos** (famílias com imagem)
  6. [ ] **Área "Para o seu negócio"** (B2B: hotéis, restaurantes, revendedores)
  7. [ ] **Rede de lojas** (lista ou mapa simplificado)
  8. [ ] **Conteúdo editorial** (notícias, artigos)
  9. [ ] **CTA final** (visite-nos, fale connosco)
  10. [ ] **Footer** (reutilizar componente da FASE 5)

### Regras
- `welcome.blade.php` é a **única** homepage
- Lógica de negócio **no Controller/Service**, não na view
- Componentes Blade **apenas para repetição real**

### Critério de conclusão
Homepage a apresentar dados reais da base de dados com todas as 10 secções.

---

## FASE 7 — Páginas Institucionais

### Objectivo
Criar as páginas de conteúdo institucional.

### Tarefas
- [ ] `/institucional/equipa` — Team members (board + leadership)
- [ ] `/institucional/sobre` — Sobre a Mangolê (conteúdo das settings)
- [ ] `/noticias` — Lista de news_articles
- [ ] `/noticias/{slug}` — Artigo individual
- [ ] `/parceiros` — Lista de partners
- [ ] `/carreiras` — Lista de vacancies
- [ ] `/carreiras/{slug}` — Vaga individual
- [ ] `/contacto` — Formulário de contacto (store_messages)
- [ ] Criar SEO dinâmico com `seo_metadata` por página

### Critério de conclusão
Todas as páginas institucionais a funcionar com dados reais.

---

## FASE 8 — Lojas e Localização

### Objectivo
Páginas de lojas e sistema de geolocalização.

### Tarefas
- [ ] `/lojas` — Lista de lojas com pesquisa por província
- [ ] `/lojas/{slug}` — Página individual da loja
  - Informações, horário, serviços, foto
  - Mapa (Google Maps ou OpenStreetMap)
  - Formulário de contacto específico da loja
- [ ] Opcional: criar tabelas `provinces` e `municipalities` se decidido na FASE 1
- [ ] Index geográfico (latitude/longitude)

### Critério de conclusão
Páginas de lojas completas com dados reais.

---

## FASE 9 — B2B / Grossistas / Revendedores

### Objectivo
Secção de negócio para público empresarial.

### Tarefas
- [ ] `/para-o-seu-negocio` — Página institucional B2B
- [ ] Formulário de lead B2B (diferente de `store_messages`)
- [ ] Conteúdo sobre fornecimento para hotéis, restaurantes, mercearias, revendedores
- [ ] Diferenciação entre consumidor final e cliente empresarial

### Critério de conclusão
Página B2B publicada com formulário funcional.

---

## FASE 10 — Formulários e Leads

### Objectivo
Sistema de captação e gestão de leads.

### Tarefas
- [ ] Validação e sanitização de todos os formulários
- [ ] Notificações por email para novos leads
- [ ] Dashboard Filament para gestão de leads
- [ ] Export de leads (CSV/Excel via Filament)
- [ ] Rate limiting em formulários públicos

### Critério de conclusão
Formulários funcionais com notificação e gestão.

---

## FASE 11 — SEO e Performance

### Objectivo
Otimizar o portal para motores de busca e performance.

### Tarefas
- [ ] Meta tags dinâmicas (title, description, Open Graph, Twitter)
- [ ] Sitemap.xml dinâmico
- [ ] Robots.txt configurável
- [ ] Schema.org (LocalBusiness, Article, Product)
- [ ] Canonical URLs
- [ ] Cache de queries (HomepageService cacheado)
- [ ] Lazy loading de imagens
- [ ] Lighthouse score ≥ 90
- [ ] Breadcrumbs em páginas internas

### Critério de conclusão
Lighthouse ≥ 90 em mobile e desktop. Dados estruturados validados.

---

## FASE 12 — Testes e Produção

### Objectivo
Qualidade, testes e deploy.

### Tarefas
- [ ] Testes unitários para Models e Services
- [ ] Testes feature para rotas públicas
- [ ] Testes de formulários (validação, submissão)
- [ ] Testes Filament (Resources CRUD)
- [ ] Seeders para ambiente de testes
- [ ] Configuração de produção:
  - [ ] APP_DEBUG=false
  - [ ] Cache config
  - [ ] Queue driver → redis (ou sync)
  - [ ] Mail driver → SMTP
  - [ ] Session driver → redis (ou file)
- [ ] Deploy (a definir: servidor, domínio)

### Critério de conclusão
Testes verdes. Portal funcional em produção.

---

## FASE 15 — Database Foundation & Testing Hardening ✅ (CONCLUÍDA)

### Objectivo
Tornar a base de dados reproduzível, portável, testável e instalável do zero, sem dependência de tabelas legadas.

### Entregáveis
- [x] Foundation migration `2026_07_20_230000_create_foundation_tables.php` (12 tabelas com `Schema::hasTable()`)
- [x] 14 factories para todos os modelos + geografia
- [x] `HasFactory` trait em 15 Models
- [x] StoreSeeder corrigido (removido `province_code`)
- [x] XSS fix no mapa Leaflet (`@json()`)
- [x] Rich text sanitization (`safe_html()`)
- [x] SQLite/MySQL compatibilidade (migration 000012)
- [x] Acessibilidade básica (aria-*)
- [x] Cache na homepage (`Cache::remember()`)
- [x] Enum labels (10 enums)
- [x] 5 testes: DatabaseFoundation, ContentModel, BusinessInquiry, RouteResponse, ModelCast
- [x] Documentação: `docs/PHASE_15_DATABASE_FOUNDATION.md`, `docs/CHANGELOG.md`

### Validação
- `php artisan migrate:fresh --seed` — ✅ 24 migrations, 12 seeders
- `php artisan test --compact` — ✅ 46 tests, 110 assertions, 0 failures
- `npm run build` — ✅ Vite 8.1.5, 6.56s
- `php artisan route:list` — ✅ 52 rotas

### Decisões tomadas
- Migrations usam `Schema::hasTable()` para compatibilidade com base legada e instalação limpa
- Testes usam SQLite `:memory:` + `RefreshDatabase`
- `safe_html()` carregada via `autoload.files` no `composer.json`

---
## FASE 16 — Security, Admin & Production Hardening ✅ (CONCLUÍDA)

### Objectivo
Rate limiting, testes Filament, correcção de imports, iconografia, documentação arquitectural, auditoria `product_families`, `fontaine`.

### Entregáveis
- [x] Rate limiter `form` (5/min por IP) em `AppServiceProvider::boot()` + middleware na POST `/para-negocios`
- [x] 20 testes Filament: AdminLogin (3), StoreResource (5), ContentResource (12)
- [x] RateLimitingTest (2): form burst → 429, GET ilimitado → 200
- [x] Imports corrigidos em 16 Resources (Section/Fieldset → Schemas, Tables\Actions → Actions)
- [x] `heroicon-o-handshake` → `heroicon-o-user-group`
- [x] Icons removidos dos navigation groups
- [x] `product_families` auditado — inócuo
- [x] `fontaine` instalado — build limpo de warnings Vite
- [x] Documentação: `docs/DATA_MODEL.md`, `docs/DOMAIN_ARCHITECTURE.md` actualizados

### Validação
- `php artisan test --compact` — ✅ 68 tests, 209 assertions, 0 failures
- `php artisan migrate:fresh --seed` — ✅ 24 migrations, 12 seeders
- `npm run build` — ✅ 6.12s, sem warnings

---

## FASE 18 — Settings → Homepage ✅ (CONCLUÍDA)

### Objectivo
Vincular a tabela `settings` à homepage, tornando todo o texto do front-end editável via Filament.

### Entregáveis
- [x] ~40 settings no grupo `home` (todas as secções: Hero, Localizador, Categorias, Campanhas, Experiência, Negócios, Rede, Notícias, CTA Final)
- [x] Cache dedicada `settings.home`, `settings.contact`, `settings.seo` (3600s TTL)
- [x] `welcome.blade.php`: todo o texto substituído por `$homeSettings['key'] ?? 'fallback'`
- [x] Meta tags: título/descrição vêm de `seo.default_title` / `seo.default_description`
- [x] Contacto: phone/WhatsApp lidos de `contact.phone` / `contact.whatsapp`
- [x] `SettingResource`: grupos `company`, `seo`, `operational` adicionados
- [x] `StoreResource::phone`: removido `->tel()` (validação excessiva)
- [x] Documentação: `docs/PHASE_18_SETTINGS_HOMEPAGE.md`

### Validação
- `php artisan test --compact` — ✅ 68 tests, 209 assertions, 0 failures
- `php artisan migrate:fresh --seed` — ✅ 24 migrations, 12 seeders
- `npm run build` — ✅ 9.96s, sem warnings

---

## FASE 19 — Homepage Editorial Architecture & Content Control ✅ (CONCLUÍDA)

### Objectivo
Auditar arquitecturalmente a homepage, classificar todas as Settings, decidir entre composição fixa vs Page Builder, e implementar HomepageService com cache segura e observer de invalidação.

### Entregáveis
- [x] Auditoria arquitectural completa: `docs/PHASE_19_ARCHITECTURE_AUDIT.md`
- [x] Classificação de todas as ~45 settings — 100% adequadas como Settings, nenhuma a migrar
- [x] Decisão tomada — composição fixa (Estratégia A), sem Page Builder
- [x] `app/Services/HomepageService.php`: service centralizado com `build(): array`
- [x] Cache reintroduzida para settings: `Cache::remember("settings.{group}", 3600, ...)`
- [x] `app/Observers/SettingObserver.php`: invalida cache no saved/deleted
- [x] `routes/web.php`: usa `HomepageService::build()` em vez de Closure com @php
- [x] `welcome.blade.php`: removido @php block — dados injectados pelo serviço
- [x] `AppServiceProvider`: registado SettingObserver

### Validação
- `php artisan test --compact` — ✅ 68 tests, 209 assertions, 0 failures
- `php artisan migrate:fresh --seed` — ✅ 24 migrations, 12 seeders
- `npm run build` — ✅ 5.77s, sem warnings

## FASE 20 — Homepage Hero Carousel Editorial ✅ (CONCLUÍDA)

### Objectivo
Substituir a hero estática por um carousel editorial com múltiplos slides geridos pelo Filament.

### Entregáveis
- [x] `HomepageSlide` — entidade dedicada (migration, model, factory, seeder)
- [x] `HomepageSlideResource` — Filament com 5 secções (Conteúdo, CTAs, Imagem, Apresentação, Programação)
- [x] `HomepageSlideObserver` — invalida cache no saved/deleted
- [x] `HomepageService::heroSlides()` — cache com arrays puros + fallback editorial
- [x] `x-homepage.hero-carousel` — componente Blade com 5 variantes visuais
- [x] Alpine.js — carousel interactivo (autoplay 6s, pause hover/teclado, dots, setas)
- [x] `welcome.blade.php` — hero substituída pelo componente
- [x] 11 testes (slides vazios, activos, período, ordenação, service, observer, CRUD)
- [x] `docs/PHASE_20_HOMEPAGE_HERO_CAROUSEL.md`

### Validação
- `php artisan test --compact` — ✅ 79 tests, 242 assertions, 0 failures
- `php artisan migrate:fresh --seed` — ✅ 25 migrations, 13 seeders
- `npm run build` — ✅ 12.05s, sem warnings

---

## Resumo de Fases — Estado Actual (79 testes, 242 assertions, 0 falhas)

| Fase | Nome | Estado | Detalhe |
|------|------|--------|---------|
| 0 | Auditoria e Baseline | ✅ **CONCLUÍDA** | Auditoria BD, baseline do projecto, roadmap |
| 1 | Arquitectura de Dados | ✅ **CONCLUÍDA** | Decisões integradas nas fases seguintes |
| 2 | Models e Migrations | ✅ **CONCLUÍDA** | 24 migrations, 21 Models |
| 3 | Filament CMS | ✅ **CONCLUÍDA** | Resources: Stores, Products, Categories, Brands, Campaigns, News, Partners, Vacancies, Opportunities, Settings, SEO, Inquiries, Team |
| 4 | Design System | ✅ **CONCLUÍDA** | Paleta Mangolê, Tailwind v4, componentes Blade |
| 5 | Layout Global | ✅ **CONCLUÍDA** | Navbar, footer, layout base |
| 6 | Homepage | ✅ **CONCLUÍDA** | welcome.blade.php com 10 secções |
| 7 | Páginas Institucionais | ✅ **CONCLUÍDA** | Equipa, Sobre, Notícias, Carreiras, Contacto, Parceiros |
| 8 | Lojas e Localização | ✅ **CONCLUÍDA** | Lista, detalhe, mapa Leaflet, províncias/municípios |
| 9 | B2B / Grossistas | ✅ **CONCLUÍDA** | `/para-negocios`, formulário B2B |
| 10 | Formulários e Leads | ✅ **CONCLUÍDA** | Contacto, B2B, BusinessInquiry, Filament gestão |
| 11 | SEO e Performance | ✅ **CONCLUÍDA** | Meta tags, sitemap.xml, robots.txt, lazy loading, cache |
| 12 | Testes e Produção | ✅ **CONCLUÍDA** | 46 testes, 110 assertions (ver FASE 15) |
| 13-14 | Fases intermédias | ✅ **CONCLUÍDA** | Migrations evolutivas, enums, Filament refinamentos |
| 15 | Database Foundation & Testing | ✅ **CONCLUÍDA** | Foundation migration, factories, XSS fix, sanitização, testes |
| 16 | Security, Admin & Production Hardening | ✅ **CONCLUÍDA** | Rate limiting, 20 testes Filament, imports corrigidos, fontaine |
| 17 | Business Experience & Content Audit | ✅ **CONCLUÍDA** | Auditoria arquitectural (10 perguntas), mapeamento de fluxos |
| 18 | Settings → Homepage | ✅ **CONCLUÍDA** | ~40 settings, cache, welcome.blade.php editável via admin |
| 19 | Homepage Editorial Architecture & Content Control | ✅ **CONCLUÍDA** | Auditoria arquitectural, HomepageService, SettingObserver, cache segura |
| 20 | Homepage Hero Carousel Editorial | ✅ **CONCLUÍDA** | HomepageSlide, HeroCarousel, Alpine.js, 11 testes |
