# PLAN_BACKEND.md — Backend API multi-tenant unificado

## Descrição geral

Este plano descreve a extração do monólito Rota Viva para um **backend headless REST
multi-tenant e restrito**, única fonte de dados e de inteligência artificial. O backend responde
exclusivamente JSON versionado (`/api/v1`), resolve o tenant por requisição (`X-Tenant` + domínio),
autentica via Laravel Sanctum (tokens de API stateless) e mantém todas as chaves de IA, regras de
negócio e acesso a dados fora de qualquer front-end. Não renderiza HTML, não mantém sessão de
navegador e não expõe segredos. Cobre resolução de tenant, autenticação (3 perfis de token),
recursos de saída, controllers de API, validação, CORS, upload assinado, hardening de segurança
(isolamento cross-tenant, cabeçalhos defensivos, HTTPS/HSTS, logs sem vazamento) e compatibilidade
com PostgreSQL 10.23. O contraponto visual está em `PLAN_FRONTEND.md`; o roteiro de execução está em
`EPIC.md` (PLANO B / T).

## Objetivo

Extrair toda a lógica de negócio, IA e acesso a dados do monólito atual para um **único
backend headless REST**, multi-tenant, que atende a todos os front-ends dos diversos tenants.
O backend passa a ser a fonte restrita e central de dados e de inteligência; não renderiza
HTML nem mantém sessão de navegador.

## Princípios de design

- **Headless / stack-agnostic:** respostas somente JSON, versionadas (`/api/v1`). O frontend
  pode ser Blade, SPA ou qualquer stack.
- **Multi-tenant por requisição:** o tenant continua resolvido por `X-Tenant` (slug/uuid) ou
  domínio, reutilizando `ResolveTenantMiddleware` e `TenantManager`.
- **Restrito:** todo endpoint exige token (leitura pública incluída). Chaves de IA
  (`AI_PROVIDER`, `ZEN_API_KEY`, etc.) permanecem **somente no backend**.
- **Reuso máximo:** serviços (`ItineraryService`, `RouteAdaptationService`, AI writers,
  repositório, analytics) já são desacoplados do HTTP e são mantidos intactos.

## O que fica no backend

| Camada | Conteúdo atual reutilizado |
|--------|----------------------------|
| Domínio/DB | `app/Models/*`, migrations, `Municipio` + `DominioMunicipio` (tenant). |
| Tenancy | `app/Services/Tenant/TenantManager.php`, `ResolveTenantMiddleware.php`. |
| Retrieval/IA | `app/Services/Itinerary/*`, `app/Services/Adaptation/*`, `app/Services/Ai/*`, `app/Repositories/*`. |
| Analytics | `app/Services/Analytics/JourneyAnalyticsService.php`, `app/Services/Dashboard/DashboardService.php` (como fontes de dados). |
| Persistência | `app/Services/Itinerary/ItineraryPersistenceService.php`. |
| Auth (token) | `AuthController` adaptado para emitir tokens; `User`, `UsuarioPlataforma`. |

## O que sai do backend

- Todas as views Blade (`resources/views/*`), layouts, assets Vite.
- Sessão web, `auth` session middleware, CSRF, `RedirectResponse` para páginas.
- Controllers que devolvem `view()` — substituídos por API Resources + controllers de API.

## Arquitetura alvo

```
Cliente (front-end tenant)
   │  Authorization: Bearer <tenant_token>
   │  X-Tenant: <slug|uuid>
   ▼
routes/api.php
   ├─ ResolveTenantMiddleware  (X-Tenant / domínio → TenantManager)
   ├─ auth:sanctum             (validação de token)
   ├─ throttles                (route-generation, route-adaptation, login, admin-actions)
   ▼
Controllers API → Services (reutilizados) → Repository/Models → DB (compartilhado multi-tenant)
   ▼
API Resources (JSON) ← validação anti-alucinação já existente nos writers
```

## Mapa de conversão (web → API)

