Integração via API REST
Migre de CSV estático para dados em tempo real consumindo a API REST do eKyte, com proxy seguro via Serverless Function.
Quando fazer: depois que o dashboard estiver estável e você quiser dados em tempo real, sem exportar CSV manualmente. Requer deploy em plataforma que suporte Serverless Functions (Vercel, Netlify, Railway etc.).
Princípios de segurança
A chave da API nunca é exposta no browser. A arquitetura segue o padrão de proxy seguro via Serverless Function:
Browser (frontend) → /api/tasks (proxy interno) → api.ekyte.com
- A chave fica armazenada como variável de ambiente no servidor (
EKYTE_API_KEY). - O frontend chama apenas o proxy interno (
/api/tasks). - O proxy (Serverless Function) faz a chamada real à API do eKyte.
Onde obter a chave da API
No painel do eKyte, vá em:
Minha Empresa → Data Driven → Token de acesso
O token exibido deve ser usado como valor da variável de ambiente:
EKYTE_API_KEY=seu-token-aqui
A chave deve ser tratada como credencial sensível e nunca pode ser exposta no frontend ou commitada no repositório.
Passo 1 — Subir o projeto Lovable para o GitHub
O Lovable se integra diretamente com o GitHub — não é preciso usar terminal nem comandos git.
- Crie uma conta no GitHub caso ainda não tenha.
- No Lovable, clique no menu do projeto e selecione GitHub.
- Com a conta vinculada, conecte-a ao projeto. O Lovable cria automaticamente um repositório no seu perfil do GitHub e sincroniza o código.
A partir daqui, qualquer alteração feita no Lovable é refletida automaticamente no repositório.
Passo 2 — Clonar o projeto na plataforma de hospedagem
Importe o repositório do GitHub na plataforma escolhida:
| Plataforma | Como clonar |
|---|---|
| Vercel | "Add New… → Project" → importar do GitHub |
| Netlify | "Add new site → Import an existing project" |
| Railway | "New Project → Deploy from GitHub repo" |
| Heroku | "New → Create new app" → conectar ao GitHub na aba Deploy |
| AWS Amplify | "Host a web app → Connect a Git provider" |
| Docker | git clone do repositório no host |
Aguarde o primeiro deploy concluir (mesmo que falhe por falta da chave — isso é esperado neste momento).
Passo 3 — Configurar a variável de ambiente
Com o projeto já clonado na plataforma, abra-o no painel e adicione:
- Nome:
EKYTE_API_KEY - Valor: sua chave
- Ambiente: Production (e Preview/Staging, se desejar)
Atenção: nunca use prefixo VITE_ para esta variável — isso a exporia no bundle do browser.
| Plataforma | Localização |
|---|---|
| Vercel | Settings → Environment Variables |
| Netlify | Site settings → Environment variables |
| Railway | Variables → New Variable |
| Heroku | Settings → Config Vars |
| AWS Amplify | Environment variables |
| Docker | arquivo .env ou docker-compose.yml |
Passo 4 — Fazer redeploy
Variáveis de ambiente só passam a valer no próximo build/deploy — adicioná-las não atualiza o deploy atual.
| Plataforma | Como forçar redeploy |
|---|---|
| Vercel | Deployments → menu ⋯ do último deploy → "Redeploy" |
| Netlify | Deploys → "Trigger deploy → Deploy site" |
| Railway | Deployments → "Redeploy" |
| Heroku | Deploy → "Deploy Branch" |
| AWS Amplify | App → menu do branch → "Redeploy this version" |
| Docker | docker compose up -d --build |
Passo 5 — Verificar o deploy
Após o redeploy, confirme que:
- A aplicação está acessível.
- A variável
EKYTE_API_KEYfoi configurada corretamente. - O endpoint
/api/tasksresponde sem expor a chave. - Acesse a URL da aplicação indicada no painel da plataforma:
- Acesse no navegador:
<url>/api/tasks
- Se tudo estiver correto, cole o prompt de API (§ abaixo) no Lovable.
Especificação da API eKyte
Endpoints
| Ambiente | URL base |
|---|---|
| Produção | https://api.ekyte.com/v1.1/tasks |
Parâmetros obrigatórios
| Parâmetro | Descrição | Formato | Exemplo |
|---|---|---|---|
apiKey | Chave de autenticação | String | (gerenciado pelo proxy) |
createdFrom | Data inicial | YYYY-MM-DD | 2022-01-15 |
status | Filtro de status | 0, 1 ou omitir | 0 = ativas, 1 = concluídas |
page | Número da página | Integer | 1 (começa em 1) |
Exemplo de chamada
https://api.ekyte.com/v1.1/tasks?apiKey={KEY}&createdFrom=2022-01-15&status=0&page=1
Serverless Function (proxy seguro)
Arquivo padrão: api/tasks.ts (criado na raiz do projeto)
| Plataforma | Caminho |
|---|---|
| Vercel / Netlify | api/tasks.ts |
| Next.js | pages/api/tasks.ts ou app/api/tasks/route.ts |
| Express / Node | server/routes/tasks.js |
Responsabilidades da função:
- Receber requisições do frontend (
?page=X). - Ler
EKYTE_API_KEYdeprocess.env. - Validar que a chave existe.
- Fazer a requisição à API do eKyte.
- Retornar os dados ao frontend.
- Configurar CORS adequadamente.
Prompt de migração para API REST
# Prompt: Dashboard eKyte via API REST
## Contexto
Substituir leitura do `tarefas.csv` pelo consumo da API REST do eKyte.
Projeto hospedado na Vercel.
- Frontend/proxy: <url>.vercel.app ##INSERIR AQUI URL
- Serverless Function: <url>.vercel.app/api/tasks ##INSERIR AQUI URL
---
## Segurança (obrigatório)
1. Criar `/api/tasks.ts` como Vercel Serverless Function — a chave **nunca** sai do servidor
2. Chave via `process.env.EKYTE_API_KEY` (Settings → Environment Variables) — sem hardcode, sem fallback, sem prefixo `VITE_`
3. `.env` no `.gitignore`
4. Frontend chama apenas `/api/tasks?page=X`
5. Configurar CORS na função
6. Se a chave estiver ausente → `HTTP 500` com `{ "error": "EKYTE_API_KEY não configurada" }` → frontend exibe mensagem clara
---
## API eKyte
GET https://api.ekyte.com/v1.1/tasks?apiKey={KEY}&createdFrom=2022-01-15&status=0&page={N}
**Paginação:** buscar todas as páginas automaticamente; detectar fim por array vazio, `hasMore=false` ou total atingido; máximo 3 requests paralelos.
**Retry:** backoff exponencial em 429/5xx — esperas 1s, 2s, 4s (máx 3 tentativas); exibir "Aguardando..." durante backoff.
---
## UX
- Progresso: `"Carregando página X de Y..."`
- Botão "Atualizar dados"
- Offline: mensagem + botão "Tentar novamente"
---
## Pipeline de dados (ordem obrigatória)
[API eKyte] → [Serverless /api/tasks] → [Frontend]
→ [Camada 1: Envelope Resolver]
→ [Camada 2: Task Canonical Mapper]
→ [Camada 3: Validação + Telemetria]
→ [Camada 4: Agregações/KPIs]
→ [Gráficos e UI]
> **Regra absoluta:** nenhum gráfico, KPI ou componente acessa o payload bruto. Tudo usa exclusivamente o `TaskCanonical`.
---
## Schema real da API
| Grupo | Campos |
|---|---|
| Identificação | `id`, `title`, `description` |
| Status | `situation` (campo primário) |
| Prioridade | `priority`, `priorityGroup` |
| Datas | `creationDate`, `originalDueDate`, `currentDueDate`, `resolvedDate` |
| Esforço | `estimatedTime`, `actualTime` (minutos) |
| Responsáveis | `executor`, `createdBy`, `coExecutor` (string ou `{name, email}`) |
| Fluxo | `phase`, `phases`, `phaseStartDate`, `phaseDueDate` |
| Organização | `workspace`, `project`, `squad`, `channel`, `media` |
| Financeiro | `manualBudget`, `totalEstimatedHourlyRate`, `totalAccomplishedHourlyRate` |
---
## TaskCanonical (TypeScript)
interface TaskCanonical {
id: string
title: string
description: string
status: 'Ativa' | 'Concluída' | 'Cancelada' | 'unknown'
prioridade: 'Urgente' | 'Alta' | 'Média' | 'Baixa' | 'Não definida'
dataCriacao: Date | null
dataPrazoOriginal: Date | null
dataPrazoAtual: Date | null
dataConclusao: Date | null
esforcoEstimadoMin: number
esforcoRealMin: number
responsaveis: string[]
etapaAtual: string
workspace: string
project: string
squad: string
orcamento: number
taxaEstimada: number
taxaRealizada: number
_camposAusentes: string[]
_fallbacksAplicados: string[]
}
---
## Camada 1 — Envelope Resolver
Detectar o array real nesta ordem:
1. `payload` (se array)
2. `payload.data`
3. `payload.data.items`
4. `payload.data.tasks`
5. `payload.data.results`
6. `payload.items`
7. `payload.tasks`
8. `payload.results`
9. `payload.response?.data`
Se nenhum for array → lançar erro estruturado logando o payload bruto.
---
## Camada 2 — Task Canonical Mapper
**`status`** (fonte: `situation`):
| Valores raw | Canônico |
|---|---|
| done, concluido, finalizado, resolved, completed | `'Concluída'` |
| cancelled, cancelado, canceled | `'Cancelada'` |
| active, ativo, open, aberto, in_progress | `'Ativa'` |
| qualquer outro | `'Ativa'` |
| ausente/null | `'unknown'` + registrar |
**`prioridade`** (fonte: `priority`, fallback `priorityGroup`):
| Valor | Canônico |
|---|---|
| 1 / urgent / urgente | `'Urgente'` |
| 2 / high / alta | `'Alta'` |
| 3 / medium / média / normal | `'Média'` |
| 4 / low / baixa | `'Baixa'` |
| ausente | `'Não definida'` + registrar |
---
## Camada 3 — Validação + Telemetria
- `status` 100% `'unknown'` → modo diagnóstico (não renderizar gráficos)
- `esforço` 100% zero → aviso "Dados de esforço indisponíveis"
- `responsaveis` 100% vazios → aviso "Responsáveis não identificados"
- Modo diagnóstico exibe sumário na UI em vez de gráficos zerados
---
## Camada 4 — KPIs (somente `TaskCanonical[]`)
| KPI | Lógica |
| --- | --- |
| Taxa de conclusão | `Concluídas / total * 100` |
| Throughput | Concluídas com `dataConclusao !== null`, agrupadas por semana/mês |
| Esforço total/médio | `esforcoRealMin` (realizado), `esforcoEstimadoMin` (planejado); exibir em horas (÷60) |
| Atraso | `status !== 'Concluída' && dataPrazoAtual < now` |
| Distribuição por etapa | Agrupar por `etapaAtual` |
| Heatmap executor × etapa | Cruzar `responsaveis[0]` com `etapaAtual` |
| Financeiro | Somar `orcamento`, `taxaEstimada`, `taxaRealizada`; usar `?? 0` em todos |