mirror of
https://github.com/domfelipe/mika-agent-assist.git
synced 2026-08-07 11:36:42 +00:00
276 lines
14 KiB
Markdown
276 lines
14 KiB
Markdown
# Mika
|
||
|
||
Plataforma de agentes pessoais de IA com integração nativa ao Telegram.
|
||
|
||
## Stack
|
||
|
||
- **Frontend**: React 19 + TanStack Start (Vite 7) + Tailwind v4
|
||
- **Backend**: Lovable Cloud (Supabase) — Postgres, Auth, Vault, Edge Functions, Realtime
|
||
- **Pagamentos**: Paddle (sandbox + live)
|
||
- **Deploy SSR**: Cloudflare Workers (via Wrangler)
|
||
|
||
## Variáveis de ambiente
|
||
|
||
Já configuradas via `.env` (gerado automaticamente pelo Lovable Cloud):
|
||
|
||
- `VITE_SUPABASE_URL`
|
||
- `VITE_SUPABASE_PUBLISHABLE_KEY`
|
||
- `VITE_SUPABASE_PROJECT_ID`
|
||
- `VITE_PADDLE_ENVIRONMENT` (`sandbox` ou `production`)
|
||
- `VITE_PADDLE_CLIENT_TOKEN`
|
||
|
||
### Secrets do backend (configurados via UI do Lovable Cloud)
|
||
|
||
- `PADDLE_API_KEY` / `PADDLE_WEBHOOK_SECRET`
|
||
- `SUPABASE_SERVICE_ROLE_KEY`
|
||
- `RAILWAY_API_TOKEN` — token da Railway Public API, usado por `provision-agent`/`suspend-agent`/`resume-agent` para criar e gerenciar containers Hermes.
|
||
|
||
> **Suspend/Resume via flag, não via stop.** Railway não permite parar containers sem redeploy. As Edge Functions `suspend-agent`/`resume-agent` usam a env var `HERMES_SUSPENDED` + `serviceInstanceRedeploy`:
|
||
> - `suspend` → upsert `HERMES_SUSPENDED=true` e redeploy → container entra em `sleep infinity`.
|
||
> - `resume` → upsert `HERMES_SUSPENDED=""` e redeploy → container sobe normal.
|
||
>
|
||
> Isso depende do start command verificar a flag. Novos serviços já são provisionados com o comando correto (`HERMES_START_COMMAND` em `_shared/railway.ts`):
|
||
> ```bash
|
||
> /bin/bash -c 'if [ "$HERMES_SUSPENDED" = "true" ]; then echo "Agent suspended" && sleep infinity; fi && if [ -n "$HERMES_SOUL_OVERRIDE" ]; then echo "$HERMES_SOUL_OVERRIDE" > /opt/data/SOUL.md; fi && /opt/hermes/docker/entrypoint.sh gateway run'
|
||
> ```
|
||
> **Para serviços Railway existentes (provisionados antes desta mudança):** atualize manualmente o Start Command via Railway UI/Agent para o comando acima — caso contrário `suspend-agent` apenas marcará `status='suspended'` no banco mas o container continuará rodando.
|
||
- `OPENROUTER_API_KEY` — **obrigatório**. Injetado em cada container Hermes provisionado para que o agente possa chamar os modelos `openrouter/google/gemma-4-*-it`. Sem isso o `provision-agent` retorna 500.
|
||
- `ADMIN_TELEGRAM_BOT_TOKEN` — token do bot de admin (ex: `@mika_test2_bot`) usado pelo `payments-webhook` para enviar notificações de novos clientes, falhas de pagamento e cancelamentos.
|
||
- `ADMIN_TELEGRAM_CHAT_ID` — chat ID do admin que recebe as notificações (ex: `179720882`).
|
||
- (opcional, Fase 5) credenciais SSH para Hermes
|
||
|
||
## Keep-alive dos agentes (substitui UptimeRobot)
|
||
|
||
A Edge Function `keep-alive-agents` mantém todos os containers Railway ativos automaticamente — **não há nada para configurar por agente**. A cada 4 minutos:
|
||
|
||
1. Carrega todos os `agent_instances` com `status = 'active'` e `telegram_bot_token_vault_id` preenchido.
|
||
2. Faz `GET https://api.telegram.org/bot{token}/getMe` para cada um (em paralelo, com falhas isoladas).
|
||
3. Esse tráfego de saída do container Hermes evita que o Railway hiberne instâncias ociosas.
|
||
|
||
Agendado via `pg_cron` (job `keep-alive-agents-every-4min`, schedule `*/4 * * * *`). Consultar/desagendar:
|
||
|
||
```sql
|
||
SELECT * FROM cron.job WHERE jobname = 'keep-alive-agents-every-4min';
|
||
SELECT cron.unschedule('keep-alive-agents-every-4min');
|
||
```
|
||
|
||
---
|
||
|
||
## Fase 3 — Telegram Onboarding (✅ entregue)
|
||
|
||
### O que foi entregue
|
||
|
||
- Wizard guiado de 6 passos (`TelegramOnboardingWizard`) com Framer Motion
|
||
- Validação de token via Edge Function `validate-telegram-bot` (armazenamento em Supabase Vault)
|
||
- Configuração automática de webhook (`configure-telegram-webhook`) com secret de 32 bytes
|
||
- Webhook público `telegram-webhook` com 3 camadas de segurança:
|
||
1. Validação do `uuid_tenant` na URL
|
||
2. Verificação do header `X-Telegram-Bot-Api-Secret-Token`
|
||
3. Rate limit de 30 req/min por agente
|
||
- Detecção da primeira mensagem em **tempo real** via Supabase Realtime, com fallback de polling (5s) após 10s de espera
|
||
- Banners contextuais no painel:
|
||
- Agente suspenso → vermelho com link para Faturamento
|
||
- Token revogado → vermelho com link para Meu Agente
|
||
- Onboarding pendente → amber com CTA "Conectar agora"
|
||
- Onboarding parcial → primary com CTA "Continuar configuração"
|
||
- Card de status no `/painel/agente` com ações (Abrir bot, Desconectar)
|
||
- Auto-abertura do wizard ao retornar do checkout com `?status=success`
|
||
|
||
### Etapas pós-deploy (uma única vez)
|
||
|
||
1. **Verificar Vault** — confirme que a extensão `vault` está ativa e que os RPCs `vault_create_secret`, `vault_decrypt_secret`, `vault_delete_secret` estão restritos ao `service_role`.
|
||
2. **Realtime** — a tabela `telegram_messages_log` foi adicionada à publicação `supabase_realtime` via migration. Confirme em **Database → Replication** que ela está listada.
|
||
3. **Edge Functions públicas** — a função `telegram-webhook` deve estar com `verify_jwt = false` em `supabase/config.toml` (já configurado).
|
||
4. **URL pública do webhook** — a Edge Function gera automaticamente:
|
||
`https://<project-ref>.supabase.co/functions/v1/telegram-webhook/<uuid_tenant>`
|
||
O `uuid_tenant` é gerado por agente ao provisionar.
|
||
5. **Teste manual end-to-end**:
|
||
- Crie um bot no [@BotFather](https://t.me/BotFather)
|
||
- No painel, abra o wizard e cole o token
|
||
- Aguarde a tela "Mande qualquer mensagem para seu Mika agora"
|
||
- Envie "oi" no chat do bot — a tela deve mudar para o estado de sucesso em até 2s
|
||
|
||
### Observações de segurança
|
||
|
||
- Tokens dos bots **nunca** trafegam para o frontend após validação. Ficam apenas em `vault.secrets`, referenciados por `telegram_bot_token_vault_id`.
|
||
- Apenas o `service_role` (Edge Functions) consegue gravar/atualizar/deletar em `agent_instances` via RPCs Vault.
|
||
- A tabela `telegram_messages_log` tem RLS: usuário só vê seus próprios chats; INSERT é restrito ao `service_role`.
|
||
|
||
### O que **não** está nesta fase
|
||
|
||
- ❌ Resposta real via Hermes (Fase 5 — proxy SSH/API)
|
||
- ❌ Outros canais (Slack, WhatsApp)
|
||
- ❌ Comandos customizados / menus
|
||
- ❌ Mensagens de voz/imagem processadas por IA
|
||
- ❌ Suporte a grupos do Telegram
|
||
|
||
A Edge Function `telegram-webhook` hoje responde com um placeholder. O `TODO Fase 5` está marcado no código.
|
||
|
||
---
|
||
|
||
## Fase 4 — Integrações OAuth + Automações (✅ entregue)
|
||
|
||
### O que foi entregue
|
||
|
||
- **5 providers OAuth** cadastrados em `available_mcps`: Google Workspace, Notion, Todoist, Cal.com, Microsoft 365
|
||
- **Edge Functions**:
|
||
- `oauth-start` — gera state token + URL de autorização (PKCE quando aplicável)
|
||
- `oauth-callback` (público, `verify_jwt = false`) — troca code por tokens, persiste no Vault
|
||
- `refresh-integration-token` — renova access_token via refresh_token
|
||
- `disconnect-integration` — revoga no provider + apaga do Vault + auto-pausa cronjobs dependentes
|
||
- `test-integration` — verifica conectividade sem consumir refresh
|
||
- `parse-cronjob-natural-language` — Lovable AI Gateway (gemini-2.5-flash) → cron + prompt
|
||
- **Frontend `/painel/integracoes`** — grid com 4 estados (available, locked, connected, error), página de detalhe com `DisconnectMCPDialog` que lista cronjobs dependentes
|
||
- **Frontend `/painel/cronjobs`** — wizard 3 passos (NL → revisão obrigatória → checagem de dependências MCP), gestão de status (active/paused/auto_paused)
|
||
- **Dashboard** — widgets de Skills, Automações e Integrações + banner de auto-pausa
|
||
- **Enforcement via banco** — views `user_jobs_limits` e `user_integration_limits` aplicam limites por plano
|
||
- **Cleanup oauth_states** — trigger `FOR EACH STATEMENT` (não FOR EACH ROW) limpa tokens expirados
|
||
|
||
### Etapas pós-deploy (uma única vez)
|
||
|
||
#### 1. Configurar OAuth apps em cada provider
|
||
|
||
Para cada provider abaixo, crie um OAuth app e configure a **Redirect URI**:
|
||
|
||
```
|
||
https://smsarmgoirlcedmqvdgc.supabase.co/functions/v1/oauth-callback
|
||
```
|
||
|
||
| Provider | Console | Scopes mínimos |
|
||
|----------|---------|----------------|
|
||
| **Google Workspace** | [console.cloud.google.com](https://console.cloud.google.com) → APIs & Services → Credentials → OAuth 2.0 Client ID (Web app) | `openid email profile https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/calendar` |
|
||
| **Microsoft 365** | [Azure Portal](https://portal.azure.com) → App registrations → New registration → Web | `openid email profile offline_access Mail.Read Calendars.ReadWrite` |
|
||
| **Notion** | [notion.so/my-integrations](https://www.notion.so/my-integrations) → New integration (Public) | (definidos na integração) |
|
||
| **Todoist** | [developer.todoist.com](https://developer.todoist.com/appconsole.html) → App management → Create app | `data:read_write` |
|
||
| **Cal.com** | [app.cal.com/settings/developer](https://app.cal.com/settings/developer/oauth-clients) → New OAuth Client | `READ_BOOKING WRITE_BOOKING READ_PROFILE` |
|
||
|
||
#### 2. Adicionar os 10 secrets no Lovable Cloud
|
||
|
||
Pelo menu **Connectors → Lovable Cloud → Secrets**, adicione:
|
||
|
||
```
|
||
GOOGLE_OAUTH_CLIENT_ID
|
||
GOOGLE_OAUTH_CLIENT_SECRET
|
||
MICROSOFT_OAUTH_CLIENT_ID
|
||
MICROSOFT_OAUTH_CLIENT_SECRET
|
||
NOTION_OAUTH_CLIENT_ID
|
||
NOTION_OAUTH_CLIENT_SECRET
|
||
TODOIST_OAUTH_CLIENT_ID
|
||
TODOIST_OAUTH_CLIENT_SECRET
|
||
CALCOM_OAUTH_CLIENT_ID
|
||
CALCOM_OAUTH_CLIENT_SECRET
|
||
```
|
||
|
||
#### 3. Verificar publicação Realtime
|
||
|
||
A view `user_integration_limits` e `user_jobs_limits` usam dados de `user_integrations` e `scheduled_jobs`. Não precisam estar em realtime, mas confirme que os RPCs Vault permanecem restritos ao `service_role`.
|
||
|
||
#### 4. Teste end-to-end
|
||
|
||
1. Acesse `/painel/integracoes` → conecte uma integração (ex: Notion)
|
||
2. Acesse `/painel/cronjobs/nova` → descreva "todo dia útil às 9h, criar uma página no Notion com resumo do dia"
|
||
3. Confirme a revisão (cron + prompt)
|
||
4. A automação deve aparecer ativa em `/painel/cronjobs`
|
||
5. Desconecte a integração Notion → a automação deve aparecer **auto-pausada** com banner no dashboard
|
||
|
||
### O que **não** está nesta fase
|
||
|
||
- ❌ Execução real de cronjobs (Fase 5 — scheduler + Hermes)
|
||
- ❌ Sync Mika ↔ Container (Fase 5)
|
||
- ❌ MCPs corporativos privados / BYOA
|
||
- ❌ Histórico de execuções de cronjobs
|
||
- ❌ Dashboard de uso de API calls
|
||
- ❌ Providers além dos 5 listados
|
||
|
||
---
|
||
|
||
## Fase 5.1 — Provisionamento Railway (parcial: schema + provision-agent + railway-webhook)
|
||
|
||
### O que foi entregue nesta etapa
|
||
|
||
- **Schema**:
|
||
- `vps_pool` (pool de projetos Railway, com `railway_project_id` / `railway_environment_id` placeholders)
|
||
- `provisioning_jobs` (state machine: pending/running/retrying/completed/failed, com retry exponencial `attempt²` minutos)
|
||
- Acréscimos em `agent_instances`: `railway_service_id`, `vps_pool_id`, `provisioned_at`, `last_health_check_at`
|
||
- `vps_host` e `container_name` mantidos como deprecated via comentário
|
||
- `user_roles` + enum `app_role` + função `has_role()` (substitui `is_admin` em profiles, mais seguro)
|
||
- Trigger `on_agent_instance_provisioning` usando `pg_net` chama `provision-agent` quando uma agent_instance entra em status `provisioning`
|
||
- **Edge Functions**:
|
||
- `provision-agent` (verify_jwt=false): cria serviço Docker no Railway via GraphQL API, configura variáveis (TELEGRAM_BOT_TOKEN do Vault, OPENCODE_ZEN_API_KEY, etc.) e dispara deploy. Apaga webhook do Telegram antes (Hermes opera em polling). Retry com backoff exponencial até 5 tentativas.
|
||
- `railway-webhook` (verify_jwt=false): recebe eventos do Railway. SUCCESS → marca agent como `active`; FAILED/CRASHED → marca como `error`.
|
||
- **Helper compartilhado**: `supabase/functions/_shared/railway.ts`
|
||
|
||
### Etapas pós-deploy (uma única vez) — **OBRIGATÓRIAS**
|
||
|
||
#### 1. Criar conta Railway e workspace
|
||
|
||
1. Crie conta em [railway.com](https://railway.com)
|
||
2. Crie um Workspace chamado **"Mika Agents"**
|
||
3. Dentro dele, crie um Projeto chamado **"hermes-agents-prod"** com environment **"production"**
|
||
|
||
#### 2. Gerar Account Token e adicionar como secret
|
||
|
||
1. **Account Settings → Tokens → Create Token** (não confundir com Project Token, precisa ser de conta)
|
||
2. Copie o token e adicione como secret `RAILWAY_API_TOKEN` em Lovable Cloud → Secrets
|
||
3. As Edge Functions já leem `OPENCODE_ZEN_API_KEY` e `OPENCODE_GO_API_KEY` (também precisam estar configurados — já solicitados nesta fase)
|
||
|
||
#### 3. Preencher os IDs do Railway na vps_pool
|
||
|
||
Pegue o `railway_project_id` na URL do projeto (`railway.com/project/<UUID>`) e o `railway_environment_id` em **Project → Settings → Environments → production → Copy ID**, e rode via SQL:
|
||
|
||
```sql
|
||
UPDATE public.vps_pool
|
||
SET railway_project_id = '<UUID-DO-PROJETO>',
|
||
railway_environment_id = '<UUID-DO-ENV-PRODUCTION>'
|
||
WHERE name = 'railway-prod-1';
|
||
```
|
||
|
||
#### 4. Configurar webhook do Railway → Lovable Cloud
|
||
|
||
No Railway: **Project Settings → Webhooks → Add Webhook** e cole:
|
||
|
||
```
|
||
https://smsarmgoirlcedmqvdgc.supabase.co/functions/v1/railway-webhook
|
||
```
|
||
|
||
Tipo: **Deployment status changes** (ou todos).
|
||
|
||
#### 5. Marcar você (Felipe) como admin
|
||
|
||
```sql
|
||
INSERT INTO public.user_roles (user_id, role)
|
||
VALUES ('<SEU_USER_UUID>', 'admin');
|
||
```
|
||
|
||
Pegue seu UUID em **Lovable Cloud → Auth → Users**.
|
||
|
||
### O que ainda falta nesta fase (próxima mensagem)
|
||
|
||
- ❌ Edge Functions `suspend-agent` e `resume-agent`
|
||
- ❌ Botão "Abrir no Telegram" no `/painel` quando `status='active'`
|
||
- ❌ Página `/admin` (lista de agentes, ações suspender/reativar, link Railway, contadores)
|
||
- ❌ Simplificação do wizard de Telegram (capturar só token, sem configurar webhook)
|
||
|
||
### O que **não** está nesta fase (5.1) por design
|
||
|
||
- ❌ Sync de skills/cronjobs/MCPs para o container (Fase 5.2)
|
||
- ❌ Backup de memória antes de desprovisionamento
|
||
- ❌ Múltiplos environments Railway por plano
|
||
- ❌ Auto-scaling
|
||
|
||
### Notas técnicas
|
||
|
||
- Hermes roda em **polling**: o container faz outbound para `api.telegram.org`, sem necessidade de domínio público nem TLS.
|
||
- Após `provision-agent` retornar 200, o Railway leva 1–5 min para puxar a imagem Docker e iniciar. Durante esse tempo, `agent_instance.status` permanece `provisioning`. O webhook do Railway notifica quando o deploy fica `SUCCESS`.
|
||
- A Edge Function `telegram-webhook` (Fase 3) ainda existe mas será desativada na próxima entrega — o polling do Hermes substitui o webhook do Telegram.
|
||
|
||
---
|
||
|
||
## Comandos úteis
|
||
|
||
```bash
|
||
bun dev # dev server (porta 8080)
|
||
bun run build # build de produção
|
||
bun run typecheck
|
||
```
|
||
|