# 数えて、順位をつけて、返答できる機能要望を集める

> 解決策ではなく課題を尋ね、要望をテーマ別に保存し、件数ではなく人数で数え、リリース時にメールで知らせる機能要望フォームです。

公開日 2026-10-25 · https://ikiform.com/ja/guides/feedback-form/feature-request

欲しい機能ではなく、何をしようとしていて今はどうやっているかを尋ね、リリース時に知らせられるようメールアドレスを必須にします。要望は Webhook でテーブルに保存し、テーマごとにタグを付け、困っている人の人数でテーマを順位付けします。テーマをリリースしたら、要望した全員にメールを送ります。

## 機能要望ならではの違い

バグ報告は直せば終わりです。機能要望はデータの 1 点で、同じ不足を多くの人が違う言葉で語っているうちの 1 件です。そこから 3 つのことが言えます。

- **人は解決策を語ります。**「CSV ボタンを追加して」は「経理担当が先月の請求書を必要としている」という意味かもしれません。やりたいことを尋ねれば、要望された方法より良い解決策を選べます。
- **同じニーズが何度も届きます。** Ikiform はすべての送信を保存し、重複をまとめません。そもそも 2 人が同じ言葉を使うことはまれです。要望はテーマごとに自分でまとめ、異なる人の数を数えます。
- **価値はフォローアップにあります。**「ご要望いただいた機能を作りました」と伝えられることこそ、要望を募る一番の理由です。そのためにはすべての要望にメールアドレスが必要なので、このフォームでは必須にしています。

図: 機能要望が、数えられるテーマとリリースのお知らせメールになるまで

1. 利用者がやりたいことを書き、領域と影響度を選び、メールアドレスを残します。
2. Webhook の中継が、送信 ID ごとに 1 回だけ要望をデータベースに挿入します。
3. 毎週、新しい要望に手作業かパターンでテーマのタグを付けます。
4. 既存のテーマに当てはまれば、そのテーマを求める人が 1 人増えます。
5. 当てはまらなければ、新しいテーマになります。
6. テーマをリリースしたら、そのテーマのメールアドレスをすべて選び、メッセージを 1 通送ります。

順位は要望の件数ではなく、テーマごとの人数で決めます。同じ顧客が 5 回要望しても 1 人です。

## 課題を尋ねる

フォーム: Feature request

- **何をしようとしていますか？** (`problem`, textarea, 必須)
- **今はどうやっていますか？** (`workaround`, textarea)
- **製品のどの部分ですか？** (`area`, select, 必須)
- **どのくらい重要ですか？** (`impact`, radio, 必須)
- **メールアドレス** (`email`, email, 必須)

`problem` は 30 文字以上が必要なので、「ダークモードほしい」が理由の入った文になります。

| フィールド | 尋ねる理由 |
| --- | --- |
| `problem` | 本人の言葉で書かれた、やりたいこと。群を抜いて役立つフィールド |
| `workaround` | どれだけ困っているかがわかります。「手作業でスプレッドシートにコピーしている」は強いシグナル |
| `area` | 大まかな一次分類。全体ではなく請求の中でタグ付けできます |
| `impact` | 困っている顧客と興味本位の人を分けます。本人が判断できる結果の形で表現します |
| `email` | 必須。これがないとフォローアップも質問もできません |

優先度や投票のフィールドは入れないでください。誰もが自分の要望を高優先度にしますし、テーマごとの人数のほうがどんなボタンよりも良い投票になります。

## フォーム

このフォームにスクリプトは不要です。送信してリダイレクトするだけです。**Redirect after submit** には、この後どうなるかを書いたページを設定してください。フレームワークでページ内に留まる版が欲しければ、ピラーの[フォームのコード](https://ikiform.com/ja/guides/feedback-form.md#form)を使い、フィールドをこれに差し替えてください。

`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>
```

## 要望を Webhook で保存する

最初の数十件ならダッシュボードと CSV エクスポートで十分です。毎週テーマにタグを付けて人数を数えるようになったら、テーブルのほうが楽です。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
);
```

次に、Ikiform でこのルートを指す [Webhook](https://ikiform.com/ja/docs/webhooks.md) のエンドポイントを追加します。`pg` パッケージがあればどの Node ホストでも動きます。同じパターンは[自分のサーバー](https://ikiform.com/blog/form-submissions-to-your-own-server.md)でさらに詳しく解説しています:

`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` は、エンドポイントの `whsec_` シークレットで署名されていないものをすべて拒否します。
- `on conflict (submission_id) do nothing` でリトライが安全になります。Ikiform は失敗した配信を同じ送信データで再送するので、2 回目の挿入は何もしません。
- データベースのエラーは例外になり、ルートは `500` を返し、Ikiform があとでリトライします。データベースの再起動中でも要望は失われません。
- メールアドレスは受け取る時点で小文字にするので、異なる人数を正しく数えられます。

> Ikiform はメールアドレスで重複する送信をまとめたり拒否したりしません。24 時間以内の同一内容の繰り返しはスパムスコアを上げるだけです。重複はリストの置き場所かエクスポート時に除去してください。

## タグ付けと順位付け

### 新しい要望にタグを付ける

週に 1 回、タグのない行を読んで、それぞれにテーマを付けます。わかりやすいものはパターンで処理できますが、残りは自分で読んでください。興味深い要望ほどパターンには当てはまりません。

`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%']);
```

### テーマを順位付けする

このクエリは、困っていると答えた要望の数でテーマを順位付けし、次に要望した異なる人の数で並べます:

`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. 何かを設計する前に、上位 3 テーマの `problem` の本文をすべて読んでください。
2. 回避策に注目してください。小さな変更 1 つで最悪の部分が解消することもよくあります。
3. 順位は自分の計画と照らし合わせて判断してください。示すのは需要であって、作るべきものではありません。

