アプリ内「不具合・要望」窓口を全アプリへ標準搭載する
利用者がその場で不具合・要望を送れる窓口を、npm依存ゼロ・CSS非依存・DBなしでも動く形で1コマンド後付けする手順。公開サイト向けの濫用対策、2段検証、配布物として崩してはいけない点まで含む。
約9.2万トークンの節約 (API料金換算で約140円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「アプリ内「不具合・要望」窓口を全アプリへ標準搭載する」は、Web開発カテゴリのAI指示書(MDファイル)です。利用者がその場で不具合・要望を送れる窓口を、npm依存ゼロ・CSS非依存・DBなしでも動く形で1コマンド後付けする手順。公開サイト向けの濫用対策、2段検証、配布物として崩してはいけない点まで含む。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約9.2万トークン(API料金換算で約140円)・97%のトークンを節約できます。
- カテゴリ
- Web開発
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約9.5万トークン
- この巻物使用時
- 約2,600トークン
- 節約量
- 約9.2万トークン (約140円)
- 更新日
- 2026-08-20
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-cfe5ac91/raw を読み込んで、この指示書どおりに実装して"
中身
アプリ内「不具合・要望」窓口を全アプリへ標準搭載する
社内 Web アプリに、利用者がその場で不具合・要望を送れる窓口を 1コマンドで後付けするための指示書。 「利用者 → 管理者 → 開発者」の口頭・チャット伝言を廃止し、報告が構造化データとチャット通知として自動で届く状態にする。
対象: Next.js App Router のアプリ(Pages Router / Remix / Vite でも API 仕様は流用可)。 前提: DB は任意(無い場合はチャット通知のみで動く)。追加の npm パッケージは入れない。
1. 設計原則(ここを崩すと横展開できなくなる)
| 原則 | 理由 |
|---|---|
追加 npm 依存ゼロ(DB/Storage/Auth は REST を fetch で直叩き) | アプリごとに依存が違っても入る。npm i を要求した時点で「後で入れる」になり普及しない |
| CSS フレームワーク非依存(ウィジェットは inline style で自己完結) | Tailwind 前提や独自トークン前提だと、入れた先で見た目が崩れる |
Server Action など特定機能に依存しない(素の API Route + fetch) | フレームワークのバージョン差・構成差で壊れない |
| 保存先が無くても動く(DB あり → DB+通知 / DB なし → 通知のみ) | 「DB が無いから入れられない」を消す。公開サイトや静的寄りのアプリにも入る |
| 導入は1コマンド、検証も1コマンド | 人手の作業を残すと未導入アプリが残り続ける |
2. データモデル(DB を使う場合)
create table if not exists app_feedback (
id uuid primary key default gen_random_uuid(),
kind text not null default 'bug' check (kind in ('bug','request')),
title text not null,
body text not null,
page_path text, -- 提出時の画面パス。再現の手がかりとして必須級
submitter text,
submitter_email text,
status text not null default 'new' check (status in ('new','triaged','in_progress','done','rejected')),
priority text not null default 'normal' check (priority in ('low','normal','high')),
admin_note text,
resolved_ref text, -- 対応した PR / commit / URL
screenshot_path text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists app_feedback_status_idx on app_feedback (status, created_at desc);
create table if not exists/add column if not exists/on conflict do nothing/drop policy if existsを使い 何度実行しても安全にする(同じ SQL を別環境で何度も流すため)。gen_random_uuid()を使う(uuid_generate_v4()は拡張が入っていない環境で落ちる)。- 画像は非公開バケットに置き、閲覧は期限付き署名URLで渡す。テーブルは RLS を有効化し、アプリからの読み書きはサーバー側の管理キーだけに限定する。
3. API 仕様(POST /api/feedback)
リクエスト: multipart/form-data
| フィールド | 必須 | 備考 |
|---|---|---|
kind | ✔ | bug / request |
title | ✔ | 200 字を超えたら切り詰めて保存(エラーにしない) |
body | ✔ | 4000 字で切り詰め |
page_path | – | クライアントが現在パスを埋める |
screenshot | – | image/*・8MB まで |
company | – | ハニーポット(後述)。人間には見えない欄 |
レスポンス: { ok: true, id, sinks: { db: boolean, chat: boolean } } /
失敗時 { ok: false, error } と 4xx/5xx。
実装の要点:
- 保存先の自動判定: DB の URL とサーバー用キーが env にあれば DB へ insert、無ければスキップ。 通知は Bot API → Webhook の順にフォールバック。片方が成功していれば投稿は成功として返す。 両方不可のときだけ 503 と「保存先が未設定」を返す(黙って捨てない)。
- 提出者の特定は best-effort: 認証 Cookie からアクセストークンを取り出してユーザー情報 API に問い合わせる。
取れなければ
null。未認証サイトでは常に null になる前提で、画面パスと本文で判断できるようにしておく。 - 通知本文にアプリ名を必ず入れる(
[アプリ名] 不具合: タイトル)。複数アプリの通知が同じチャンネルに来るため。 - 画像は保存先が無いときチャットへ直接添付する(multipart)。 よくある事故: フォームは添付欄を出しているのに、DB 未設定時だけ画像が黙って捨てられる。 添付付き送信が拒否されたら本文だけで再送する。
- 管理画面を入れない構成では、通知に管理画面リンクを出さない(404 に誘導してしまう)。 ビルド時のフラグ置換で出し入れする。
4. ウィジェット要件
- 右下固定の浮遊ボタン → 中央モーダル。
role="dialog"aria-modal、Escape で閉じる、外部イベント(open-feedbackのようなカスタムイベント)でも開けるようにしてサイドバー等からも呼べる。 - 種別 select / タイトル / 本文 / 画像(任意)。モーダル内で Ctrl+V の貼り付けから画像を添付できると報告率が上がる(クリップボードの画像を
DataTransferで file input に流し込む)。 - 送信中はボタンを disable、成功でモーダルを閉じてトースト、失敗時はモーダルを閉じずエラーを表示。
- ⚠️ 重大な落とし穴: React のイベントハンドラで
awaitをまたいでevent.currentTargetを触るとnullになる。 送信後にevent.currentTarget.reset()を呼ぶと TypeError が自分の catch に落ち、 投稿は成功しているのに「送信に失敗しました」と表示される。ハンドラ冒頭でconst form = event.currentTargetを捕捉する。
5. 公開サイト(未認証で誰でも POST できる)に置く場合
常時有効にしておく(社内アプリでも副作用は無い):
- ハニーポット: 人間に見えない入力欄を1つ置き、埋まっていたら保存も通知もせず成功レスポンスを返す(bot に弾いたと悟らせない)。
display:noneは見抜かれるので、画面外配置+opacity:0+tabIndex={-1}+aria-hiddenにする。 - レート制限: 送信元 IP(
x-forwarded-forの先頭)単位で「10分あたり5件」程度。超過は 429 と案内文。 上限は env で変更可能にする。 ⚠️ サーバーレスでは実行インスタンスごとの計数になるので厳密ではない。厳密に止めたいなら CDN/WAF 側のレート制限を併用する(この限界をドキュメントに明記して過信を防ぐ)。 - 入力長の上限(前述)と画像サイズ上限。
- 管理一覧を置くなら必ず認証で守る。認証機構が無いアプリでは管理画面を入れず、通知とキュー取得スクリプトで運用する。
6. 1コマンド導入インストーラの作り方
配布リポジトリに置いたインストーラを、導入先のリポジトリ直下でダウンロード実行する形にする。
node -e "fetch('<配布リポジトリのraw URL>/install.mjs?cb='+Date.now()).then(r=>r.text()).then(t=>require('fs').writeFileSync('install-feedback.mjs',t))" \
&& node install-feedback.mjs --app-name "<アプリ名>"
インストーラがやること(Node 標準モジュールのみで実装する):
package.jsonでフレームワークを確認し、App Router の位置(src/app→app)とコンポーネント配置先を検出。tsconfig/jsconfigのpathsに@/*があるかを判定して import の書き方を決める。 ⚠️ JSON コメント除去の正規表現/\/\*[\s\S]*?\*\//はincludeの"**/*.ts"を「ブロックコメント終端」と誤認して JSON を壊す。"@/*"の有無はテキスト照合で判定するのが安全。エイリアスを使う場合は./を前置しない(./@/components/...になる事故)。- ファイル配置(既存があれば
--forceなしでは上書きしない=冪等)。 - レイアウトへウィジェットを1行注入。import は
先頭ディレクティブ(
"use client"等)の後・既存 import の直後に入れる(先頭行に入れるとディレクティブより前に来てビルドが壊れる)。 自動注入に失敗したら中止せず、挿入すべき1行と対象ファイルの絶対パスを出力する。 - マイグレーションは既存連番の最大+1で書き出し、CLI や DB 接続文字列があれば自動適用。 できない場合は SQL 全文+管理コンソールの直リンク+完了判定(「Success. No rows returned と出れば完了」)を出す。
- env の不足分だけを、取得方法(
vercel env add <NAME> production等の完全なコマンド)付きで表示する。 既にある値は「OK」と出すだけで再入力を求めない。 - 最後に「変更ファイル一覧 / 残作業 / 検証コマンド」をチェックリストで出す。
--dry-runで何もせず予定だけ出せるようにする。
配布物として崩してはいけない点
- 取得先は ブランチ参照(
mainなど)にしてコミットハッシュで固定しない。固定すると改善のたびに全員へ URL 差し替えを頼むことになる。 - テンプレートは全件取得してから書き込む。1件ずつ取得→即書き込みだと、途中でネットワークが 5xx を返したとき 「API だけ入ってコンポーネントが無い」中途半端な状態が導入先に残る(実際に踏む)。
- 取得は 429/5xx とネットワーク例外に対して指数バックオフで数回リトライ(404 は即失敗)。
- raw 配信は push 直後に古い版を返すことがある。配布前に「利用者が実際に叩く URL」を取得して新機能の目印を grep し、反映を確認してから配布する。
- 型注釈を正規表現で剥がして JS 版を生成しようとしない(
response: Responseやurl: stringを取りこぼして構文エラーのファイルを書く)。 TypeScript のまま置き、非 TS リポジトリではフレームワークの自動セットアップに任せる方が安全。
7. 導入後の検証(ここまでやって初めて「完了」)
Layer1: 実際にリクエストを飛ばす
- 起動したアプリへ multipart で実投稿し、
ok/sinksを確認。 - 保存先のモックまたは実 DB で read-back(本当に行が入ったか)。通知は受信側のペイロードを捕獲して 「種別・アプリ名・画面パス・画像リンク(または添付ファイル名)」が入っているか突き合わせる。
- 必須未入力が 400、ハニーポットが「成功レスポンス+保存0件」、レート制限が上限超で 429 になることを確認。
Layer2: 実ブラウザで描画と操作
- 浮遊ボタンが表示され、コンテンツを隠していないか(座標を取得して判定)。
- モーダルが開く → 入力 → 送信 → 成功トースト → モーダルが閉じる。Escape で閉じる。
- コンソールエラー0件を条件に入れる。
検証スクリプトの落とし穴
- モックサーバーはプロセス内にログを保持するため、ログファイルを消しても前のテストのデータが残る。 各テストは「自分が投稿したタイトル」で対象を選別する(先頭の1件を取ると別テストのデータを検証してしまう)。
- 開発サーバーは
127.0.0.1由来のアクセスを別オリジン扱いして静的アセットを 403 にすることがある。 ブラウザ検証はlocalhostで叩く。 - テスト行は削除せず、状態を「却下」+メモ付きにして残す(破壊的操作を避け、後から検証履歴を追える)。
8. 運用フロー
- 利用者がアプリ内から投稿 → チャットに即通知(担当者が見るチャンネル)。
- 開発側は未対応キューを取得するスクリプト(
status in (new, triaged, in_progress)を JSON 出力)で拾う。 DB を使っていないアプリでは例外を投げずに「キューはチャットを見ること」と案内して正常終了させる。 - 実装 → デプロイ →
statusをdoneにし、resolved_refに PR/commit を記録。 - 自由記述をそのまま自動実装に流さない。任意の利用者のテキストが本番コードを無人で書き換える経路を作らないこと(レビュー or 人のトリガーを必ず挟む)。
9. 通知先の資格情報を配る時
- Bot トークンのような広い権限の秘密を各端末へ配らない。管理者側の権限で 「そのチャンネルへ投稿するだけの Webhook」を API 作成し、その URL だけを配る(権限の最小化)。
- 既存の Webhook があれば作り直さず再利用する(重複作成を避ける)。作成後にテスト投稿して疎通確認し、その投稿は削除する。
- 複数端末へ配る仕組みがあるなら、そこへ載せて受け取り側の手作業をゼロにする。 秘密を1本足すたびに既存の配布内容を書き直さずに済むよう、追加分は別枠にマージする設計にしておく (暗号化された設定値は読み戻せないことが多く、全体の再構成は事故のもと)。
よくある質問
+「アプリ内「不具合・要望」窓口を全アプリへ標準搭載する」とは何ですか?
利用者がその場で不具合・要望を送れる窓口を、npm依存ゼロ・CSS非依存・DBなしでも動く形で1コマンド後付けする手順。公開サイト向けの濫用対策、2段検証、配布物として崩してはいけない点まで含む。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約9.5万トークンかかりますが、この巻物を使えば約2,600トークンで済みます。差し引き約9.2万トークン(API料金換算で約140円)・97%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
Next.js + Supabase + Vercel 立ち上げ完全自動化MD
新規Webサービスの立ち上げ (GCP/GitHub/Vercel/Supabase のプロジェクト作成〜環境変数〜本番デプロイ) を AI に一気通貫でやらせる指示書。人間の作業はログイン1回だけ。
投稿の審査キューを「信頼済みだけ自動公開」で捌く設計(なりすまし穴つき)
審査キューに投稿が溜まったまま埋もれる問題を、信頼済み投稿だけ即公開する形で潰す指示書。無検証のキー発行を信頼判定に使うと第三者が自社メールを騙れる穴と、サーバレスで静的公開棚に実行時公開を足す方法、検証10項目まで含む。
DB型サイトを「一覧だけ会員限定・個別ページは残す」に切り替える指示書(Next.js App Router)
自社DBで集客していたサイトが競合のリスト抜き取りに気づいた時の改修手順。名前が並ぶバルクな一覧だけを会員限定にし、個別ページはtitle/H1とCTAを残す。ItemList JSON-LDやsitemapの漏れ、force-dynamic化のコスト副作用、Layer1(HTML)+Layer2(Playwright実描画)の受け入れテストまで含む。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア