ken_nogi/NodeSrv/docs/superpowers/specs/2026-07-25-app-portal-design.md
Kenichiro NOGI ce58cb4be4 初回コミット: dev配下(NodeSrv/Pleasanter等)をGitea管理下に統合
GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。
NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは
別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter
インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 15:37:06 +09:00

9.1 KiB
Raw Permalink Blame History

アプリポータル 設計書

作成日: 2026-07-25

背景・目的

NodeSrv配下に複数のNode.jsアプリauthgw-poclineworks-board-synclineworks-cxtalk-syncmlmanagerをDokploy上へデプロイしていく運用が確立した。しかしDokployは稼働インフラの管理はできても、アプリを横断した実行管理起動・停止・手動実行・ログ確認をまとめて行う場所は提供しない。個別アプリのDokploy管理画面を都度行き来する運用は、アプリ数が増えるほど煩雑になる。

これを解消するため、登録済みアプリを一覧表示し、種別に応じた操作常駐WEBサービスの起動/停止/再起動、バッチジョブの手動実行トリガーとログ確認を1画面で行える集中管理ポータルを新設する。

スコープ

  • 対象: webapps project配下にDokploy Composeとして登録された全アプリ
  • 非対象: mail-infra・auth-infra・app-gateway・Gitea等のインフラ系サービスアプリ運用者向けの管理画面であり、インフラ管理はDokploy管理画面で行う想定は変えない

アーキテクチャ概要

[ブラウザ] → Traefik(oauth-auth) → [ポータル(Express+SSR)]
                                          │
                    ┌─────────────────────┼─────────────────────┐
                    │                     │                     │
              Dokploy tRPC API    各アプリの管理API      Dokploy tRPC API
              (start/stop/deploy)  (/admin/trigger等、    (ログ取得)
                                    X-Portal-Secret検証)

ポータルは NodeSrv/apps/app-portal(仮称)として、他アプリと同じ _template パターンExpress、Dockerfile、Gitea経由デプロイで追加する。webapps project配下に独立したComposeとしてデプロイし、他アプリのデプロイ・再起動に影響しない既存の「1アプリ1フォルダ1Compose」独立性方針を踏襲

Dokploy APIトークン・アプリ間共有シークレットPORTAL_SECRET)はポータルの本番環境変数としてのみ保持し、AUTH_SECRETS.mdと同様の機密情報として扱う。レスポンス・ログには一切出力しない。

前提: Dokploy CLI GET系400エラーの回避

調査の結果、@dokploy/cliv0.29.4)のapiGet実装がtRPCのGETクエリを{json: params}でラップせず生のparamsをJSON化しているだけの実装バグと判明した。DokployのtRPCサーバーは{"json": {...}}形式のラップを要求するため、CLIのGET系コマンドcompose oneは軒並み400エラーになる。

Dokploy API自体は正常で、x-api-keyヘッダー付きでGET {DOKPLOY_URL}/api/trpc/<endpoint>?input=<encodeURIComponent('{"json":{...}}')>の形式で直接叩けば200が返ることを実証済みcompose.oneで確認済み)。

方針: CLI自体へのパッチは行わないグローバルnpmパッケージの一時修正はnpm update等で消える。ポータルはCLIを介さず、この正しいtRPC形式で自前のDokployクライアントモジュールを実装する。

前提: 認証ゲートウェイの404問題先行タスク

ポータルはKeycloak/oauth2-proxy認証ゲートウェイ経由でのアクセスを前提とする。しかし前回のセッションで、Traefikルーターにoauth-errors@file,oauth-auth@fileミドルウェアを付けると404になる問題が発生し、原因は未特定のまま認証ミドルウェアを外して回避した経緯があるREADME.md参照)。

ポータルの実装に着手する前に、この404の原因を特定し認証ゲートウェイを実際に機能させる必要がある。 これは本設計のスコープ外の先行タスクとして、実装計画の最初のステップに位置づける。

機能要件

ダッシュボード1ページ

ロード時にサーバー側で webapps project配下のCompose一覧をDokploy tRPC APIから取得し、各Composeのenvから以下のポータル用メタ情報をパースしてカード表示する。

