# 02 — PRD: SDD Bot do Slack

worktree: SDDL-2
branch-raiz: main

**Orquestração:** SDDL-2 — SDD Bot do Slack
**Data:** 2026-06-24
**Agente:** prd
**Estado:** approved — CP-1 aprovado em 2026-06-24
**Artifact store:** `.worktree/SDDL-2/docs/sddl-2/`

---

## Rastreabilidade

| Campo | Valor |
|---|---|
| Origem (ideia) | `docs/sddl-2/01-idea.md` |
| Project Discovery | `docs/sddl-2/00-project-discovery.md` |
| Risk Classification | `docs/sddl-2/00-risk-classification.md` — Nível: ALTO |
| Próximo artefato | `docs/sddl-2/03-techspec.md` |
| Checkpoint | CP-1 — aprovação humana obrigatória |

---

## 1. Resumo Executivo

O SDD Bot do Slack é um agente conversacional que expõe o fluxo Spec-Driven Development diretamente em canais Slack. Elimina a necessidade de alternar entre Slack, Jira e terminal para criar, acompanhar e aprovar demandas. Via comandos `/bot`, o usuário cria cards Jira, dispara o orquestrador SDD automaticamente até o PRD, recebe o conteúdo de cada etapa como mensagem efêmera ou arquivo no Slack, e aprova o card sem sair do ambiente de mensagens.

---

## 2. Objetivos

| # | Objetivo | Métrica de sucesso |
|---|---|---|
| O-1 | Criar cards Jira e disparar orquestrador sem sair do Slack | 100% dos `/bot create` resultam em card Jira + execução até PRD |
| O-2 | Exibir conteúdo de cada etapa gerada no Slack | Cada etapa emite ao menos uma mensagem ephemeral ao criador |
| O-3 | Gate `/bloqueado` impede avanço automático | 100% dos casos bloqueados quando último comentário Jira é `/bloqueado` |
| O-4 | Restringir operações ao criador do card | 100% das tentativas não autorizadas retornam acesso negado |
| O-5 | Consulta offline via SQLite | `/bot view` retorna conteúdo sem nova chamada à IA |

---

## 3. Não Objetivos (fora do MVP)

- Múltiplos aprovadores por card
- Edição de artefatos via Slack
- Integração com Confluence
- Interface web ou dashboard
- Múltiplos workspaces Slack por instância
- Histórico de versões de artefatos
- Migração automática de schema SQLite (versão 2+)

---

## 4. Personas

| Persona | Papel | Frequência |
|---|---|---|
| P-1 — Desenvolvedor/Tech Lead | Cria demandas, acompanha etapas, aprova PRDs | Diária |
| P-2 — Membro da equipe | Visualiza e gerencia somente seus próprios cards | Diária |
| P-3 — Administrador | Instala e configura o bot via `sdd bot install` | Pontual |

---

## 5. Fluxos Principais

### 5.1 — `/bot create`

1. Usuário executa `/bot create <texto>` no canal Slack
2. Bot faz `ack()` em até 3 s e confirma recebimento
3. Bot lê `key: PROJ` do tópico/descrição do canal
4. Bot chama LLM para gerar título (máx. 100 chars)
5. Bot cria card Jira com título gerado e descrição original
6. Bot persiste no SQLite: `card_id`, `slack_user_id`, `canal`, `texto_original`, `titulo`, `status = "em_progresso"`
7. Bot adiciona comentário `/bloqueado` no card Jira
8. Bot dispara `sdd orchestrator <CARD-ID>` assincronamente
9. Para cada etapa (risk, idea, prd):
   - Envia ephemeral: "gerando `<etapa>`..."
   - Ao concluir: envia conteúdo como ephemeral; se > 3.000 chars → envia como arquivo
   - Persiste conteúdo da etapa no SQLite vinculado ao `card_id`

### 5.2 — `/bot update`

1. Verifica ownership (SQLite). Se não for criador → acesso negado
2. Atualiza descrição do card Jira
3. Adiciona `/bloqueado` no Jira; atualiza SQLite com novo texto e `status = "em_progresso"`
4. Dispara orquestrador e segue subfluxo 5.1 passo 9

### 5.3 — `/bot aproved`

1. Verifica ownership. Se não for criador → acesso negado
2. Adiciona comentário `/aprovado` no Jira
3. Atualiza SQLite: `status = "aprovado"`
4. Envia confirmação ephemeral ao usuário

### 5.4 — `/bot list`

1. Consulta SQLite por `slack_user_id = <executor>` e `status != "aprovado"`
2. Retorna lista: `CARD-ID — título`
3. Se vazio → mensagem informativa

### 5.5 — `/bot view`

1. Verifica ownership. Se não for criador → acesso negado
2. Consulta SQLite pelos conteúdos das etapas do `card_id`
3. Retorna conteúdo; se > 3.000 chars → arquivo
4. **Nenhuma chamada à IA**

