diff --git a/CLAUDE.md b/CLAUDE.md index e5d3d1de..f531b5b9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -181,8 +181,8 @@ npm run deploy ## Synology バックエンド(server.js) - ファイル: `server.js`(ルートに配置、git 管理外) -- **デプロイ方法(必須)**: `bash deploy-server.sh` を実行する(SSH → docker cp → docker restart まで自動) - - SSHパスワード → sudoパスワードの順に2回入力を求められる +- **デプロイ方法(必須)**: `bash deploy-server.sh` を実行する(SSH鍵認証・完全無人) + - 入力不要(SSH鍵 `~/.ssh/id_ed25519` + docker グループで自動実行) - スクリプト内の処理: `ssh` でファイル転送 → `docker cp` → `docker restart posimai_api` → ログ確認 - ⚠️ `vercel --prod` や File Station での手動アップロードは使わない - API base: `https://posimai-lab.tail72e846.ts.net/brain/api` @@ -234,11 +234,26 @@ npm run deploy ## 新アプリ作成 -`_template/` をコピーして使う。`APP_NAME` / `APP_ID` / `APP_DESCRIPTION` を置換するだけで動く。 +### テンプレート選択 + +| テンプレート | 使うべきアプリ | +|------------|--------------| +| `_template/` | 複数ビュー・i18n・Magic Link 認証・サイドバーナビが必要なアプリ(brain, daily, together, journal 相当) | +| `_template-minimal/` | 単機能ツール・サイドバー不要なアプリ(diff, clean, timer, lens, ambient 相当) | + +迷ったら `_template-minimal/` を選ぶ(後からフル機能に移行する方が簡単)。 + +`create-app.sh` で新規アプリを一括セットアップできる(Git 初期化 + Gitea/GitHub リポジトリ作成 + Vercel 連携まで自動): + +```bash +bash create-app.sh posimai-myapp "My App Name" "アプリの説明" +``` + +`create-app.sh` は `_template/` を使う。`_template-minimal/` を使いたい場合は手動でコピーしてから `create-app.sh` の Step 3 以降と同じ Git セットアップを行う(`_template-minimal/README.md` 参照)。 **完全な手順(Git / Vercel セットアップ含む)は必ず `_template/README.md` を参照すること。** 特に以下の2点は詰まりやすいので注意: -- Gitea リポジトリは **Web UI で先に作成**してから `git remote add gitea` する +- Gitea リポジトリは **Web UI で先に作成**してから `git remote add gitea` する(`create-app.sh` は `GITEA_TOKEN` 環境変数があれば API で自動作成) - `vercel git connect` 後、**空コミット push** で初回本番デプロイをトリガーする ### 新アプリ作成後の必須チェックリスト(抜け漏れ禁止) diff --git a/_template-minimal/README.md b/_template-minimal/README.md new file mode 100644 index 00000000..d380f3ee --- /dev/null +++ b/_template-minimal/README.md @@ -0,0 +1,64 @@ +# Posimai Minimal App Template + +シンプルなツール系 PWA アプリ用のボイラープレート。 +サイドバーなし・i18n なし・Magic Link なし。ヘッダー + メインコンテンツのみ。 + +## _template vs _template-minimal の使い分け + +| テンプレート | 向いているアプリ | +|------------|----------------| +| `_template/` | 複数ビュー・i18n・Magic Link・設定パネルが必要なアプリ(brain, daily, together 等) | +| `_template-minimal/` | 単機能ツール(diff, clean, timer, lens, ambient 等) | + +## 使い方 + +```bash +# 1. テンプレートをコピー +cp -r _template-minimal posimai-[new-app-name] +cd posimai-[new-app-name] + +# 2. APP_NAME / APP_ID / APP_DESCRIPTION を置換 +# APP_NAME → 表示名 (例: "Posimai Memo") +# APP_ID → 識別子 (例: "posimai-memo") +# APP_DESCRIPTION → 説明文 + +# 3. 以降は _template/README.md の Step 3〜8 と同じ手順 +``` + +または `create-app.sh` を使う(`--minimal` フラグはまだない。手動コピーで対応): + +```bash +# create-app.sh は _template/ を使う。 +# minimal を使いたい場合は先に手動コピーしてから Git セットアップだけ行う: +cd posimai-[new-app-name] +git init -b main && git add . && git commit -m "init: APP_NAME" +gh repo create posimai/APP_ID --private +git remote add gitea http://100.76.7.3:3000/mai/APP_ID.git +git remote add github https://github.com/posimai/APP_ID.git +npm run deploy +echo "https://github.com/posimai/APP_ID.git" | vercel git connect +git commit --allow-empty -m "ci: trigger initial Vercel deployment" +npm run deploy +``` + +## 実装ガイド + +`index.html` の中の以下のコメント箇所を編集するだけ: + +1. ` + + + +
+
+ + APP_NAME +
+ +
+ +
+ + + +
+ +
APP_NAME
+
APP_DESCRIPTION
+
+
+ +
+ + + + diff --git a/_template-minimal/manifest.json b/_template-minimal/manifest.json new file mode 100644 index 00000000..84821776 --- /dev/null +++ b/_template-minimal/manifest.json @@ -0,0 +1,17 @@ +{ + "id": "/APP_ID/", + "name": "APP_NAME", + "short_name": "APP_NAME", + "description": "APP_DESCRIPTION", + "start_url": "/", + "display": "standalone", + "display_override": ["window-controls-overlay", "standalone"], + "background_color": "#0D0D0D", + "theme_color": "#0D0D0D", + "orientation": "portrait-primary", + "categories": ["productivity"], + "icons": [ + { "src": "/logo.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, + { "src": "/logo.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } + ] +} diff --git a/_template-minimal/package.json b/_template-minimal/package.json new file mode 100644 index 00000000..dc417230 --- /dev/null +++ b/_template-minimal/package.json @@ -0,0 +1,9 @@ +{ + "name": "APP_ID", + "version": "1.0.0", + "description": "APP_DESCRIPTION", + "private": true, + "scripts": { + "deploy": "git push gitea main && git push github main" + } +} diff --git a/_template-minimal/sw.js b/_template-minimal/sw.js new file mode 100644 index 00000000..734d1975 --- /dev/null +++ b/_template-minimal/sw.js @@ -0,0 +1,38 @@ +// Posimai SW — stale-while-revalidate + update notification +// バージョンは index.html に inline で管理(この文字列変更で旧キャッシュ削除) +const CACHE = 'APP_ID-v2'; +const STATIC = ['/', '/index.html', '/manifest.json', '/logo.png']; + +self.addEventListener('install', e => { + e.waitUntil( + caches.open(CACHE).then(c => c.addAll(STATIC)) + // skipWaiting() は意図的に呼ばない + // → updatefound イベントで UI 側からユーザーに通知する方式を採用 + ); +}); + +self.addEventListener('activate', e => { + e.waitUntil( + caches.keys().then(keys => + Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))) + ).then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', e => { + if (e.request.method !== 'GET') return; + if (!e.request.url.startsWith(self.location.origin)) return; + + e.respondWith( + caches.open(CACHE).then(cache => + cache.match(e.request).then(cached => { + const network = fetch(e.request).then(res => { + if (res.ok && res.type === 'basic') cache.put(e.request, res.clone()); + return res; + }).catch(() => cached); + // stale-while-revalidate: キャッシュがあればすぐ返し、裏でネットワーク更新 + return cached || network; + }) + ) + ); +}); diff --git a/create-app.sh b/create-app.sh new file mode 100644 index 00000000..4d4875fa --- /dev/null +++ b/create-app.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# ============================================ +# Posimai — 新規アプリ作成スクリプト +# 使い方: bash create-app.sh posimai-myapp "My App Name" "アプリの説明" +# ============================================ +set -e + +APP_ID="${1}" +APP_NAME="${2}" +APP_DESC="${3:-${APP_NAME}}" + +# --- 引数チェック --- +if [ -z "$APP_ID" ] || [ -z "$APP_NAME" ]; then + echo "使い方: bash create-app.sh [description]" + echo "例: bash create-app.sh posimai-memo \"Posimai Memo\" \"メモ帳\"" + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TARGET_DIR="$SCRIPT_DIR/$APP_ID" + +if [ -d "$TARGET_DIR" ]; then + echo "[ERROR] ディレクトリが既に存在します: $TARGET_DIR" + exit 1 +fi + +GITEA_BASE="http://100.76.7.3:3000/mai" +GITHUB_ORG="posimai" + +echo "========================================" +echo " Posimai App Creator" +echo "========================================" +echo " APP_ID : $APP_ID" +echo " APP_NAME: $APP_NAME" +echo " APP_DESC: $APP_DESC" +echo "========================================" +echo "" + +# --- Step 1: テンプレートコピー & 置換 --- +echo "Step 1: テンプレートをコピーして置換..." +cp -r "$SCRIPT_DIR/_template" "$TARGET_DIR" + +# sed で 3 変数を一括置換(macOS / Linux / Git Bash 対応) +find "$TARGET_DIR" -type f \( -name "*.html" -o -name "*.json" -o -name "*.js" -o -name "*.md" \) | while IFS= read -r f; do + sed -i "s/APP_NAME/$APP_NAME/g; s/APP_ID/$APP_ID/g; s/APP_DESCRIPTION/$APP_DESC/g" "$f" +done + +echo " コピー完了: $TARGET_DIR" + +# --- Step 2: Git 初期化 --- +echo "" +echo "Step 2: Git 初期化..." +cd "$TARGET_DIR" +git init -b main +git add . +git commit -m "init: $APP_NAME" +echo " Git 初期化完了" + +# --- Step 3: Gitea にリポジトリ作成 --- +echo "" +echo "Step 3: Gitea にリポジトリを作成..." + +# Gitea の認証情報(~/.netrc または環境変数から取得) +GITEA_TOKEN="${GITEA_TOKEN:-}" +if [ -n "$GITEA_TOKEN" ]; then + GITEA_AUTH="-H \"Authorization: token $GITEA_TOKEN\"" + curl -s -X POST "http://100.76.7.3:3000/api/v1/user/repos" \ + -H "Content-Type: application/json" \ + -H "Authorization: token $GITEA_TOKEN" \ + -d "{\"name\":\"$APP_ID\",\"private\":false,\"auto_init\":false}" \ + > /dev/null + echo " Gitea リポジトリ作成完了(API)" +else + echo " [WARN] GITEA_TOKEN 未設定。Gitea リポジトリは手動で作成してください:" + echo " → http://100.76.7.3:3000 で $APP_ID リポジトリを作成後、Enter を押してください" + read -r +fi + +# --- Step 4: GitHub にリポジトリ作成 --- +echo "" +echo "Step 4: GitHub にリポジトリを作成..." +gh repo create "$GITHUB_ORG/$APP_ID" --private --description "$APP_DESC" 2>&1 || { + echo " [WARN] GitHub リポジトリ作成に失敗(既存の可能性)。続行します。" +} +echo " GitHub リポジトリ作成完了" + +# --- Step 5: リモート追加 & push --- +echo "" +echo "Step 5: リモートを追加して push..." +git remote add gitea "$GITEA_BASE/$APP_ID.git" +git remote add github "https://github.com/$GITHUB_ORG/$APP_ID.git" +npm run deploy +echo " push 完了" + +# --- Step 6: Vercel 連携 --- +echo "" +echo "Step 6: Vercel と GitHub を連携..." +echo "https://github.com/$GITHUB_ORG/$APP_ID.git" | vercel git connect 2>&1 || { + echo " [WARN] vercel git connect に失敗。手動で連携してください。" +} + +# --- Step 7: 初回本番デプロイ --- +echo "" +echo "Step 7: 初回本番デプロイをトリガー..." +git commit --allow-empty -m "ci: trigger initial Vercel deployment" +npm run deploy + +echo "" +echo "========================================" +echo " 完了! $APP_NAME" +echo "========================================" +echo "" +echo " ディレクトリ : $TARGET_DIR" +echo " Gitea : http://100.76.7.3:3000/mai/$APP_ID" +echo " GitHub : https://github.com/$GITHUB_ORG/$APP_ID" +echo "" +echo " 次の必須作業(Dashboard 更新):" +echo " 1. posimai-dashboard/src/data/projects.json にカードを追加" +echo " 2. ecosystem/page.tsx の NODES / EDGES に追加" +echo " 3. timeline/page.tsx の EVENTS に追加" +echo " 4. access/page.tsx の APPS に追加" +echo " 5. Dashboard をデプロイ: cd posimai-dashboard && npm run deploy" +echo "" diff --git a/deploy-server.sh b/deploy-server.sh index a0a9ae72..6e97efee 100644 --- a/deploy-server.sh +++ b/deploy-server.sh @@ -6,6 +6,7 @@ set -e HOST="mai@100.76.7.3" +SSH_KEY="$HOME/.ssh/id_ed25519" CONTAINER="posimai_api" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SERVER_FILE="$SCRIPT_DIR/server.js" @@ -23,20 +24,18 @@ fi echo "" echo "→ Step 1: server.js を Synology /tmp に転送..." -echo " (SSH パスワードを求められたら入力してください)" -ssh "$HOST" "cat > $REMOTE_TMP" < "$SERVER_FILE" -echo " ✓ 転送完了" +ssh -i "$SSH_KEY" -o BatchMode=yes "$HOST" "cat > $REMOTE_TMP" < "$SERVER_FILE" +echo " 転送完了" echo "" echo "→ Step 2: コンテナに適用 + 再起動..." -echo " (sudo パスワードを求められたら入力してください)" -ssh -t "$HOST" " - sudo $DOCKER cp $REMOTE_TMP $CONTAINER:/app/server.js && \ - echo ' ✓ コピー完了' && \ - sudo $DOCKER restart $CONTAINER && \ - echo ' ✓ 再起動完了。ログを確認中...' && \ +ssh -i "$SSH_KEY" -o BatchMode=yes "$HOST" " + $DOCKER cp $REMOTE_TMP $CONTAINER:/app/server.js && \ + echo ' コピー完了' && \ + $DOCKER restart $CONTAINER && \ + echo ' 再起動完了。ログを確認中...' && \ sleep 5 && \ - sudo $DOCKER logs $CONTAINER --tail 20 + $DOCKER logs $CONTAINER --tail 20 " echo ""