Os controllers atuais em `app/Http/Controllers/Public`, `Auth`, `Admin`, `Platform` viram
endpoints JSON. A lógica de serviço é reaproveitada; apenas a entrada/saída muda.

| Atual (web) | Endpoint API (restrito) | Auth |
|-------------|--------------------------|------|
| `CatalogController` (index/show) | `GET /api/v1/catalogos/{section}[/{slug}]` | tenant token |
| `CityMapController` | `GET /api/v1/mapa` | tenant token |
| `ItineraryController@store` | `POST /api/v1/roteiros` | tenant token |
| `ItineraryController@show` | `GET /api/v1/roteiros/{id}` | tenant token |
| `AdaptationController@rain` | `POST /api/v1/roteiros/{id}/adaptar/chuva` | tenant token |
| `AdaptationController@show` | `GET /api/v1/roteiros/{id}/adaptacoes/{adaptation}` | tenant token |
| `EntrepreneurController@store` | `POST /api/v1/empreendedores` | tenant token |
| `InteractionController@track` | `POST /api/v1/interacoes` | tenant token |
| `AuthController@login` | `POST /api/v1/auth/login` → token | público (throttle login) |
| `DashboardController@index` | `GET /api/v1/gestor/dashboard` | user token (access-admin-panel) |
| `MunicipalityAppearanceController@update` | `PUT /api/v1/gestor/aparencia` | user token |
| `AdminController` (módulos) | `GET/POST/PUT/DELETE /api/v1/gestor/{module}[/{id}]` | user token |
| `PlatformController` | `GET/POST /api/v1/plataforma/municipios*` | platform token |
| (novo) bootstrap | `GET /api/v1/tenant/config` | tenant token |

> `tenant/config` devolve branding/aparência do município para o front-end single-tenant
> renderizar corretamente (subtitui o `View::composer` atual em `AppServiceProvider`).

## Autenticação multi-tenant

- **Laravel Sanctum** (tokens de API) para stateless. Três perfis de token:
  1. **Tenant client token** — emissão por tenant (secret armazenado no deploy do front-end);
     usado em todas as leituras/catálogos/roteiros/cadastros.
  2. **User token** — gestor municipal (`can_access_admin_panel`) via `POST /auth/login`.
  3. **Platform token** — super-admin (`can_manage_platform`) para criação de municípios.
- `ResolveTenantMiddleware` registrado no grupo `api` (já lê `X-Tenant`/`_tenant`).
- `Gate` `access-admin-panel` / `manage-platform` mantidos; validados no token do usuário.

## Multitenancy (já suportado)

- Tenancy é *column-based* (shared tables + `municipio_id` / pivot). Nenhuma mudança de
  schema necessária. `TenantManager::resolveByDomain` e `createTenant` permanecem.
- Cada request API define o tenant via `X-Tenant`; `EloquentAtrativoRepository::available()`
  e serviços já operam no contexto resolvido.

## Passos de implementação (resumo)

1. Criar `routes/api.php` com grupo `X-Tenant` + `auth:sanctum` + throttles.
2. Instalar/Configurar Sanctum; migrar `AuthController` para emitir tokens.
3. Criar API Resources (`CatalogResource`, `RoteiroResource`, `AdaptacaoResource`,
   `DashboardResource`, `ModuleResource`, `TenantConfigResource`, `EntrepreneurResource`).
4. Criar `App\Http\Controllers\Api\*` espelhando a tabela de conversão; chamar os mesmos services.
5. Mover validações de entrada para Form Requests.
6. Remover `view()`, sessão web e CSRF do backend; manter CORS para os domínios dos tenants.
7. Manter `AI_PROVIDER` e chaves no `.env` do backend (nunca expostas).
8. Ajustar rate limits já existentes em `AppServiceProvider::boot`.

## Riscos / atenção

- `ItineraryController@store` usa `set_time_limit(150)` e `redirect()` — trocar por resposta
  JSON e tratamento de timeout do lado do cliente/queue.
- `AppServiceProvider::boot` faz `View::composer` global — remover do backend; mover para
  endpoint `tenant/config`.