### 5.6 — Gate `/bloqueado` no sdd-layer

1. `sdd orchestrator` recebe argumento no padrão `[A-Z]+-[0-9]+` (Card ID)
2. Consulta Jira REST: obtém último comentário do card
3. Se último comentário = `/bloqueado` (exato, case-sensitive) → aborta com erro não-zero + mensagem descritiva
4. Bot captura o erro → envia ephemeral explicativo ao criador
5. Texto livre como argumento **não dispara** a verificação

---

## 6. Requisitos Funcionais

### 6.1 Bot Slack — Comandos

| ID | Requisito |
|---|---|
| RF-01 | Bot responde ao slash command `/bot create <texto>` |
| RF-02 | `ack()` em até 3 s; processamento assíncrono após ack |
| RF-03 | Extrai `key: PROJ` do tópico/descrição do canal (case-insensitive). Sem key → erro orientativo |
| RF-04 | Chama LLM para gerar título (máx. 100 chars) a partir do texto |
| RF-05 | Cria card Jira com título LLM e descrição original |
| RF-06 | Adiciona comentário `/bloqueado` no card antes de disparar o orquestrador |
| RF-07 | Persiste no SQLite: `card_id`, `slack_user_id`, `slack_channel_id`, `texto_original`, `titulo`, `status`, `criado_em`, `atualizado_em` |
| RF-08 | Dispara `sdd orchestrator <CARD-ID>` assincronamente |
| RF-09 | Envia ephemeral "gerando `<etapa>`..." a cada etapa iniciada |
| RF-10 | Envia conteúdo gerado ao concluir cada etapa; se > 3.000 chars → arquivo |
| RF-11 | Persiste conteúdo de cada etapa no SQLite vinculado ao `card_id` |
| RF-12 | `/bot update`: verifica ownership, atualiza Jira, adiciona `/bloqueado`, re-executa orquestrador e **atualiza SQLite** com novo texto/status |
| RF-13 | `/bot aproved`: verifica ownership, adiciona `/aprovado` no Jira, atualiza SQLite |
| RF-14 | `/bot list`: retorna cards do usuário executor com `status != "aprovado"` via SQLite |
| RF-15 | `/bot view`: retorna conteúdo das etapas via SQLite; sem chamada à IA |
| RF-16 | Acesso negado com mensagem amigável quando `slack_user_id` não é o criador do card |

### 6.2 Gate `/bloqueado` — sdd-layer (CLI Rust)

| ID | Requisito |
|---|---|
| RF-17 | `sdd orchestrator` com argumento Card ID consulta Jira REST para obter último comentário antes de iniciar |
| RF-18 | Último comentário corresponde a `/bloqueado` (case-insensitive, regex `^\/bloqueado$` com flag `i`) → aborta com erro não-zero e mensagem descritiva |
| RF-19 | Verificação só ocorre para padrão `[A-Z]+-[0-9]+`; texto livre não consulta Jira |
| RF-20 | Bot captura o erro de gate e envia ephemeral explicativo ao criador |

### 6.3 Instalador e Limpeza

| ID | Requisito |
|---|---|
| RF-21 | `sdd bot install` guia interativamente a geração de `sdd-bot.config.yaml` |
| RF-22 | Instalador verifica `.gitignore` e emite aviso se `sdd-bot.config.yaml` não estiver listado |
| RF-23 | Instalador verifica se `sdd` está no PATH do ambiente e emite aviso se não estiver |
| RF-24 | Amarrações do bot antigo em `sdd install` / `sdd orchestrator` são removidas sem quebrar comandos CLI existentes |

---

## 7. Requisitos Não Funcionais

| ID | Requisito |
|---|---|
| RNF-01 | `ack()` em até 3 s em 99% dos comandos Slack |
| RNF-02 | Bot suporta reinicialização pm2 sem perda de dados SQLite |
| RNF-03 | Tokens nunca commitados; `sdd-bot.config.yaml` no `.gitignore`; instalador valida |
| RNF-04 | Validação HMAC-SHA256 de todos os payloads Slack; rejeição com HTTP 401 se inválido |
| RNF-05 | Mensagens de texto respeitam 3.000 chars por bloco (limite do Block Kit Slack); conteúdo de artefatos/docs enviado sempre como arquivo (sem limite prático de tamanho no Slack) |
| RNF-06 | SQLite acessado por instância única do bot; lock de arquivo em produção |
| RNF-07 | Log estruturado de todas as operações relevantes (criação, gate, aprovação) |
| RNF-08 | Falhas de API (Jira, Slack) capturadas e comunicadas ao usuário; bot não crasha |
| RNF-09 | Consultas SQLite retornam em < 500 ms para até 10.000 cards |

---

