# Colete pedidos de funcionalidades que você consegue contar, priorizar e responder

> Um formulário de pedido de funcionalidade que pergunta pelo problema em vez da solução, armazena pedidos por tema, conta pessoas, não linhas, e avisa quando sair.

Publicado em 2026-10-25 · https://ikiform.com/pt-br/guides/feedback-form/feature-request

Pergunte o que a pessoa está tentando fazer e como faz isso hoje, não qual funcionalidade ela quer, e exija um e-mail para poder avisá-la quando sair. Armazene cada pedido numa tabela via webhook, agrupe os pedidos em temas e priorize os temas por quantas pessoas diferentes estão bloqueadas. Quando um tema sair, mande e-mail para todos que pediram.

## O que muda nos pedidos de funcionalidades

Um relato de bug está resolvido quando é corrigido. Um pedido de funcionalidade é um dado: uma de muitas pessoas descrevendo a mesma lacuna com palavras diferentes. Daí vêm três coisas:

- **As pessoas descrevem soluções.** "Adicionem um botão de CSV" pode querer dizer "meu contador precisa das faturas do mês passado". Pergunte pela tarefa, e você pode escolher uma solução melhor do que a pedida.
- **A mesma necessidade chega muitas vezes.** O Ikiform armazena todo envio e não junta repetições, e duas pessoas raramente usam as mesmas palavras de qualquer forma. Você mesmo agrupa os pedidos, por tema, e conta pessoas distintas.
- **O valor está no retorno.** Dizer a alguém "você pediu, nós fizemos" é o melhor motivo para perguntar. Isso exige um e-mail em todo pedido, então este formulário o torna obrigatório.

Diagrama: Como um pedido de funcionalidade vira um tema contado e um e-mail de lançamento

1. Alguém descreve o que está tentando fazer, escolhe uma área e um impacto e deixa um e-mail.
2. Um relay de webhook insere o pedido no seu banco de dados, uma vez por id de envio.
3. Toda semana você marca os pedidos novos com um tema, à mão ou com um padrão.
4. Se ele se encaixa num tema existente, esse tema agora tem mais uma pessoa por trás.
5. Se não, ele começa um tema novo.
6. Quando um tema sai, você seleciona todos os e-mails dele e envia uma única mensagem.

A prioridade é pessoas por tema, não pedidos brutos. Um cliente pedindo cinco vezes continua sendo um cliente.

## Pergunte pelo problema

Formulário: Feature request

- **O que você está tentando fazer?** (`problem`, textarea, obrigatório)
- **Como você faz isso hoje?** (`workaround`, textarea)
- **Qual parte do produto?** (`area`, select, obrigatório)
- **O quanto isso importa?** (`impact`, radio, obrigatório)
- **E-mail** (`email`, email, obrigatório)

`problem` tem um mínimo de 30 caracteres, o que transforma "modo escuro pfv" numa frase com um motivo.

| Campo | Por que está aí |
| --- | --- |
| `problem` | A tarefa a ser feita, nas palavras da pessoa. De longe o campo mais útil |
| `workaround` | Mostra o quanto dói. "Copio à mão para uma planilha" é um sinal forte |
| `area` | Uma primeira triagem grosseira, para você marcar dentro de cobrança, não no meio de tudo |
| `impact` | Separa clientes bloqueados de curiosos, formulado como resultados que as pessoas sabem avaliar |
| `email` | Obrigatório. Sem ele você não consegue fechar o ciclo nem fazer uma pergunta |

Deixe de fora um campo de prioridade ou de voto. Todo mundo marca o próprio pedido como alta prioridade, e a contagem de pessoas por tema é um voto melhor que qualquer botão.

## O formulário

