> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kazzle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Automações

> Agende tarefas e responda a webhooks dentro de um app Kazzle.

Automações são as partes de um app que rodam por conta própria — em um cronograma, ou quando um serviço externo envia um evento.

Você as declara em um componente process em `kazzle.config.ts`. Um componente pode ter quantos triggers você precisar.

## A estrutura

```ts theme={"theme":"material-theme-darker"}
{
  name: 'events',
  type: 'process',
  path: './components/events/index.ts',
  processMode: 'persistent', // ou 'triggered'
  triggers: [
    { name: 'daily-digest', kind: 'schedule', schedule: '0 9 * * *', path: '/cron/daily-digest' },
    { name: 'stripe',       kind: 'webhook',                          path: '/webhook/stripe' },
  ],
}
```

Duas coisas estão acontecendo aqui:

* `processMode` escolhe o **ciclo de vida** — servidor de longa duração, ou uma execução única por trigger.
* `triggers[]` lista os **eventos** que devem disparar este componente.

Os dois são independentes. Um servidor persistente pode ter um cron. Um processo efêmero pode ter um webhook. Escolha o ciclo de vida que se adequa à carga de trabalho e anexe quantos triggers quiser.

## `processMode`

| Modo                  | O que roda                                                         | Quando usar                                                                                                 |
| --------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `persistent` (padrão) | Um servidor HTTP de longa duração. Triggers são POSTados para ele. | O componente já serve HTTP, ou mantém estado em memória (filas, websockets, caches).                        |
| `triggered`           | O script de entrada é executado por trigger e sai.                 | Tarefas de background puro — limpeza noturna, handler único de webhook Stripe, etc. Sem servidores ociosos. |

## Triggers

Cada trigger tem um `name` (único dentro do componente), um `kind`, e — dependendo do modo — um `schedule` e/ou `path`.

| Campo      | Quando obrigatório                 | Notas                                                       |
| ---------- | ---------------------------------- | ----------------------------------------------------------- |
| `name`     | sempre                             | Usado no segmento da URL do webhook e em logs. Kebab-case.  |
| `kind`     | sempre                             | `'schedule'` ou `'webhook'`.                                |
| `schedule` | quando `kind: 'schedule'`          | Expressão cron de 5 campos. Resolução de minuto é o mínimo. |
| `path`     | quando `processMode: 'persistent'` | Rota HTTP no seu servidor onde o trigger chega.             |

## Modo persistente — HTTP para o servidor

Quando um trigger dispara para um componente persistente, Kazzle faz POST no seu servidor no `path` declarado. A requisição carrega:

| Header                                           | O que informa                                       |
| ------------------------------------------------ | --------------------------------------------------- |
| `Authorization: Bearer ${KAZZLE_TRIGGER_SECRET}` | Valide isto. Rejeite chamadas que não correspondem. |
| `x-kazzle-trigger-name`                          | O `name` do trigger do manifesto.                   |
| `x-kazzle-trigger-run-id`                        | ID opaco para correlação de logs.                   |
| `x-kazzle-triggered-by`                          | `cron` \| `webhook` \| `manual`.                    |

Para triggers de webhook, o corpo da requisição original é encaminhado como corpo do POST. Para triggers de cronograma o corpo está vazio.

```ts theme={"theme":"material-theme-darker"}
// components/events/index.ts (modo persistente)
const TRIGGER_SECRET = process.env.KAZZLE_TRIGGER_SECRET ?? '';

Bun.serve({
  port: Number(process.env.PORT),
  hostname: process.env.HOST,
  async fetch(req) {
    const url = new URL(req.url);

    if (req.method === 'POST' && url.pathname === '/cron/daily-digest') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      await sendDigest();
      return Response.json({ ok: true });
    }

    if (req.method === 'POST' && url.pathname === '/webhook/stripe') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      const event = await req.json();
      await handleStripe(event);
      return Response.json({ ok: true });
    }

    return new Response('not found', { status: 404 });
  },
});
```

## Modo triggered — uma execução por trigger

Quando um trigger dispara para um componente `triggered`, Kazzle executa o script de entrada do zero e aguarda sua saída. Não há `path`; o script aprende qual trigger disparou através de variáveis de ambiente.

| Variável de ambiente | Valor                                    |
| -------------------- | ---------------------------------------- |
| `TRIGGER_NAME`       | O `name` do trigger do manifesto.        |
| `TRIGGERED_BY`       | `cron` \| `webhook` \| `manual`.         |
| `RUN_ID`             | ID opaco para correlação de logs.        |
| `WEBHOOK_PAYLOAD`    | Corpo JSON (apenas triggers de webhook). |

```ts theme={"theme":"material-theme-darker"}
// components/events/index.ts (modo triggered)
const trigger = process.env.TRIGGER_NAME;
const runId = process.env.RUN_ID;

if (trigger === 'daily-digest') {
  await sendDigest();
} else if (trigger === 'stripe') {
  const event = JSON.parse(process.env.WEBHOOK_PAYLOAD ?? '{}');
  await handleStripe(event);
}

console.log(`run ${runId} done`);
```

Componentes triggered não têm máquinas ociosas em produção — eles iniciam por chamada e desligam na saída.

## URLs de webhook

```text theme={"theme":"material-theme-darker"}
POST https://api.kazzle.app/webhooks/{spaceId}/{appId}/{componentName}/{triggerName}
```

O segmento `triggerName` deve corresponder a uma entrada `kind: 'webhook'` em `triggers[]` daquele componente. Nomes de trigger desconhecidos retornam 404.

## Resolução de cronograma

Expressões cron são de 5 campos (minuto, hora, dia do mês, mês, dia da semana) e resolução de minuto é o mínimo. Cronogramas sub-minuto são rejeitados na validação do manifesto.

## Como as execuções são registradas

Cada disparo de trigger escreve uma linha `process_runs` com `trigger_name`, `triggered_by`, `run_id` e o status de saída da execução. Você pode consultá-las do seu próprio código ou inspecioná-las na visualização de execuções do app.

## Ficando sem créditos

Uma execução com falha é registrada e registrada em log, mas o cronograma continua rodando em seu ritmo normal — uma execução instável nunca desativa o trigger. A única coisa que para uma execução é créditos: cada disparo de trigger é verificado contra o saldo do espaço, e enquanto o espaço está sem créditos (ou não tem cobrança configurada) as execuções são puladas com um `402`. Isto é auto-recuperável — o cronograma permanece armado e o próximo disparo após você recarregar roda normalmente, sem retomada manual.

## Adicionando automações depois

Um app simples pode começar sem triggers e ganhá-los depois — adicione um resumo diário, conecte Stripe, execute limpeza. O ciclo de vida do componente (`processMode`) e triggers (`triggers[]`) são independentes, então você pode alterá-los sem reescrever o resto do app.
