PWAアプリビルダー は何をしますか?
プロジェクトのアイデアを、初日から本番環境で動作するアプリに変換します。ローカルで実行され、電話にインストールでき、オフラインで動作し、通知を送信し、公開リンクで共有できます。以下のスタックは意図的に固定されています。これらのプロジェクトが動作するホストの制約(コンパイラなし、約300MBのRAM、Postgres/MongoDBなし、sudoなし)を満たす唯一の組み合わせです。プロジェクトごとに変化するのはドメインであり、変わらないのはスケルトンです。
何かをする前に、このファイル全体を読んでください。次に、フェーズを順番に進めてください。各フェーズにはゲートがあります。
0. スタック(変更不可)
| レイヤー | 選択肢 | なぜこれであり、明らかな代替案ではないのか |
|---|---|---|
| バックエンド | Express 4、CommonJS、'use strict' | 1つのプロセスがAPI + ビルド済みUI + 画像を提供 → CORSなし、再起動するものが1つ、メモリ最小 |
| データベース | node:sqlite(DatabaseSync) | Node ≥22.5に組み込み。ネイティブモジュールゼロ。better-sqlite3はインストールさえできない(gccなし) |
| パスワード | crypto.scrypt + timingSafeEqual | bcryptなし(ネイティブ)。プレーンテキストを保存しない |
| セッション | HttpOnly Cookie内のHMAC署名トークン | jsonwebtoken依存関係なし、XSSによるlocalStorage露出なし |
| フロントエンド | React 18 + Vite 5 + Tailwind 3、server/publicにビルド | 高速低メモリビルド、Expressによって提供される静的出力、SSR不要 |
| PWA | 手書きのsw.js + manifest.webmanifest | Workbox / vite-plugin-pwaなし。キャッシュポリシーの完全な制御 |
| プッシュ | web-push + ローカル生成VAPIDキー | 無料、Firebaseアカウント不要 |
| 画像 | アップロード前にブラウザ内でCanvasで圧縮 | sharp/multerなし(ネイティブ)、サーバーRAM削減 |
| i18n | 小規模な社内辞書、i18nextなし | 即時のRTL/LTR切り替え、小さなバンドル |
絶対に追加しないこと: better-sqlite3、mongodb、pg、bcrypt、argon2、jsonwebtoken、sharp、canvas、multer、i18next、Workbox、vite-plugin-pwa、socket.io、またはネイティブコードを含むパッケージ。タスクがそれらを必要とするように見える場合は、標準ライブラリまたはブラウザ内で解決してください。
1. フェーズ0 — ホストの調査(これを最初に行う)
bash <skill>/scripts/check-host.sh # node、コンパイラ、RAM、スワップ、CPU、ポート、cloudflared
結果が出力されます。計画に反映しなければならない2つのこと:
- コンパイラなし → 上記のJSのみのルールは、好みではなくハードな事実です。
- 低リソース(
⚠️ LOW RESOURCES) →npm installとnpm run buildは、ログファイルをポーリングしながらバックグラウンドで実行する必要があります。フォアグラウンドの長時間コマンドは強制終了されます。references/host-constraints.mdを参照してください。
ブラウザルール(重要、そして条件付き)
デフォルトでは、curlとAPIスモークテストで検証します。これはより高速で低コストです。しかし、ルールは**「許可を求めずにブラウザを起動しない」**であり、「決して起動しない」ではありません:
-
快適なホスト(≥4 CPU、スワップあり、十分な空きRAM)の場合:許可を求めるのは形式的なものです。レンダリングされたUIを確認するためにヘッドレスブラウザを開きたいと伝え、ユーザーに決定させます。
-
低リソースホスト(2 vCPU / ~300MB / スワップなしなど)の場合:ユーザーに理由を、リクエストと同じタイミングで伝えます。Chromiumインスタンスはマシン全体を消費し、サーバーがOOMで強制終了され、再起動が必要になる可能性があります。次のように伝えます:
「UIを確認するためにブラウザを開きますか?このサーバー(2コア、スワップなし)でブラウザを実行すると、リソースを完全に消費し、サーバーが停止して再起動が必要になる可能性があります。代わりに
curlとAPIテストで確認しますか、それともブラウザを実行しますか?」
そして、回答を尊重します。決してブラウザを静かに起動しないでください。
2. フェーズ1 — アイデアを理解し、ユーザーにインタビューする(ハードゲート)
2a. 理解した内容を言い換える — 50行ではなく5行で
カバーする内容:誰が使うか、コアループ(最も繰り返すアクション)、保存するデータ、最初のバージョンで「完了」がどのような状態か。まだアーキテクチャを計画しないでください。
2b. 構築前に設定を尋ねる — これは必須であり、オプションではありません
ユーザーは、サービスワーカーが何かを知るずっと前に、見たいものを知っています。これらの回答を事前に得ることは、初回で気に入られるアプリと、「色を変えて」を3回繰り返すことの違いです。system_ask_userツールを使用して、ユーザーがワンタップで回答できるようにします。最大5つの質問で、各質問に正確に3つのオプションを設定します。 ビルドに最も影響を与えるものを選択し、合理的に推測または自分で決定できるものはスキップします。
質問バンク(プロジェクトのドメインに合わせて文言を調整し、ユーザーの言語で質問してください):
| # | 質問 | オプション |
|---|---|---|
| 1 | デフォルトのインターフェース言語 | アラビア語(RTL)+ EN切り替え · 英語(LTR)+ AR切り替え · アラビア語のみ |
| 2 | カラーパレット | 暖色(オレンジ/アンバー) · 落ち着いた色(ターコイズ/ブルー) · エレガント(バイオレット/インディゴ)— またはプロジェクトのドメインに合わせる |
| 3 | デザインムード | シンプルで機能的、情報量多め · モダン、角丸、アニメーション · デフォルトでダークエレガント |
| 4 | モバイルファーストかデスクトップか | ボトムナビゲーションのモバイルアプリ · サイドバーのデスクトップダッシュボード · 両方(デフォルトのレスポンシブ) |
| 5 | アカウント | 登録 + ゲストモード · ゲストのみ(後でアップグレード) · アカウントなし |
| 6 | 通知 | スケジュールアラート + プッシュ · アプリ内通知のみ · 通知なし |
| 7 | 公開コンテンツ | JSONファイルから提供されるコンテンツカタログ · ユーザーコンテンツのみ · 後で |
| 8 | 名前とロゴ | アラビア語 + 英語の名前と絵文字 · 1つの名前と描かれたアイコン · あなたが最適なものを選んでください |
インタビューのルール:5つ以上質問しないこと。センスで決められること(間隔、アニメーションカーブ)は質問しないこと。ユーザーが「あなたが選んで」と言ったら、決めて先に進み、再質問しないこと。回答を記録してください。それらはフェーズ3のスキャフォールドフラグになります。
2c. 計画を回答して待つ
短い計画(スタックは決定済み。画面。データモデルを1行で。フェーズ)を伝え、停止します。このワークフローのほとんどのユーザーは、コードが書かれる前に承認したいと考えています。「OK、始めて」の1行は、高速な間違ったビルドよりも価値があります。
3. フェーズ2 — ドメインを設計する(小さく、具体的に)
コードを書く前に、チャットに次の内容を書き留めてください:
- エンティティ + フィールド — ユーザーのコアループに必要なすべてのフィールド。必須とオプションをマークします。必須フィールドは絶対最小限に抑えます(名前とカテゴリは10フィールドのフォームより優れています)。
- 画面 — リストアップ。各画面は
web/src/pages/内の1つのファイルに対応します。 - ルート — エンティティごとに1つのRESTグループと認証。
- どのオプションモジュールが適用されるか — アカウント/ゲスト、アラーム+プッシュ、公開共有リンク、公開コンテンツカタログ。それぞれは既にテンプレートに実装されています。あなたは選択するのであり、発明するのではありません。
4. フェーズ3 — スキャフォールド(1つのコマンド、その後確認)
node <skill>/scripts/scaffold.mjs \
--dir <workspace> --name "アプリ名" --name-en "AppName" \
--slug appname --prefix ap --palette orange --ink warm [--with-catalog]
これにより約68ファイルが配置されます:完全な動作スケルトン(認証、1つのデモCRUDエンティティ、PWAシェル、プッシュ、i18n、UIキット、運用スクリプト)で、アプリのID、Cookieプレフィックス、ブランドパレットがすべて代入されています。パレット:orange amber rose violet indigo sky teal emerald。インク:warm cool stone。
次に、他の何かに触れる前に、パイプラインが機能することを証明します:
export PATH="$HOME/node-v24.20.0-linux-x64/bin:$PATH" # これらのホストではNodeがPATHにありません
npm install # 低RAMホスト? ログをポーリングしながらバックグラウンドで実行
npm run build
./scripts/run.sh start
curl -s http://127.0.0.1:3000/api/health
npm run test:api # 新しいデモスキャフォールドで「110 passed, 2 failed」を期待
2つの失敗は、実際の画像ファイルを必要とするカタログアサーションです(npm run catalog:imagesで取得、ネットワークが必要)。他のすべては、ドメインの変更を開始する前に成功していなければなりません。そうしないと、後の失敗が自分のものかどうかわかりません。
配置された各ファイルの内容と、まもなく置き換えるデモドメインの部分については、references/templates-guide.mdをお読みください。
5. フェーズ4 — デモドメインを実際のドメインに置き換える
スキャフォールドには、完成した動作例(食事アプリ)が含まれているので、その形状を正確にコピーできます。データレイヤーから外側に向かって作業し、何もぶら下がらないようにします:
server/db.js— エンティティ用にデモテーブルを書き換えます。常に追加的に:CREATE TABLE IF NOT EXISTSブロックに新しいテーブル、マイグレーション配列に新しいカラムを追加します。次に、クエリ関数を記述します。server/routes/<entity>.js—routes/meals.jsを正規のCRUDルーターとしてコピーします(optionalFields、toEntity()マッパー、INSERT/PATCH)。エクスポートスタイルを、server/index.jsがそれをインポートする方法(module.exports = routervs{ router }— リポジトリは一貫性がないため、記述する前に確認してください)に合わせます。server/index.jsにルーターをマウントします。それ以外にはAPIプレフィックスを追加しないでください(SPAフォールバックは既に/apiを除外しています)。web/src/lib/api.js— ルートごとに1つのメソッド。ページやコンポーネントでfetchを使用しないこと。絶対に。web/src/pages/*+web/src/App.jsxのルート。scripts/smoke-test.js— 既存のcheck(name, condition, extra)+call(path, {method, body})ヘルパーを使用して、デモアサーションを書き換えます。これが証明になります。
デモエンティティのルーター、ページ、APIメソッド、i18nキーなど、ドメインに不要なものは、デッドコードとして残さずに削除します。
6. フェーズ5 — フロントエンド:RTLファースト、両言語、1つのデザインシステム
- すべてのユーザー向け文字列は、
web/src/lib/i18n.jsの**dict.arとdict.enの両方**に配置し、t('key')で読み取り、{name}プレースホルダーで補間します。一方の辞書にしかキーがない場合はバグです。 - 論理ユーティリティ(
start-*/end-*/ps-*/pe-*/ms-*/me-*)を使用して、RTLとLTRの両方が機能するようにします。意図的な例外:パスワード入力はdir="ltr"であるため、物理的なpr-12/right-3を使用します。 - バラバラのTailwindを書く前に、
web/src/styles.cssのコンポーネントクラス(.card、.btn-primary、.input、.label、.chip)とweb/src/components/ui.jsxのプリミティブを再利用します。 - テーマは
documentElementのクラスベースであり、localStorageに永続化され、最初のペイントの前にweb/index.htmlのインラインスクリプトによって適用されます(フラッシュを防止し、iOSステータスバーを修正します)。 - レスポンシブ:モバイルファーストで、ボトムナビゲーションが
md:からサイドレールになります(AppShell.jsx)。 - フォーム、リスト、アプリバー、モーダル、トーストの位置でRTL/LTRを確認します。
7. フェーズ6 — PWA + 通知
sw.jsとmanifest.webmanifestは配置されています。忘れてはいけない2つのこと:
- そのファイルを変更するたびに
web/public/sw.jsのVERSIONを増やしてください。そうしないと、インストールされたクライアントは古いキャッシュを永久に保持します。 - VAPIDキーは、初回起動時に
data/vapid.jsonに生成されます。VAPIDのsubは実際の解決可能なドメイン(mailto:[email protected])でなければなりません。Appleは*.local/@localhostを403 BadJwtTokenで拒否しますが、Googleは受け入れるため、「Androidでは動作するが、iPhoneでは静かに失敗する」という古典的な問題が発生します。VAPID_SUBJECTで上書きし、個人のアドレスをハードコードしないでください。 - プロバイダーの実際の応答なしにプッシュの成功を報告しないでください。
sendToUserは{total, sent, failed:[{status, reason}]}を返し、無効なサブスクリプション(404/410/403)を削除します。 - iOSでは、アプリをホーム画面にインストールし、タップから許可を要求する必要があります。アプリ内のローカル通知フォールバック(
App.jsxのuseAlarmWatcher)を機能させ続けてください。
詳細とプラットフォームの制限(通知内の画像、ステータスバーの色、スタンドアロンのレターボックス)については、references/pwa-and-push.mdにあります。iOSについて何かを約束する前に、それを読んでください。
8. フェーズ7 — 確認(これが成果物の証明です)
npm run test:api # 分離されたデータ/test.db、ポート3100、ライブDBはそのまま
npm run build && ./scripts/run.sh restart
curl -s http://127.0.0.1:3000/api/health
curl -s http://127.0.0.1:3000/ | head -3 # ビルドされたSPAが提供されている
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/manifest.webmanifest
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/sw.js
また、curlで実際のユーザーパスを実行します(登録/ゲスト → 作成 → 読み取り → 更新 → 削除)。「動作するはず」ではなく、実際の出力を報告できるようにします。その後、ブラウザが許可されている場合は、電話サイズのビューポートで視覚的なパスに使用します。
正確なコマンドとその実際の出力を報告します。何かが失敗した場合は、エラーとともにそのように述べてください。
9. フェーズ8 — 納品
- ローカルgitリポジトリ + 最初のコミット(
git init -b main)。これにより、危険な実験の前に戻れる既知の良好な状態が確保されます。依頼がない限り、pushしないでください。アラビア語の件名でConventional Commitsを使用します:feat(meals): إضافة فلتر الفئات。 - Cloudflareクイックトンネルを介した公開リンク(
./scripts/tunnel.sh start、その後tunnel.logからURLを読み取ります)。この手順はオプションであり、2つの個別の承認が必要です:- 公開リンクが必要かどうかを尋ねます。 ユーザーが既にドメイン、リバースプロキシ、またはデプロイできるホスティングを所有している場合は、トンネルは必要ありません。押し付けないでください。
cloudflaredを確認してから約束します(scripts/check-host.shが報告します)。不足している場合は、その旨を伝え、インストーラーを実行する前にインストールの許可を求めます。決してバイナリを静かにインストールしないでください。インストールが簡単な場合(brew install cloudflared、apt、ダウンロードは手動)は、あなたがインストールを提供します。
トンネルがアクティブになったら、curlで公開リンクをテストし(「HTTP/1.1 200」とボディの最初の行を期待)、報告します。その後、トンネルを維持するか(scripts/tunnel.sh status)、停止するかを尋ねます。さまざまな国のユーザーにリンクをテストするように依頼するのは適切です。
- 最後に、次回このマシンで再開する方法を要約した実行時カード:
npm run build && ./scripts/run.sh restart(ビルド時にクライアントに新しいSWバージョンを強制する)またはnpm run dev(ファイル監視あり)。それとnpm run test:api。
10. トリガー(コマンドライン引数)
このスキルをCLI呼び出しで明示的に起動するには:
claude tasks send --skill "スキル名" "完全なアプリの説明"
.claude/settings.jsonでエイリアスを作成すると便利な場合もあります。
付録 — リファレンスドキュメント
スキルコードベース内で利用可能:
| ファイル | 内容 |
|---|---|
references/host-constraints.md | 低リソースマシンの制限と回避策の詳細 |
references/templates-guide.md | 生成された各ファイルとその役割の完全なウォークスルー |
references/pwa-and-push.md | iOS PWAの制限、プッシュ通知の動作、VAPIDキーの管理 |
references/sqlite-patterns.md | スキーママイグレーション、クエリパターン、およびDatabaseSyncの制限 |
references/translations.md | 新しいi18nキーを追加する方法と、見逃しやすい落とし穴 |