環境変数 内容 必須
PORTAL_APP_TYPE web または batch 必須
PORTAL_APP_LABEL カードの表示名(省略時はappName 任意
PORTAL_APP_URL 「開く」リンク先web型のみ web型は必須
PORTAL_TRIGGER_PATH 手動実行トリガーのパスbatch型のみ batch型は必須

このメタ情報の規約はapps/_templateREADME.mdSKILL.mdに追記し、新規アプリ作成時の標準手順に組み込む。

カードの表示・操作

項目 web型 batch型
ステータス表示 稼働中/停止中/デプロイ中(composeStatus 同左
操作ボタン Start / Stop / Restart 今すぐ実行
追加リンク 「開く」→ PORTAL_APP_URL を新規タブで開く なし
共通 「ログ表示」→ モーダルでログ取得・表示 同左

操作フロー

  • Start/Stop/Restart: ポータル → Dokploy tRPC APIcompose.start/compose.stop等、要実装時に正確なエンドポイント名を確認)
  • 今すぐ実行: ポータル → 対象アプリのPORTAL_TRIGGER_PATHへPOSTX-Portal-Secretヘッダー付与。トリガー先は202を返して即応答し、実処理は非同期で行い結果は標準出力ログに書く
  • ログ表示: ポータル → Dokploy tRPC APIでデプロイ/コンテナログ取得 → モーダル表示

未検証事項(実装時に確認): Compose一覧取得・ログ取得の具体的なtRPCエンドポイント名とレスポンス形式。compose.oneは動作確認済みだが、一覧系・ログ系は別エンドポイントで未検証。

アプリ側の規約(_template拡張)

batch型アプリは、_templateに追加する以下のパターンでトリガーエンドポイントを実装する。

app.post(process.env.PORTAL_TRIGGER_PATH, (req, res) => {
  if (req.headers['x-portal-secret'] !== process.env.PORTAL_SECRET) {
    return res.sendStatus(403);
  }
  // 実処理を非同期でキューイングし即座に202を返す
  res.sendStatus(202);
});

PORTAL_SECRETはポータルと各batch型アプリで共有する値。Dokploy Environment画面で個別に設定し、AUTH_SECRETS.md同様に機密情報として扱う。

認証・権限

  • ポータルへのアクセス自体はTraefik層でoauth2-proxy認証必須websecureルーターにoauth-errors@file,oauth-auth@fileを付与。上記「先行タスク」解決後に適用)
  • ログイン後、Express側のミドルウェアでX-Auth-Request-EmailヘッダーをPORTAL_ALLOWED_EMAILSカンマ区切り環境変数と照合。リスト外なら403Dokploy情報自体も見せない
  • 将来的に利用者が増えKeycloakのGroup/Role連携が必要になった場合は、oauth2-proxy設定変更を伴う拡張として別途検討する現時点ではYAGNIによりallowlist方式のみ実装

エラーハンドリング

  • Dokploy API呼び出し失敗トークン切れ・400/500等: 該当カードに「状態取得失敗」を表示。Promise.allSettled等で個別処理し、1アプリの取得失敗が他アプリの表示を巻き込まないようにする
  • 実行トリガー失敗応答なし・403: 「シークレット不一致」「応答なし」を区別してポータル側にエラー表示
  • allowlist外ユーザーのアクセス: 403ページ表示操作ボタン・Dokploy情報を一切見せない

テスト方針

  • ユニットテスト: DokployクライアントモジュールtRPCリクエスト形成・レスポンスパース、allowlist照合ロジック、.envメタ情報パース処理
  • 手動E2E確認実機、Dokployへの実デプロイ後:
    1. ダッシュボードにアプリ一覧が表示される
    2. web型アプリのStart/Stop/Restartが機能する
    3. batch型アプリの実行トリガーが機能する
    4. ログ表示が機能する
    5. allowlist外ユーザーでアクセスすると403になる

対象ファイル(実装時)

  • apps/app-portal/新規、Express+SSR
  • apps/_template/docker-compose.ymlbatch型メタ情報・トリガーエンドポイントパターンの追記
  • apps/_template/README.md
  • README.md(アプリポータルの章を追加)
  • .claude/skills/dokploy-webapp/SKILL.mdPORTAL_APP_TYPE等の規約を追記)

未解決・後続タスク

  • 認証ゲートウェイ404問題の原因特定本設計の先行タスク
  • Dokploy tRPC APIのCompose一覧取得・ログ取得エンドポイントの実地検証
  • lineworks-board-sync/lineworks-cxtalk-sync/mlmanagerは現状_templateのスケルトンのまま。ポータル動作確認用に、最低1つのbatch型アプリを実装しておく必要がある