## フォローアップする

テーマをリリースしたら、それを要望した全員を取り出します:

`notify.sql`:

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

メールツールか自分の受信箱から、何をリリースしたかとそのリンクを書いた短いメールを 1 通送ります。Ikiform はフォームを入力した本人にはメールを送りません。通知メールが届くのはあなたとチームだけなので、自動返信、確認メール、ダブルオプトインはありません。それらは [Webhook](https://ikiform.com/ja/docs/webhooks.md) をきっかけに、自分のメールツールから送ってください。ここでも同じで、リリースのお知らせメールは Ikiform ではなくあなたから送ります。

## 動作を確認する

1. 10 文字の課題で要望を送信します。Ikiform は `problem` を指摘して `422` を返します。
2. 本物の要望を送信します。**Submissions** に表示され、`feature_requests` に行が追加されます。
3. **Webhooks** で配信を再送します。その送信データの行はテーブルに 1 行のままです。
4. 大文字と小文字を変えた同じメールアドレスで 2 回送信します。順位付けのクエリでは 1 人と数えられます。

## ハマりどころ

- Canny のような公開フィードバックボードなら、投票と公開ステータスページが加わります。顧客同士で要望を見せたいならそちらが適したツールです。この構成では要望を非公開に保ちます。
- リンクを複数含む要望はスパム判定されることがあります。件数が少ないうちは毎週 **Spam** フィルターを確認してください。
- あとで `area` の選択肢を追加するなら、先に定義に追加してください。一覧にない値は拒否されます。
- 必要なものだけを保存してください。メールアドレス入りの要望テーブルは個人データです。プライバシーポリシーにそう記載し、不要になった行は削除してください。

## トラブルシューティング

| 問題 | 対処法 |
| --- | --- |
| テーブルに行がない | **Webhooks** でエンドポイントを開きます。`400` ならシークレットが間違っています。データベースのエラー付きの `500` なら挿入に失敗しており、Ikiform がリトライ中です。 |
| `422 validation_failed` | 送信がフォームのフィールド定義に合っていません。`error.fields` に各フィールドと理由が示されます。入力欄の `name` をフィールド ID に合わせてください。 |
| 送信データはダッシュボードにあるのに、メールも Webhook も届かない | スパムとして保存されています。スパムでは何も送られません。**Spam** フィルターで開いて理由を確認し、スパムではないとマークすると、メールと Webhook が送られます。 |

## よくある質問

### 機能要望フォームでは何を尋ねればよいですか？

その人が何をしようとしているか、今はどうやっているか、製品のどの部分に関わるか、どのくらい重要か、そしてメールアドレスです。機能ではなく課題を尋ねることで、より良い解決策を探す余地が生まれます。

### 重複した機能要望はどう扱えばよいですか？

重複は起きるものと考え、行ではなく人を数えてください。各要望にテーマのタグを付け、異なるメールアドレスの数でテーマを順位付けします。Ikiform はすべての送信データを保存し、重複をまとめません。

### ユーザーが機能要望に投票できますか？

フォームだけではできません。フォームは要望を非公開に保ちます。Canny のような公開ボードなら投票が加わります。テーマごとに異なる人数を数えれば、非公開のまま同等のことができます。

### 要望がリリースされたことをどう伝えればよいですか？

各要望にメールアドレスを保存しておき、リリースしたテーマのメールアドレスをすべて選んで、メールツールからメッセージを 1 通送ります。Ikiform 自体は送信者にメールを送りません。

## その他のガイド

- [ウェブサイトやアプリのフィードバックフォーム](https://ikiform.com/ja/guides/feedback-form.md): どのページにもアプリ内にもフィードバックフォームを設置。評価、コメント、送信元ページ、スパム対策、低評価時の通知まで。
- [バグ報告フォーム](https://ikiform.com/ja/guides/feedback-form/bug-report.md): 手順と深刻度は本人に尋ね、URL、ブラウザー、ビューポート、直近のエラーはページが自動で追加するバグ報告フォームです。
- [ベータテスターのフィードバック](https://ikiform.com/ja/guides/feedback-form/beta-tester-feedback.md): テスターとビルドごとの個別リンク、2 つの評価スケール、各ビルドが良くなったかがわかる週次サマリーを備えたベータ版フィードバックフォームです。
- [NPS アンケート](https://ikiform.com/ja/guides/feedback-form/nps-survey.md): メールに 0〜10 のスコアを載せ、スコアに応じて変わる追加質問を自分のページで尋ね、スクリプトで NPS を計算する NPS アンケートを実施します。
- [React フィードバックウィジェット](https://ikiform.com/ja/guides/feedback-form/react-feedback-widget.md): React アプリ用のフローティングのフィードバックボタン。小さなパネルを開き、回答ごとに画面、アプリのバージョン、アカウントを送り、下書きを失いません。
- [解約アンケート](https://ikiform.com/ja/guides/feedback-form/cancellation-survey.md): SaaS の解約フローで解約理由を尋ね、スキップはワンクリックのまま、理由を Stripe と Ikiform に保存し、解約を決して遅らせない方法。