O formulário não precisa de script: ele envia e redireciona. Defina **Redirect after submit** para uma página que diga o que acontece em seguida. Para uma versão que fica na página no seu framework, pegue o [código do formulário](https://ikiform.com/pt-br/guides/feedback-form.md#form) do guia principal e troque pelos campos abaixo.

`feature-request.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="problem">What are you trying to do?</label>
  <textarea id="problem" name="problem" rows="5" required minlength="30"
    placeholder="Send last month's invoices to our accountant in one go"></textarea>
  <label for="workaround">How do you do it today?</label>
  <textarea id="workaround" name="workaround" rows="3"></textarea>
  <label for="area">Which part of the product?</label>
  <select id="area" name="area" required>
    <option value="billing">Billing and invoices</option>
    <option value="reports">Reports</option>
    <option value="team">Team and permissions</option>
    <option value="integrations">Integrations and API</option>
    <option value="other">Something else</option>
  </select>
  <fieldset>
    <legend>How much does it matter?</legend>
    <label><input type="radio" name="impact" value="blocking" required /> It stops us using the product for something</label>
    <label><input type="radio" name="impact" value="slow" /> It costs us time every week</label>
    <label><input type="radio" name="impact" value="nice" /> It would be nice</label>
  </fieldset>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send request</button>
</form>
```

## Armazene os pedidos via webhook

O painel e a exportação CSV funcionam para as primeiras dezenas de pedidos. Quando você estiver marcando temas e contando pessoas toda semana, uma tabela é mais fácil. Crie uma no Postgres:

`schema.sql`:

```text
create table feature_requests (
  submission_id text primary key,
  area text not null,
  impact text not null,
  problem text not null,
  workaround text,
  email text not null,
  theme text,
  created_at timestamptz not null
);
```

Depois adicione um endpoint de [webhook](https://ikiform.com/pt-br/docs/webhooks.md) no Ikiform apontando para esta rota. Ela roda em qualquer host Node com o pacote `pg`, e [seu próprio servidor](https://ikiform.com/blog/form-submissions-to-your-own-server.md) cobre o mesmo padrão com mais detalhes:

`app/api/feature-requests/route.ts`:

```ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { Pool } from "pg";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

const INSERT = `insert into feature_requests (submission_id, area, impact, problem, workaround, email, created_at)
values ($1, $2, $3, $4, $5, lower($6), $7)
on conflict (submission_id) do nothing`;

export async function POST(request: Request) {
  const payload = await request.text();
  let event;
  try {
    event = await verifyWebhook({
      payload,
      headers: request.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
    throw error;
  }
  if (event.type !== "submission.created") return new Response(null, { status: 204 });

  const { problem, workaround, area, impact, email } = event.data.fields;
  await pool.query(INSERT, [
    event.data.submission_id,
    area,
    impact,
    problem,
    workaround ?? null,
    email,
    event.data.created_at,
  ]);
  return new Response(null, { status: 204 });
}
```

- `verifyWebhook` rejeita tudo o que não foi assinado com o secret `whsec_` do seu endpoint.
- `on conflict (submission_id) do nothing` torna as novas tentativas seguras. O Ikiform reenvia uma entrega que falhou com o mesmo envio, e o segundo insert não faz nada.
- Um erro no banco de dados lança uma exceção, a rota responde `500` e o Ikiform tenta de novo depois. Você não perde pedidos durante um restart do banco.
- O e-mail é convertido para minúsculas na entrada, então a contagem de pessoas distintas funciona.

> O Ikiform não junta nem rejeita envios repetidos por e-mail. Uma repetição idêntica em até 24 horas só soma à pontuação de spam. Remova os duplicados onde a lista fica, ou ao exportar.

## Marque e priorize

### Marque os pedidos novos

Uma vez por semana, leia as linhas sem tema e dê um tema a cada uma. Padrões resolvem os óbvios; leia o resto você mesmo, porque os pedidos interessantes não batem com um padrão.

`tag.sql`:

```text
update feature_requests
set theme = 'invoice-export'
where theme is null
  and area = 'billing'
  and problem ilike any (array['%export%', '%accountant%', '%download%']);
```

### Priorize os temas

Isto ordena os temas por quantos pedidos dizem estar bloqueados e depois por quantas pessoas diferentes pediram:

`ranking.sql`:

```text
select coalesce(theme, 'untagged') as theme,
       count(*) as requests,
       count(distinct email) as people,
       count(*) filter (where impact = 'blocking') as blocking
from feature_requests
group by 1
order by blocking desc, people desc;
```

1. Leia por inteiro os textos de `problem` dos três primeiros temas antes de desenhar qualquer coisa.
2. Olhe as alternativas que as pessoas usam. Muitas vezes uma pequena mudança remove a pior parte.
3. Pese a prioridade contra o seu plano; ela mostra demanda, não o que é certo construir.

## Feche o ciclo

Quando um tema sair, puxe todos que pediram por ele:

`notify.sql`:

```text
select distinct email
from feature_requests
where theme = 'invoice-export';
```

Envie um e-mail curto pela sua ferramenta de e-mail ou da sua própria caixa de entrada, dizendo o que saiu e com um link. O Ikiform não envia e-mail para quem preenche o formulário. Os e-mails de notificação vão só para você e sua equipe, então não há resposta automática, e-mail de confirmação nem double opt-in. Envie isso pela sua ferramenta de e-mail, disparada por um [webhook](https://ikiform.com/pt-br/docs/webhooks.md). O mesmo vale aqui: o e-mail de lançamento vem de você, não do Ikiform.

## Confira se funciona

1. Envie um pedido com um problema de 10 caracteres. O Ikiform responde `422` apontando `problem`.
2. Envie um pedido real. Ele aparece em **Submissions** e como uma linha em `feature_requests`.
3. Em **Webhooks**, reenvie a entrega. A tabela continua com uma única linha para esse envio.
4. Envie duas vezes com o mesmo e-mail em maiúsculas e minúsculas diferentes. A consulta de prioridade conta uma pessoa.

## Pegadinhas

- Um quadro público de feedback, como o Canny, adiciona votação e uma página pública de status. Se você quer que os clientes vejam os pedidos uns dos outros, essa é a ferramenta melhor; esta configuração mantém os pedidos privados.
- Pedidos com vários links podem ser pontuados como spam. Confira o filtro **Spam** toda semana enquanto o volume for baixo.
- Se você adicionar uma opção de `area` depois, adicione-a primeiro na definição. Um valor que não está na lista é recusado.
- Armazene o que você precisa e nada mais. Uma tabela de pedidos com e-mails é dado pessoal; diga isso no seu aviso de privacidade e apague as linhas de que não precisa mais.

## Solução de problemas

| Problema | O que fazer |
| --- | --- |
| Linhas faltando na tabela | Abra o endpoint em **Webhooks**. Um `400` significa que o secret está errado; um `500` com erro de banco de dados significa que o insert falhou e o Ikiform está tentando de novo. |
| `422 validation_failed` | O envio não corresponde à definição de campos do formulário. `error.fields` aponta cada campo e o motivo. Faça o `name` do input bater com o id do campo. |
| O envio está no painel, mas nenhum e-mail ou webhook chegou | Ele foi armazenado como spam. Spam não envia nada. Abra-o no filtro **Spam** para ver os motivos e marque-o como não spam para enviar o e-mail e os webhooks dele. |

## Perguntas

### O que um formulário de pedido de funcionalidade deve perguntar?

O que a pessoa está tentando fazer, como faz isso hoje, qual parte do produto isso envolve, o quanto importa e um e-mail. Perguntar pelo problema em vez da funcionalidade dá espaço para encontrar uma solução melhor.

### Como lido com pedidos de funcionalidade duplicados?

Conte com eles e conte pessoas, não linhas. Marque cada pedido com um tema e priorize os temas por e-mails distintos. O Ikiform armazena todos os envios e não junta repetições.

### Os usuários podem votar em pedidos de funcionalidades?

Não só com um formulário. Um formulário mantém os pedidos privados; um quadro público como o Canny adiciona votação. Contar pessoas distintas por tema dá um equivalente privado.

### Como aviso as pessoas quando o pedido delas sai?

Guarde o e-mail junto com cada pedido, selecione todos os e-mails do tema que saiu e envie uma única mensagem pela sua ferramenta de e-mail. O Ikiform não envia e-mail para quem preencheu o formulário.

## Mais guias

- [Formulário de feedback para um site ou app](https://ikiform.com/pt-br/guides/feedback-form.md): Coloque um formulário de feedback em qualquer página ou dentro do seu app: uma nota, um comentário, a página de origem, filtro de spam e alertas para notas baixas.
- [Formulário de relato de bug](https://ikiform.com/pt-br/guides/feedback-form/bug-report.md): Um formulário de relato de bug que pede às pessoas os passos e a gravidade, e deixa a página adicionar sozinha a URL, o navegador, o viewport e os erros recentes.
- [Feedback de beta testers](https://ikiform.com/pt-br/guides/feedback-form/beta-tester-feedback.md): Um formulário de feedback de beta com um link pessoal por tester e build, duas escalas de nota e um resumo semanal que mostra se cada build melhorou.
- [Pesquisa NPS](https://ikiform.com/pt-br/guides/feedback-form/nps-survey.md): Rode uma pesquisa NPS com a nota de 0 a 10 no e-mail, uma pergunta de acompanhamento na sua própria página que muda com a nota e um script que calcula o NPS.
- [Widget de feedback em React](https://ikiform.com/pt-br/guides/feedback-form/react-feedback-widget.md): Um botão de feedback flutuante para um app React que abre um pequeno painel, envia a tela, a versão do app e a conta com cada resposta e nunca perde um rascunho.
- [Pesquisa de cancelamento](https://ikiform.com/pt-br/guides/feedback-form/cancellation-survey.md): Pergunte por que os clientes cancelam dentro do fluxo de cancelamento do seu SaaS, deixe o Pular a um clique, salve o motivo no Stripe e no Ikiform e nunca atrase o cancelamento.