## 8. Regras de Negócio

| ID | Regra |
|---|---|
| RN-01 | Criador = `slack_user_id` de quem executou `/bot create`. Somente ele opera o card |
| RN-02 | Gate `/bloqueado` lê apenas o último comentário Jira; verificação **case-insensitive**: qualquer variação de capitalização de "bloqueado" após "/" ativa o gate (ex: `/bloqueado`, `/BLOQUEADO`, `/Bloqueado`, `/BloquEado`) |
| RN-03 | `/bot create` e `/bot update` sempre adicionam `/bloqueado` antes de disparar o orquestrador |
| RN-04 | Chave de projeto extraída via `key: PROJ` no tópico/descrição do canal |
| RN-05 | Conteúdo de etapas armazenado no SQLite durante execução; `/bot view` consulta exclusivamente o SQLite |
| RN-06 | `/bot list` filtra por `slack_user_id = executor` e `status != "aprovado"` |
| RN-07 | Gate só se aplica a argumento Card ID (`[A-Z]+-[0-9]+`) |
| RN-08 | Título gerado pelo LLM a partir do texto; original preservado como descrição do card |
| RN-09 | Conteúdo > 3.000 chars → enviado como arquivo Slack |

---

## 9. Estados do Sistema

### Card (SQLite)

| Estado | Transições |
|---|---|
| `em_progresso` | → `aprovado` via `/bot aproved`; → `em_progresso` via `/bot update` |
| `aprovado` | Estado terminal no MVP |

### Gate Jira (último comentário)

| Último comentário | Comportamento |
|---|---|
| `/bloqueado` | Aborta execução do orquestrador |
| `/aprovado` | Permite execução |
| Qualquer outro | Permite execução |
| Nenhum | Permite execução |

---

## 10. Critérios de Aceite (Gherkin)

### CA-01 — Criar card com sucesso

```gherkin
Dado que o canal tem "key: PROJ" configurado no tópico
Quando o usuário executa "/bot create Implementar autenticação OAuth"
Então o bot responde com ack em até 3 segundos
E um card é criado no Jira no projeto "PROJ" com título gerado pelo LLM
E o último comentário do card Jira é "/bloqueado"
E o card é registrado no SQLite com status "em_progresso" e o slack_user_id do criador
E o bot envia ephemeral "gerando risk..." ao criador
E ao concluir risk, envia o conteúdo como ephemeral ou arquivo
E o bot envia ephemeral "gerando idea..." ao criador
E ao concluir idea, envia o conteúdo como ephemeral ou arquivo
E o bot envia ephemeral "gerando prd..." ao criador
E ao concluir prd, envia o conteúdo como ephemeral ou arquivo
```

### CA-02 — Canal sem chave de projeto

```gherkin
Dado que o canal não tem "key:" configurado
Quando o usuário executa "/bot create Qualquer texto"
Então o bot retorna mensagem orientando a configurar "key: PROJ" no tópico do canal
E nenhum card é criado no Jira
```

### CA-03 — Atualizar card como criador

```gherkin
Dado que existe card "PROJ-42" criado pelo usuário "U001"
E o último comentário do card é "/aprovado"
Quando "U001" executa "/bot update PROJ-42 Nova descrição"
Então o bot verifica que "U001" é o criador via SQLite
E atualiza a descrição do card Jira
E adiciona "/bloqueado" no card Jira
E atualiza SQLite com novo texto e status "em_progresso"
E dispara o orquestrador com novo contexto
E envia progresso ephemeral por etapa ao usuário
```

### CA-04 — Acesso negado para card de outro usuário

```gherkin
Dado que existe card "PROJ-42" criado pelo usuário "U001"
Quando "U002" executa qualquer comando sobre "PROJ-42" (/bot update, /bot aproved, /bot view)
Então o bot retorna mensagem amigável de acesso negado ao usuário "U002"
E nenhuma alteração é feita no Jira ou SQLite
```

### CA-05 — Aprovar card como criador

```gherkin
Dado que existe card "PROJ-42" com status "em_progresso" criado por "U001"
Quando "U001" executa "/bot aproved PROJ-42"
Então o bot adiciona comentário "/aprovado" no Jira
E atualiza SQLite: status = "aprovado"
E retorna confirmação ephemeral ao usuário
```

### CA-06 — Listar cards pessoais

```gherkin
Dado que "U001" tem cards "PROJ-10" (em_progresso), "PROJ-11" (em_progresso), "PROJ-12" (aprovado)
E "U002" tem card "PROJ-13" (em_progresso)
Quando "U001" executa "/bot list"
Então retorna "PROJ-10" e "PROJ-11"
E "PROJ-12" não aparece (aprovado)
E "PROJ-13" não aparece (outro usuário)
```

### CA-07 — Visualizar card como criador (sem IA)