- Uploads de mídia (`Storage`) devem ganhar endpoints assinados ou proxy no backend.

## Segurança do backend (prevenção de vazamento + fortalecimento)

Seção dedicada, fundamentada em `GUIDES/web_security_guide`, `GUIDES/php_guide/84` e
`GUIDES/http_uri_guide`. O risco central de um backend multi-tenant restrito é o **vazamento
cross-tenant** e o vazamento de segredos; as defesas abaixo seguem *defense in depth*.

### 1. Isolamento de tenant (anti-vazamento cross-tenant) — prioridade máxima
- **O token define o tenant, não o header.** `ResolveTenantMiddleware` aceita `X-Tenant` vindo
  do cliente; isso é controlável. Vincular cada **tenant client token** a um `municipio_id`
  fixo e resolver o tenant a partir do token (validando/ignorando o header quando divergir).
  Impede que um tenant envie `X-Tenant: outro-tenant` com seu próprio token válido.
- **Scoping obrigatório em toda query.** Aplicar `where municipio_id` no repositório
  (`EloquentAtrativoRepository`) ou um *global scope* Eloquent em `Atrativo`, `Roteiro`,
  `PreferenciaVisitante`, etc. Nenhuma leitura deve cruzar municípios.
- **Autorização por objeto (IDOR).** Endpoints `gestor/*` e `plataforma/*` validam, via `Gate`,
  que o usuário/plataforma pertence ao recurso ( comparar `user.municipio_id` com o dono do
  objeto ), não apenas `auth`. (cf. `web_security_guide/05` — *Access Control por objeto* e
  *UUIDs non-guessable*.)
- **IDs não sequenciais** para `Roteiro`/`AdaptacaoRota` expostos publicamente (UUID/snowflake)
  mitigam enumeration/IDOR.

### 2. Segredos e tokens
- **Nunca em query string.** Tokens de API via `Authorization: Bearer` — jamais em `_tenant`/
  query, que vaza em logs, `Referer` e histórico (cf. `http_uri_guide/05` — *User Info em URLs*
  e *Semantic URL Attacks*). O `_tenant` deve transportar só o slug (não secreto).
- **AI keys só no backend** (já previsto); o `.env` é gitignored (manter). Nunca retornar
  `ZEN_API_KEY`/`DEEPSEEK_API_KEY` em qualquer Resource.
- **Sanctum com `abilities`**: emitir token com escopo (`tenant`|`user`|`platform`), expiração
  curta, revogar em logout e em troca de senha. Comparações sensíveis com `hash_equals`
  (cf. `php_guide/84/14` §6).
- `APP_DEBUG=false` e `display_errors=0` em produção (cf. `php_guide/84/24` §2).

### 3. Respostas de erro sem vazamento
- Handler de exceção global retorna JSON genérico (`{"error":"..."}`) com status HTTP correto;
  **não** expor stack trace, SQL, paths ou nomes internos. Logar com contexto no servidor
  (`$e->getTraceAsString()`) sem ecoar ao cliente (cf. `php_guide/84/24` §10).

### 4. Validação de entrada (allowlist) — `web_security_guide/13`, `php_guide/84/22`
- Mover regras para **Form Requests** (tipo, formato, tamanho, range, padrão). Client-side é
  só UX; server-side é obrigatório.
- **Uploads** (gestor): apenas autenticado, allowlist de extensão, validar MIME/tamanho, gerar
  nome próprio (não confiar no `filename`), armazenar fora do webroot.
- **SSRF/command injection:** nunca passar URL/time de entrada do usuário para `file_get_contents`
  / `exec`; o backend só fala com o provedor de IA via `config()` (host fixo).
- Eloquent já usa *prepared statements* → SQLi coberto; manter consultas parametrizadas
  (cf. `php_guide/84/14` §8).

### 5. Transporte e cabeçalhos de resposta
- **HTTPS obrigatório** + `Strict-Transport-Security: max-age=63072000; includeSubDomains`
  e redirecionamento HTTP→HTTPS (cf. `web_security_guide/01`).
