ChatGPT WorkとCodexでオンライン便利ツール集を開発した話――15ツールを支える設計と検証
CSVを編集する、画像を軽くする、文字コードを変える、ZIPを作る。こうした作業をブラウザから行えるWebツール集「JIN Web Tools」を、ChatGPTのWorkとCodexを使って開発しています。
公開サイトは、事務人(jim-jin.com)です。2026年9月の開発・検証時点で、CSV、文章、画像、ZIPなどを扱う15ツールが掲載されています。
開発を進めるなかで、技術的に面白かったのは、ツール数が増え、会話が変わっても、同じ仕様を維持して開発を続ける仕組みでした。
たとえば、50万行のCSVが約4.4MBしかないのに読み込めない。Undoで表の値は戻るのに、編集欄には古い値が残る。共通処理を高速化したいが、利用者ごとの権限判定までキャッシュしてはいけない。
この記事では、WorkとCodexを使った開発の流れと、その過程で直面した設計・検証上の課題を紹介します。
1. 作ったものと、開発の前提
JIN Web Toolsは、WordPress上で動くツール群です。サイトの表示にはSWELLを使い、個別の機能はWordPressプラグインとして実装しています。
代表的なツールは、CSVエディター、Excel・CSV結合・分割、画像形式変換、オンラインスクリーンショットなどです。記事の最後に15ツールのリンクをまとめています。
利用者として想定しているのは、パソコンの専門知識を前提としない事務担当者です。そのため、変換処理だけでなく、ファイルを選んでから保存するまでの手順、エラー時の案内、スマートフォンでの表示も開発対象にしました。
技術面では、主に次の構成になっています。
| 領域 | 構成・役割 |
|---|---|
| サイト・管理画面 | WordPress、SWELL、PHP |
| 個別ツール | プラグイン、ショートコード、JavaScript |
| 共通基盤 | JIN Web Tools Core(JWTC) |
| 共通UI | JWDSの設計とCore Toolkitの共通部品 |
| ブラウザ内処理 | CSV・文字列などの処理、必要に応じたWeb Worker |
| サーバー処理 | 画像変換・軽量化、Webページ撮影など |
| 継続開発 | Git、仕様書、ツール台帳、自動テスト、配布ZIP |
処理場所はツールごとに異なります。CSVや文字列をブラウザ内で扱う設計と、画像やWebページをサーバーで処理する設計を、同じ共通基盤の上に載せています。
2. Workで工程を進め、Codexでリポジトリを育てる
今回の使い方を振り返ると、役割はおおむね次のように整理できます。
| 担当 | 今回の開発で担ったこと |
|---|---|
| 人間 | 作る目的、利用者、仕様の採否、変更範囲、公開判断 |
| ChatGPT Work | 要件・設計の整理、工程ごとの実装・検証、成果物や管理文書の作成 |
| Codex | 既存コードの調査、リポジトリ上の実装・修正、テスト、差分・配布物の確認 |
これは今回の運用上の分担です。Workにもコードを実行して成果物を作る機能があり、初期の共通基盤開発では実装・検証まで進めています。利用できるファイルやツールは、ローカル・クラウドの実行場所や権限によって変わります。ChatGPT Workの公式概要
初期段階では、共通基盤を機能単位の工程に分け、仕様書、ソースZIP、導入用ZIP、検証ログを作成して、Google Driveに保存する流れでした。
その後、個別ツールの追加や修正が増えるにつれて、現在の仕様と進捗をGitリポジトリに集め、Codexがそこから再開できる形へ整えていきました。
実際に、過去工程の再検証を進めたところ、正式な管理文書はすでに後続工程まで進んでいたことがあります。そのときは現在地を古い工程へ戻さず、再検証の成果物を履歴として保存しました。
この経験からも、「この会話で何をしていたか」と「プロジェクトが現在どこまで進んでいるか」は、別々に確認する必要があると感じました。
3. 個別ツールを増やす前に、共通基盤を作る
CSV編集と画像変換では、処理内容は大きく違います。一方で、管理メニュー、設定、利用者区分、利用上限、手順表示などには共通する部分があります。
そこで、JWTC、共通UI、プラグインテンプレートの順に基盤を整え、個別ツールへ展開しました。共通UIでは、デザイントークンやCSSの適用範囲、WordPress・SWELLとの競合回避も設計に含めています。
役割を簡略化すると、次の構成です。
共通化したのは、管理メニュー、プラン表示名、環境診断、番号付き手順などです。変換・集計の本体、個別の上限値、固有の画面状態は各ツールに残しました。
ここで考えたのが、共通基盤が使えないときの動作です。
各ツールは公開APIを介してCoreを利用し、Coreが未導入・旧版・異常な場合には、同梱部品へフォールバックする構成にしています。利用制限の判定も、安全側の無料設定へ戻す方針です。
ただし、同梱部品を各ツールで手修正すると、すぐに差分が増えてしまいます。そのため、共通部品の変更元をCoreに置き、同梱版はそこから生成し、同期状態を機械的に検査する方式にしました。
共通化によって、通常動作だけでなく、Core停止時の動作、API互換性、配布物の同期まで管理対象になります。この部分は、ツールを増やした後の保守に効いてきます。
4. AIへの引き継ぎを、ファイルとコマンドにする
継続開発のため、各ツールに次の文書を持たせています。
| ファイル | 記録するもの |
|---|---|
SPEC.md |
目的、機能、対象外、受入条件 |
CURRENT_STATE.md |
現在の版、完了したこと、次に行うこと |
DECISIONS.md |
設計判断と、その理由 |
TEST.md |
検証方法、確認範囲、結果 |
KNOWN_ISSUES.md |
既知の問題、未確認事項 |
TODO.md |
未着手の候補 |
CHANGELOG.md |
版ごとの変更内容 |
全体にはregistry/tools.jsonを置き、各ツールのバージョン、状態、ブランチ、PR、互換性を管理します。作業規則はAGENTS.mdにまとめました。
Codexは作業時にAGENTS.mdを読み、プロジェクトに応じた指示を取り込めます。一方、上記の仕様書や台帳は、このプロジェクトで定めた管理方式です。AGENTS.mdの公式説明
再開と検証のためのコマンドも用意しました。
# 対象ツールの現在地を確認
bash bin/start-tool.sh jin-character-counter
# ツール台帳などの整合性を検査
node bin/jin-tools.mjs validate
# 共通部品と各ツールへの同梱版が一致するか検査
node bin/sync-toolkit.mjs --check
新規ツールの生成時には、プラグインの雛形に加えて標準文書、専用CI、台帳登録まで作るようにしています。
引き継ぎの入口が決まると、依頼も対象と変更内容に集中できます。次は、この運用を記事用に短く整理した例です。
対象Tool ID: jin-character-counter
変更内容: 絵文字を含む場合の文字数内訳を修正したい。
リポジトリの作業規則と対象ツールの仕様・現在地を確認し、
原因、変更範囲、受入条件を提示してください。
合意した範囲で実装・検証し、仕様、テスト結果、既知問題、
変更履歴、台帳まで更新してください。
実行していない確認は、未実施として報告してください。
この方式の利点は、会話を変えたときだけでなく、人間が後から読む場合にも、判断の根拠と未完了の作業を追えることです。
5. 50万行CSVで発覚した、短いコードの落とし穴
Excel・CSV結合・分割の検証では、表示上の上限内にある50万行CSVを読み込むと、次のエラーが発生しました。
Maximum call stack size exceeded
再現用データは、見出しを含めて500,000行、2列、4,388,895バイト。ファイル容量だけを見ると約4.4MBです。
原因を切り分けると、CSV解析自体は成功していました。止まっていたのは、解析後の表の最大列数を求める処理です。
const width = Math.max(
1,
...rows.map((row) => Array.isArray(row) ? row.length : 0)
);
各行の列数を配列にし、スプレッド構文でMath.maxの引数へ展開しています。行が50万なら、引数は500,001個になります。
少量データでは問題が見えにくい一方、この入力では実行環境の関数呼び出しの限界に達していました。失敗する正確な行数は環境に依存するため、「何万行以下なら安全」と固定値で捉えないほうがよい箇所です。
修正版では、次の共通関数を使うようにしました。
export function maxColumnCount(rows, minimum = 0) {
let width = minimum;
for (const row of rows) {
width = Math.max(width, Array.isArray(row) ? row.length : 0);
}
return width;
}
両方とも行数に対してO(n)の走査ですが、修正版は行数分の引数と、列数を並べた中間配列を作りません。この計算部分で必要な追加領域はO(1)です。
さらに調べると、同じパターンが次の4箇所にありました。
- 読み込み後のテーブル化
- プレビュー
- 分割結果一覧
- Excel出力
最初の読み込みだけ直しても、後工程で再び止まり得ます。そのため、4箇所を共通関数へ置き換え、保存まで確認しました。
修正前は追加した大量行テスト4件が失敗し、修正後は既存分を含む20件が成功しています。50万行CSVの分割では、ZIPから取り出した全499,999データ行の値と順序まで照合しました。
この件で学んだのは、「最大50万行」と仕様に書いたら、検証もその規模で行う必要があるということです。小さなサンプルでの成功だけでは、受入条件を満たしたとはいえません。
なお、この修正版の確認はローカル自動テストです。配布用JavaScriptと実際のCSV解析・分割・ZIP処理を使っていますが、DOMなどにはテスト用の代替を使っています。修正報告時点では、本番反映と実ブラウザでの最終確認は未実施です。
6. Undoでは「データが戻る」だけでは足りなかった
CSVエディターでは、別の種類の問題も見つかりました。
セルを書き換えて「元に戻す」を押すと、表の値は元へ戻ります。しかし、選択セルを編集する入力欄には、変更後の値が残っていました。
状態を並べると、問題が分かりやすくなります。
| 場所 | Undo後に期待する値 | 不具合時の値 |
|---|---|---|
| 内部データ | 日本語 | 日本語 |
| 表のセル | 日本語 | 日本語 |
| セル編集欄 | 日本語 | JIN_QA_EDIT |
内部モデルのUndoだけをテストすると、成功に見える可能性があります。しかし利用者は、同じセルについて異なる値を見せられます。残った編集欄を再操作すると、取り消した値を再び適用し得る状態でした。
修正版では、Undo・Redoなどの明示的な操作後に、選択セルの確定値を編集欄へ同期させました。一方で、通常の再描画では入力途中の文字を壊さないようにしています。セル移動時も、旧セルの入力確定と移動先の表示を順番に処理する必要がありました。
ここでは、データ、選択位置、編集中の値、保存状態を一つの操作として検証することがポイントでした。修正版のJavaScript自動テスト44件は成功していますが、こちらも修正報告時点の結果はローカルでの確認です。
7. 100ツール以上を見据えた、共通初期化の高速化
ツール数が増えると、ページを開くたびに繰り返す共通処理も気になってきます。そこで、Coreのツール定義検証を見直しました。
方針は、変更のない定義について、正常な静的検証結果を再利用することです。
ただし、利用者ごとの権限・プラン判定と、ツール定義の静的な検証は分けています。今回のキャッシュには利用者別の判定を保存しません。
主な設計条件は次のとおりです。
- 定義の内容ハッシュに加え、Coreや検証実装、実行環境の違いを識別する。
- パス、読み取り上限、文字コード、JSONなどの確認は毎回行う。
- 警告・エラーのある静的検証結果は保存しない。
- キャッシュが欠落・破損した場合は、通常の厳格な検証へ戻る。
- 通常のキャッシュヒットでは、保存処理を繰り返さない。
ローカルWordPress環境で、通常ページのサーバー側生成時間を測定した結果がこちらです。
| 登録ツール数(Coreを除く) | 変更前の中央値 | 変更後の中央値 | 短縮率 |
|---|---|---|---|
| 16 | 14.54ms | 13.11ms | 9.8% |
| 100相当 | 32.39ms | 21.98ms | 32.1% |
| 150相当 | 43.05ms | 26.99ms | 37.3% |
測定環境はWordPress 7.1、PHP 8.3.33、OPcache、MariaDB 11.4、最小構成のテーマと合成データです。各ケース31サンプルを測定しています。
16件には公開15ツールに加えてテンプレートを含み、100・150相当の追加分には、実際の定義を使う登録専用の模擬プラグインを使いました。本番のSWELL、他社プラグイン、ネットワークを含むページ表示速度の測定ではありません。
また、通常ページのDB読み取りは1回増えています。クエリ数だけを指標にすると悪化に見えますが、この環境では検証処理の削減によって生成時間が短くなりました。
変更前後では、既存16対象の生成HTMLと登録結果も照合しています。速度に加えて、同じ入力・設定で既存の結果を維持することを確認対象にしました。
この改善でプラグイン数に対する負荷が一定になるわけではありません。初回や更新直後の検証、各プラグイン本体の読み込みなどのコストは残ります。
8. データの扱いも、ツールごとの仕様に含める
ファイルを扱うサービスでは、どこで処理し、どこに残るのかが設計上の重要な条件になります。
今回も、ツールの構成に合わせて、処理場所と保存方法を明文化しました。
| 例 | 設計上の扱い |
|---|---|
| CSVエディター・文字コード変換 | ファイル内容をブラウザ内で処理 |
| 画像形式変換 | サイトの非公開一時領域へ画像を送って処理 |
| 画像軽量化 | 必要に応じてサーバー処理とブラウザ処理を利用 |
| オンラインスクリーンショット | サーバーから入力URLへアクセスし、撮影結果を一時保存 |
ブラウザ内処理の「ファイル内容を送信しない」という方針は、ページ表示や会員機能を含めて通信が一切ないという意味ではありません。
サーバー処理では、入力・出力ファイルの一時保存場所、アクセス制御、終了時の削除、中断時の清掃、ログに残す情報まで仕様に含めました。
画像形式変換では、作成から60分で利用不能にし、残存データは次回の自動清掃で物理削除する設計です。「利用不能になる時点」と「ディスク上から削除される時点」を区別すると、画面の説明と運用の確認項目も具体的になります。
この種の条件は、AIへ実装を依頼するときにも有効でした。「データを適切に扱う」だけで終わらせず、何を送るか、何を残さないか、いつ削除するかを、実装と検証の項目にできます。
9. 完了条件に、文書と配布物を含める
今回の開発では、変更内容に応じて、次の層を分けて確認しています。
| 検証の層 | 確認すること |
|---|---|
| 処理ロジック | 入出力、境界値、大量データ、文字や順序の保持 |
| 画面の状態 | 入力、選択、Undo、エラー、保存案内の整合性 |
| 共通基盤との接続 | Core有効・無効・旧版・異常時の動作 |
| 静的解析・互換性 | PHP構文、PHPStan、Coding Standards、対象PHP版 |
| 実環境 | WordPress、テーマ、認証、ブラウザ、サーバー依存機能 |
| 配布物 | ZIP内のファイル、バージョン、ソースとの一致、SHA-256 |
WordPressプラグインとして配布する以上、ソースを修正しただけでは終わりません。配布用JavaScriptを再生成したか、ZIPに必要なファイルが入っているか、開発依存やログが混ざっていないかも確認します。
そして、テスト結果と同じくらい大切なのが、未実施の項目です。実行環境にPHPがない、サーバー依存機能を確認できない、実ブラウザで再テストしていない場合は、その事実を残します。
作業の終点を、次のように定義するようになりました。
実装の更新
→ 対象範囲の検証
→ 仕様・現在地・既知問題・台帳の更新
→ 配布物の作成と照合
→ 未確認事項を含めて報告
初期の基盤整備には、個別機能を作る以外の手間もかかりました。また、今回、開発時間やAI利用料金の削減率は測定していません。
そのうえで得られたのは、次の変更を始めるときに「何が完成し、何をまだ確認していないか」を読み取れる開発の土台です。Workで工程と成果物を整理し、Codexで実装・検証・文書を更新する。その往復を、ファイルに残せるようになりました。
10. 公開しているツール
事務人(jim-jin.com)で、以下のツールを公開しています。
| 分野 | ツール |
|---|---|
| CSV・表データ | CSVエディター |
| CSV・表データ | Excel・CSV取込前チェック |
| CSV・表データ | Excel・CSV結合・分割 |
| テキスト | 文字コード変換 |
| テキスト | 文章・ファイルの違い比較 |
| テキスト | 文字数カウント |
| テキスト | 英数字 全角・半角統一 |
| ZIP | ZIP圧縮 |
| ZIP | ZIP解凍 |
| 色 | Webスポイト |
| 色 | カラーピッカー |
| 画像 | 撮影情報(EXIF)確認・編集 |
| 画像 | 画像軽量化 |
| 画像 | 画像形式変換 |
| Webページ | オンラインスクリーンショット |
利用上限や対応形式、データの扱いは、各ツールの画面で確認できます。この記事で紹介した修正版の検証状況と、公開サイトへの反映状況は別に管理しています。
CSVの先頭ゼロ、絵文字の数え方、画像の向き、保存後のファイル。小さなツールにも、実データを通して初めて分かる課題があります。気になるツールを触っていただき、具体的な入力条件や操作手順とともにフィードバックをいただけるとうれしいです。
公開URLは既存の実サイト検証・掲載資料と照合しています。今回のアクセス再確認はブラウザ側の制限で未実施です。