```gherkin
Dado que card "PROJ-42" foi criado por "U001" com conteúdo de etapas no SQLite
Quando "U001" executa "/bot view PROJ-42"
Então o bot retorna o conteúdo das etapas do SQLite
E nenhuma chamada à IA é realizada
```

### CA-08 — Gate `/bloqueado` bloqueia orquestrador

```gherkin
Dado que o último comentário do card Jira "PROJ-42" é "/bloqueado"
Quando "sdd orchestrator PROJ-42" é executado
Então o orquestrador consulta Jira e lê o último comentário
E aborta com código de erro não-zero
E o bot captura o erro e envia ephemeral ao criador informando o bloqueio
E nenhuma etapa é executada
```

### CA-09 — Gate não bloqueia quando último comentário não é `/bloqueado`

```gherkin
Dado que o último comentário do card "PROJ-42" é "/aprovado"
Quando "sdd orchestrator PROJ-42" é executado
Então o orquestrador permite e inicia as etapas normalmente
```

### CA-10 — Gate não se aplica a texto livre

```gherkin
Dado que "sdd orchestrator" recebe argumento "implementar feature de login"
Quando o orquestrador processa
Então não consulta o Jira
E executa normalmente sem verificação de gate
```

### CA-11 — Conteúdo longo enviado como arquivo

```gherkin
Dado que o conteúdo de uma etapa tem mais de 3.000 caracteres
Quando o bot tenta enviar ao usuário
Então envia como arquivo no Slack
E não tenta enviar como texto inline
```

### CA-12 — Secrets fora do repositório

```gherkin
Dado que o administrador executa "sdd bot install"
Quando o instalador conclui
Então verifica se "sdd-bot.config.yaml" está no ".gitignore"
E emite aviso de segurança se não estiver
```

### CA-13 — Payload Slack inválido rejeitado

```gherkin
Dado que o bot recebe payload com assinatura HMAC-SHA256 inválida
Quando o handler processa
Então rejeita com HTTP 401
E nenhum processamento de comando é iniciado
```

---

## 11. Dependências e Integrações

| Sistema | Uso | Permissões |
|---|---|---|
| Slack API (Socket Mode) | Receber comandos, enviar ephemeral, upload de arquivo | `commands`, `chat:write`, `files:write`, `users:read` |
| Slack App Token (`xapp-...`) | Autenticação Socket Mode | — |
| Slack Bot Token (`xoxb-...`) | Chamadas REST Slack | — |
| Jira REST API | Criar card, comentar, ler último comentário | `create issue`, `add comment`, `read comments` |
| Provider LLM | Gerar título e conteúdo de etapas | API Key |
| CLI `sdd` (binário Rust) | Executar `sdd orchestrator <CARD-ID>` | Binário no PATH |
| SQLite | Armazenar cards, ownership, conteúdo de etapas | Permissão de escrita local |
| pm2 | Daemon em produção | — |

---

## 12. Restrições

| ID | Restrição |
|---|---|
| REST-01 | `sdd-bot.config.yaml` nunca commitado; gerado localmente via instalador |
| REST-02 | `ack()` em até 3 s; processamentos longos são assíncronos |
| REST-03 | Somente o criador do card (via `slack_user_id` no SQLite) opera aquele card |
| REST-04 | `/bot view` não faz chamadas à IA — consulta exclusivamente o SQLite |
| REST-05 | Gate `/bloqueado` lê somente o último comentário Jira |
| REST-06 | Gate só ativado para Card ID no padrão `[A-Z]+-[0-9]+` |
| REST-07 | Conteúdo > 3.000 chars enviado como arquivo Slack |

---

## 13. Diagrama — Fluxo do Gate `/bloqueado`

```mermaid
flowchart TD
    A[sdd orchestrator recebe argumento] --> B{É Card ID?\npadrão A-Z+-0-9+}
    B -- Não --> C[Executa normalmente\nsem verificação de gate]
    B -- Sim --> D[Consulta Jira REST\nLê último comentário do card]
    D --> E{Último comentário\n= /bloqueado?}
    E -- Sim --> F[Aborta execução\nErro não-zero + mensagem]
    F --> G[Bot envia ephemeral\nao criador: card bloqueado]
    E -- Não --> H[Permite execução\nInicia etapas do orquestrador]
    H --> I[Para cada etapa:\ngerando etapa... + conteúdo]
```

---

## 14. Diagrama — Estados do Card

```mermaid
stateDiagram-v2
    [*] --> em_progresso : /bot create
    em_progresso --> em_progresso : /bot update
    em_progresso --> aprovado : /bot aproved
    aprovado --> [*]

    note right of em_progresso
        Gate /bloqueado ativo no Jira
        Aparece em /bot list
    end note

    note right of aprovado
        Comentário /aprovado no Jira
        Não aparece em /bot list
    end note
```