- Headers defensivos no backend (mesmo sem UI, protegem consumidores/documents):
  `X-Content-Type-Options: nosniff`, `Cross-Origin-Resource-Policy: same-origin`,
  `Cross-Origin-Opener-Policy: same-origin`, `Referrer-Policy: no-referrer`,
  `Permissions-Policy` restritiva, `X-Frame-Options: DENY` (cf. `web_security_guide/05`,
  `http_uri_guide/05` §1).

### 6. CORS restrito
- `Access-Control-Allow-Origin` com **lista explícita** dos domínios dos tenants; **nunca `*`
  com credenciais**; expor apenas os headers necessários (`X-Tenant`, `Authorization`)
  (cf. `http_uri_guide/05` §1.1).

### 7. Autenticação reforçada — `php_guide/84/14`, `web_security_guide/02`
- Senhas com **Argon2id** (`password_hash(..., PASSWORD_ARGON2ID)`); rate-limit de login já
  existente; resposta neutra para evitar enumeração de e-mail.
- Considerar **MFA/TOTP** para gestor municipal (`can_access_admin_panel`).
- API stateless via token no header mitiga CSRF naturalmente; se usar cookie para token
  cross-site, `Secure; HttpOnly; SameSite=None` (cf. `web_security_guide/02` §2).

### 8. Logs sem vazamento — `php_guide/84/06`
- Não registrar tokens, senhas, descrição livre do visitante (o `JourneyAnalyticsService` já
  evita salvar o texto bruto) nem PII. Níveis adequados + rotação; monitorar picos de
  `401/403/429` e usar `Network Error Logging` onde aplicável.

### 9. Operacional
- `robots.txt` com `Disallow: /api/`; manter SBOM/lockfile e atualizações de dependências
  (supply chain); `Subdomain Takeover` evitado com ordem correta provision/deprovision de
  domínios de tenant.

## Observações e recomendações — PostgreSQL 10.23

As migrations foram revisadas e **são compatíveis com PostgreSQL 10.23**: não há colunas
geradas (`GENERATED AS`), identidade, `gen_random_uuid()`, `enum`, `fullText`, `spatial` ou
`DB::statement` com extensões. O tipo `uuid` é nativo (sem extensão); `useCurrent()` vira
`DEFAULT CURRENT_TIMESTAMP` (suportado); `json`/`jsonb`/`timestampsTz`/`softDeletes` são válidos.

Recomendações para a implementação do backend sobre este Postgres:

- **Não dependa de `gen_random_uuid()` no banco.** O PG 10 não o traz nativo (só no 13+; no 10
  exigiria extensão `pgcrypto`). O `TenantManager::createTenant` já gera `uuid` em PHP
  (`Str::uuid()`) — manter assim. Se algum seeder/model precisar de UUID default no DB,
  habilite `CREATE EXTENSION pgcrypto` ou gere na aplicação.
- **Remova os modificadores `->after('coluna')`.** São ignorados silenciosamente no PostgreSQL
  (ele não reordena colunas em `ADD COLUMN`); não quebram a migração, mas a ordem pretendida não
  é aplicada. Ocorrem em: `add_can_access_admin_panel_to_users`,
  `add_can_manage_platform_to_users`, `add_municipio_id_to_users`, `add_home_branding_to_municipios`,
  `add_local_economy_to_municipios`.
- **Prefira `jsonb` a `json`.** As colunas `json` atuais funcionam, mas se houver (ou vier a
  haver) filtros/operadores `->`/`->>` ou índices de expressão sobre esses campos, `jsonb` é o
  adequado no PG 10. Hoje nenhum índice recai sobre colunas json, então não há urgência.
- **Evite recursos de PG 12+.** Não introduzir colunas geradas/stored, `NULLS NOT DISTINCT` em
  índices únicos (PG 15+), nem particionamento declarado além do suportado em 10.
- **Teste as migrations contra o Postgres 10.23 real** (ex.: container `postgres:10.23`) antes
  de validar o plano, garantindo paridade de comportamento de `timestamptz` e índices compostos.
