# Prompt: Integrar aplicação Filament (cliente) com a API HostControl

> Cole este prompt na nova sessão, informando a pasta do projeto do cliente.

---

## Contexto

Este projeto é uma aplicação Laravel + Filament que pertence a um **cliente** de uma empresa de hospedagem. As assinaturas de servidor, pagamentos e monitoramento (heartbeats) são gerenciados centralmente por uma API externa chamada **HostControl** (projeto separado, já concluído e testado — 73 testes passando).

Cada aplicação cliente possui **exatamente uma subscription** na HostControl, e cada subscription tem uma **license_key** única (`hcl_` + 64 hex). É essa chave que autentica a aplicação — a API sempre responde no escopo da subscription autenticada.

O objetivo desta etapa é fazer esta aplicação **consumir a API HostControl** e expor ao cliente, dentro do painel Filament dele:

1. **KPIs no topo** de uma página/dashboard: métricas do estado atual da assinatura (status, dias até vencer, valor mensal, último pagamento).
2. **Histórico de pagamentos** (tabela paginada vinda da API).
3. **Registro automático de heartbeat** — um comando agendado que envia um "ping" periódico à API comprovando que a aplicação está online.

Importante: **não há banco local** para assinaturas/pagamentos. Os dados vivem na API HostControl e devem ser consumidos via HTTP em tempo real (cache curto opcional, ex: 60s). Não crie migrations para isso.

---

## Autenticação

Toda request usa o header com a license_key da subscription desta aplicação:

```
X-License-Key: <license_key da subscription>
Accept: application/json
```

Erros possíveis:

| Status | Body | Significado |
|--------|------|-------------|
| 401 | `{"message": "License key required."}` | Header não enviado |
| 401 | `{"message": "Invalid license key."}` | Key inválida |

Configuração esperada no `.env` deste projeto (criar as vars):

```
HOSTCONTROL_API_URL=http://localhost:8000/api/v1
HOSTCONTROL_LICENSE_KEY=<license_key da subscription desta aplicação>
HOSTCONTROL_TIMEOUT=10
```

---

## Endpoints disponíveis (escopo da subscription autenticada)

### 1. Minha assinatura (atual)

```
GET {HOSTCONTROL_API_URL}/subscriptions
Header: X-License-Key
```

Retorna `{"data": {...}}` — **objeto único** (não é lista):

```json
{
    "data": {
        "id": 1,
        "client_id": 1,
        "application_id": 1,
        "status": "active",
        "monthly_price": "150.00",
        "paid_until": "2026-09-24T00:00:00.000000Z",
        "next_due": "2026-10-24T00:00:00.000000Z",
        "license_key": "hcl_a1b2c3...",
        "grace_until": null,
        "created_at": "2026-08-24T19:01:57.000000Z",
        "updated_at": "2026-08-24T19:01:57.000000Z",
        "client": {"id": 1, "name": "João da Silva", "email": "..."},
        "application": {
            "id": 1,
            "client_id": 1,
            "name": "Sistema de Pedidos",
            "domain": "pedidos.cliente.com",
            "repository": "https://github.com/...",
            "server": "srv-01",
            "status": "active"
        }
    }
}
```

- `status` enum: `active | inactive | suspended | cancelled`
- `monthly_price` vem como **string** decimal (ex: `"150.00"`)

### 2. Listar meus pagamentos

```
GET {HOSTCONTROL_API_URL}/payments/me?page=1&per_page=15
Header: X-License-Key
```

Retorna paginador Laravel. Cada item de `data`:

```json
{
    "id": 1,
    "subscription_id": 1,
    "value": "150.00",
    "paid_at": "2026-09-24T10:00:00.000000Z",
    "status": "paid",
    "gateway_id": "gw_123",
    "gateway_data": {"provider": "test"},
    "created_at": "...",
    "updated_at": "...",
    "subscription": {
        "id": 1,
        "status": "active",
        "monthly_price": "150.00",
        "next_due": "...",
        "application": {"id": 1, "name": "Sistema de Pedidos", "domain": "..."}
    }
}
```

- `status` enum: `pending | paid | failed | refunded`
- Ordenação: mais recentes primeiro
- Envelope do paginador: `current_page`, `data`, `from`, `last_page`, `per_page`, `to`, `total`, `next_page_url`, `prev_page_url`, `path`, `links`

### 3. Registrar heartbeat (ping)

```
POST {HOSTCONTROL_API_URL}/heartbeats
Header: X-License-Key
Content-Type: application/json

{}
```

- **Body vazio** (ou `{}`) — a subscription é identificada pela license key, não há `subscription_id`.
- `ip_address` e `pinged_at` são opcionais (a API preenche com o IP de origem e a hora atual).
- Sucesso: `201` com `{"data": {"id": 1, "subscription_id": 1, "ip_address": "...", "pinged_at": "..."}}`
- Deve ser chamado por um **comando agendado** (scheduler), ex: `hostcontrol:heartbeat`, rodando a cada 5 minutos — um ping por execução.

### 4. Listar meus heartbeats

```
GET {HOSTCONTROL_API_URL}/heartbeats/me?page=1&per_page=15
Header: X-License-Key
```

Retorna paginador. Cada item: `{id, subscription_id, ip_address, pinged_at, subscription: {application: {...}}}`. Útil para mostrar "última vez online".

---

## O que construir

1. **Config** (`config/hostcontrol.php`): `api_url`, `license_key`, `timeout`, `cache_ttl` (default 60s), `heartbeat_frequency`.

2. **Service de integração** (ex: `app/Services/Hostcontrol/HostcontrolClient.php`): wrapper em cima do Laravel HTTP Client, com:
   - headers padrão (`X-License-Key`, `Accept`)
   - métodos: `subscription()`, `payments(int $page)`, `heartbeats(int $page)`, `ping()`
   - tratamento de exceções/timeout (ConnectionException) e API fora do ar — a página Filament deve mostrar um aviso amigável ("Não foi possível contatar o HostControl") em vez de quebrar
   - cache curto opcional para GETs (respeitar `cache_ttl`)

3. **Página Filament** (ex: `hostcontrol` — página no painel do cliente):
   - **KPIs no topo** (StatsOverviewWidget): Status da assinatura (badge colorida por status: active=success, suspended=warning, cancelled/inactive=danger), Dias até o vencimento (`next_due` — X dias, destaque se ≤ 7 dias), Valor mensal (`monthly_price` formatado em BRL), Último pagamento (status + data)
   - **Tabela de histórico de pagamentos** (TableWidget consumindo a API — paginação manual via query params `page`/`per_page`, não Eloquent): colunas ID, Valor, Status (badge), Pago em, Aplicação

4. **Comando agendado** `php artisan hostcontrol:heartbeat` que faz um `ping()` por execução; registrar no `routes/console.php` a cada 5 minutos. Logar falhas sem estourar o scheduler.

5. **Testes** (pest/phpunit): mockear o HTTP Client (`Http::fake`) e testar o service (sucesso, 401, timeout) e os widgets/página renderizando com dados fake.

---

## Observações

- Laravel HTTP Client já vem com o framework (Guzzle) — não instalar SDKs.
- O mesmo código será replicado em **duas aplicações cliente** (cada uma com sua própria `HOSTCONTROL_LICENSE_KEY`), então tudo deve ser genérico e movido apenas por config (`.env`).
- Não implementar CRUD de assinaturas/pagamentos no cliente — a gestão é toda no admin da HostControl. Aqui é somente **leitura + heartbeat**.
- Se a API retornar 401 (license key inválida), mostrar aviso claro ("Licença inválida ou revogada") em vez de estado vazio silencioso.
