マキモノ
Web開発無料✅ 公式検証済みv1.0.0 / 更新

アプリ内「不具合・要望」窓口を全アプリへ標準搭載する

利用者がその場で不具合・要望を送れる窓口を、npm依存ゼロ・CSS非依存・DBなしでも動く形で1コマンド後付けする手順。公開サイト向けの濫用対策、2段検証、配布物として崩してはいけない点まで含む。

出品者: kim@orgiast.jp2 DL📖 読込 約3,869トークン (約6円)💰 コスパ 24
トークン節約メーター97%節約
ゼロからAIに作らせた場合9.5万トークン
このMDを読ませた場合2,600トークン

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 のターミナルに貼るだけです。

⬇ .md をダウンロード
claude "https://makimono-md.vercel.app/api/v1/files/md-cfe5ac91/raw を読み込んで、この指示書どおりに実装して"
claude-codecursorcodex-cliライセンス: 商用利用可 (再販不可)

中身

アプリ内「不具合・要望」窓口を全アプリへ標準搭載する

社内 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

フィールド必須備考
kindbug / request
title200 字を超えたら切り詰めて保存(エラーにしない)
body4000 字で切り詰め
page_pathクライアントが現在パスを埋める
screenshotimage/*・8MB まで
companyハニーポット(後述)。人間には見えない欄

レスポンス: { ok: true, id, sinks: { db: boolean, chat: boolean } } / 失敗時 { ok: false, error } と 4xx/5xx。

実装の要点:

  1. 保存先の自動判定: DB の URL とサーバー用キーが env にあれば DB へ insert、無ければスキップ。 通知は Bot API → Webhook の順にフォールバック。片方が成功していれば投稿は成功として返す。 両方不可のときだけ 503 と「保存先が未設定」を返す(黙って捨てない)。
  2. 提出者の特定は best-effort: 認証 Cookie からアクセストークンを取り出してユーザー情報 API に問い合わせる。 取れなければ null未認証サイトでは常に null になる前提で、画面パスと本文で判断できるようにしておく。
  3. 通知本文にアプリ名を必ず入れる([アプリ名] 不具合: タイトル)。複数アプリの通知が同じチャンネルに来るため。
  4. 画像は保存先が無いときチャットへ直接添付する(multipart)。 よくある事故: フォームは添付欄を出しているのに、DB 未設定時だけ画像が黙って捨てられる。 添付付き送信が拒否されたら本文だけで再送する。
  5. 管理画面を入れない構成では、通知に管理画面リンクを出さない(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:0tabIndex={-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 標準モジュールのみで実装する):

  1. package.json でフレームワークを確認し、App Router の位置(src/appapp)とコンポーネント配置先を検出。
  2. tsconfig/jsconfigpaths@/* があるかを判定して import の書き方を決める。 ⚠️ JSON コメント除去の正規表現 /\/\*[\s\S]*?\*\//include"**/*.ts" を「ブロックコメント終端」と誤認して JSON を壊す"@/*" の有無はテキスト照合で判定するのが安全。エイリアスを使う場合は ./ を前置しない(./@/components/... になる事故)。
  3. ファイル配置(既存があれば --force なしでは上書きしない=冪等)。
  4. レイアウトへウィジェットを1行注入。import は 先頭ディレクティブ("use client" 等)の後・既存 import の直後に入れる(先頭行に入れるとディレクティブより前に来てビルドが壊れる)。 自動注入に失敗したら中止せず、挿入すべき1行と対象ファイルの絶対パスを出力する。
  5. マイグレーションは既存連番の最大+1で書き出し、CLI や DB 接続文字列があれば自動適用。 できない場合は SQL 全文+管理コンソールの直リンク+完了判定(「Success. No rows returned と出れば完了」)を出す。
  6. env の不足分だけを、取得方法(vercel env add <NAME> production 等の完全なコマンド)付きで表示する。 既にある値は「OK」と出すだけで再入力を求めない
  7. 最後に「変更ファイル一覧 / 残作業 / 検証コマンド」をチェックリストで出す。--dry-run で何もせず予定だけ出せるようにする。

配布物として崩してはいけない点

  • 取得先は ブランチ参照(main など)にしてコミットハッシュで固定しない。固定すると改善のたびに全員へ URL 差し替えを頼むことになる。
  • テンプレートは全件取得してから書き込む。1件ずつ取得→即書き込みだと、途中でネットワークが 5xx を返したとき 「API だけ入ってコンポーネントが無い」中途半端な状態が導入先に残る(実際に踏む)。
  • 取得は 429/5xx とネットワーク例外に対して指数バックオフで数回リトライ(404 は即失敗)。
  • raw 配信は push 直後に古い版を返すことがある。配布前に「利用者が実際に叩く URL」を取得して新機能の目印を grep し、反映を確認してから配布する。
  • 型注釈を正規表現で剥がして JS 版を生成しようとしないresponse: Responseurl: 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. 運用フロー

  1. 利用者がアプリ内から投稿 → チャットに即通知(担当者が見るチャンネル)。
  2. 開発側は未対応キューを取得するスクリプト(status in (new, triaged, in_progress) を JSON 出力)で拾う。 DB を使っていないアプリでは例外を投げずに「キューはチャットを見ること」と案内して正常終了させる。
  3. 実装 → デプロイ → statusdone にし、resolved_ref に PR/commit を記録。
  4. 自由記述をそのまま自動実装に流さない。任意の利用者のテキストが本番コードを無人で書き換える経路を作らないこと(レビュー 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で頼むだけで、仕事が完成」。

AI代行堂を見る →

関連する巻物

この巻物、誰かのトークンも救えます

𝕏 で節約レシートをシェア