Slack MCP Agent — 管理画面仕様書
v1.2 / 2026-04-20
docs/mvp-spec.md Section 10 の詳細化。各画面のワイヤーフレーム・データソース・インタラクションを定義する。
デザイントークン・コンポーネント規約は DESIGN.md を参照。
1. 概要
1.1 目的
パイプライン実行結果の閲覧・詳細確認
承認フロー・実行設定の管理
外部連携(freee / Google / Slack)の接続管理
全操作の監査ログ閲覧
1.2 技術スタック
項目
選定
フレームワーク
Next.js 16 (App Router, Server Components)
UI
Tailwind CSS v4 + shadcn/ui
データ取得
Server Components で better-sqlite3 により data/agent.db を直接参照
認証
MVP: HTTP Basic 認証(環境変数 ADMIN_USER / ADMIN_PASSWORD、web/middleware.ts で強制)
デプロイ
ローカル (localhost:3100)
1.3 画面一覧
#
パス
画面名
アクセス
実装状態
1
/
パイプライン一覧
認証必須
実装済み
2
/pipeline/[id]
パイプライン詳細
認証必須
実装済み
3
/settings
設定
認証必須
実装済み
4
/integrations
外部連携
認証必須
実装済み
5
/audit
監査ログ
認証必須
Post-MVP
Basic 認証はブラウザの WWW-Authenticate ダイアログで完結するため、独自の /login 画面は MVP スコープ外(未実装)。
2. 認証
2.1 MVP: HTTP Basic 認証
ADMIN_USER=admin
ADMIN_PASSWORD=<ランダム生成>
Next.js Middleware (web/middleware.ts) で _next/static・_next/image・favicon.ico 以外の全ルートに Basic 認証を適用する(実装抜粋)。
export function middleware ( request : NextRequest ) {
const user = process . env . ADMIN_USER || "admin" ;
const pass = process . env . ADMIN_PASSWORD || "admin" ;
const authHeader = request . headers . get ( "authorization" );
if ( authHeader ) {
const [ scheme , encoded ] = authHeader . split ( " " );
if ( scheme === "Basic" && encoded ) {
const [ u , p ] = atob ( encoded ). split ( ":" );
if ( u === user && p === pass ) return NextResponse . next ();
}
}
return new NextResponse ( "Unauthorized" , {
status : 401 ,
headers : { "WWW-Authenticate" : 'Basic realm="HR AI Agent Admin"' },
});
}
export const config = {
matcher : [ "/((?!_next/static|_next/image|favicon.ico).*)" ],
};
2.2 Post-MVP: Firebase Auth + Google SSO
@cast-er.com ドメイン制限
Caster 既存実装と同じ構成
3. 画面 0: ログイン (/login) — Post-MVP
MVP では HTTP Basic 認証をブラウザ標準のダイアログに委譲するため、独自の /login 画面は実装しない。Firebase Auth + Google SSO 化(§2.2)とセットで Post-MVP で検討する。
4. 画面 1: パイプライン一覧 (/)
5.1 ワイヤーフレーム
┌─ Sidebar ─┬───────────────────────────────────────────────────┐
│ │ パイプライン [↻ 再読込] │
│ │ │
│ │ [All] [Running] [Completed] [Failed] [Cancelled] │
│ │ │
│ │ ┌──────────────────────────────────────────────┐ │
│ │ │ Status │ タイトル │ 種別│ 作成日時 │時間│ │
│ │ ├─────────┼──────────────────┼─────┼──────────┼────┤ │
│ │ │ ✅ 完了 │ 勤怠集計(3月) │ std │ 04-18 │ 38s│ │
│ │ │ 🔄 実行 │ 入社手続き │ std │ 04-18 │ - │ │
│ │ │ ❌ 失敗 │ 給与明細発行 │ urg │ 04-17 │ 12s│ │
│ │ │ 🔵 承認 │ 退職処理 tanaka │ std │ 04-17 │ - │ │
│ │ │ 🟡 生成 │ 年末調整案内 │ std │ 04-16 │ - │ │
│ │ │ ⬜ 中止 │ 勤怠集計(2月) │ std │ 04-15 │ - │ │
│ │ └──────────────────────────────────────────────┘ │
│ │ │
│ │ ← 前へ 1 / 3 ページ 次へ → │
└────────────┴───────────────────────────────────────────────────┘
5.2 データソース
-- ステータスフィルタ付き一覧
SELECT
t . id , t . title , t . status , t . task_type , t . priority , t . created_at ,
e . completed_at , e . started_at ,
CASE WHEN e . completed_at IS NOT NULL
THEN CAST (( julianday ( e . completed_at ) - julianday ( e . started_at )) * 86400 AS INTEGER )
ELSE NULL
END as elapsed_seconds
FROM tasks t
LEFT JOIN executions e ON e . task_id = t . id AND e . status = 'completed'
WHERE t . tenant_id = ?
AND ( ? IS NULL OR t . status = ? ) -- ステータスフィルタ
ORDER BY t . created_at DESC
LIMIT 20 OFFSET ? ;
-- 総件数(ページネーション用)
SELECT COUNT ( * ) FROM tasks
WHERE tenant_id = ? AND ( ? IS NULL OR status = ? );
5.3 インタラクション
操作
動作
タブ切替
URL クエリパラメータ ?status=running でフィルタ
行クリック
/pipeline/[id] に遷移
[再読込]
router.refresh() で Server Component を再取得
ページネーション
?page=2 でオフセット計算
5. 画面 2: パイプライン詳細 (/pipeline/[id])
5.1 ワイヤーフレーム
┌─ Sidebar ─┬──────────────────────────────────────────────────────┐
│ │ ← パイプライン一覧 │
│ │ │
│ │ 勤怠集計 (先月分) [✅ 完了] │
│ │ 先月1〜末日の打刻データを集計し、給与計算用に出力 │
│ │ │
│ │ ┌──────────┬──────────┬──────────┬──────────┐ │
│ │ │ 優先度 │ 種別 │ 作成日時 │ 実行時間 │ │
│ │ │ 🟡 Medium│ standard │ 04-18 │ 38s │ │
│ │ └──────────┴──────────┴──────────┴──────────┘ │
│ │ │
│ │ ● Task 04-18 14:32 │
│ │ │ 抽出済み → 実行中 → 完了 │
│ │ │ │
│ │ ▼ Prompt v1 (承認済み) 04-18 14:33 │
│ │ │ ┌────────────────────────────────────────┐ │
│ │ │ │ 1. 従業員一覧を取得 │ │
│ │ │ │ 2. 各従業員の勤怠データを取得 │ │
│ │ │ │ 3. 労働時間・残業時間を集計 │ │
│ │ │ │ 4. 集計結果を Google Sheet に書込 │ │
│ │ │ │ 5. 完了通知を送信 │ │
│ │ │ │ │ │
│ │ │ │ 承認: @yamada · 14:33:12 │ │
│ │ │ └────────────────────────────────────────┘ │
│ │ │ │
│ │ ▼ Process v1 (承認済み) 04-18 14:34 │
│ │ │ ┌────────────────────────────────────────┐ │
│ │ │ │ 1. list_employees ✅ │ │
│ │ │ │ 2. list_attendance ✅ │ │
│ │ │ │ 3. calculate_overtime ✅ │ │
│ │ │ │ 4. write_rows_to_sheet ✅ │ │
│ │ │ │ 5. send_slack_dm ✅ │ │
│ │ │ │ │ │
│ │ │ │ 承認: @yamada · 14:34:08 │ │
│ │ │ └────────────────────────────────────────┘ │
│ │ │ │
│ │ ▼ Execution #1 (完了) 04-18 14:35 │
│ │ ┌────────────────────────────────────────┐ │
│ │ │ ✅ list_employees 0.8s │ │
│ │ │ ✅ list_attendance 12.3s │ │
│ │ │ ✅ calculate_overtime 2.1s │ │
│ │ │ ✅ write_rows_to_sheet 8.4s │ │
│ │ │ ✅ send_slack_dm 1.2s │ │
│ │ │ │ │
│ │ │ サマリー: │ │
│ │ │ 先月の勤怠データを集計し... │ │
│ │ │ 実行時間: 38s │ │
│ │ └────────────────────────────────────────┘ │
└────────────┴──────────────────────────────────────────────────────┘
5.2 データソース
-- タスク本体
SELECT * FROM tasks WHERE id = ? ;
-- Prompt 全バージョン
SELECT * FROM prompts WHERE task_id = ? ORDER BY version ASC ;
-- Process 全バージョン
SELECT * FROM processes WHERE task_id = ? ORDER BY version ASC ;
-- Execution 全件
SELECT * FROM executions WHERE task_id = ? ORDER BY started_at ASC ;
5.3 インタラクション
操作
動作
[← パイプライン一覧]
/pipeline に戻る
タイムラインノード
クリックで展開/折りたたみ(Collapsible)
複数バージョン
Prompt v1, v2... をそれぞれ表示。却下理由も表示
5.4 却下バージョンの表示
却下されたバージョンは opacity-60 で表示し、却下理由をインライン表示:
● Prompt v1 (却下) [opacity-60]
│ 理由: 「3月分のみにしたい」 by @yamada
│
● Prompt v2 (承認済み) [通常表示]
6. 画面 3: 設定 (/settings)
6.1 ワイヤーフレーム
┌─ Sidebar ─┬───────────────────────────────────────────────┐
│ │ 設定 │
│ │ 承認フローのポリシーと実行設定を管理します。 │
│ │ │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ 基本情報 │ │
│ │ │ │ │
│ │ │ 名前 [HR AI Agent ] │ │
│ │ │ スラッグ [default ] │ │
│ │ └──────────────────────────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ 承認フロー設定 │ │
│ │ │ │ │
│ │ │ Prompt 承認を必須にする [====○ ] │ │
│ │ │ 生成されたプロンプトを実行前に │ │
│ │ │ 人間が承認する必要があります。 │ │
│ │ │ │ │
│ │ │ Process 承認を必須にする [====○ ] │ │
│ │ │ LLM が生成したプロセス定義を │ │
│ │ │ 実行前に確認します。 │ │
│ │ └──────────────────────────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ 実行設定 │ │
│ │ │ │ │
│ │ │ モデル [claude-sonnet-4-6 ▾] │ │
│ │ │ L4 タイムアウト [360 ] 秒 │ │
│ │ │ ツール自動承認 [====○ ] │ │
│ │ └──────────────────────────────────────────┘ │
│ │ │
│ │ [変更を保存] │
└────────────┴───────────────────────────────────────────────┘
6.2 データソース
-- 設定取得
SELECT config FROM settings WHERE tenant_id = ? ;
-- 設定更新
UPDATE settings SET config = ? , updated_at = ? , updated_by = ? WHERE tenant_id = ? ;
config JSON の構造:
{
"name" : "HR AI Agent" ,
"slug" : "default" ,
"prompt_approval_required" : true ,
"process_approval_required" : true ,
"model" : "claude-sonnet-4-6" ,
"l4_timeout_seconds" : 360 ,
"auto_approve_tools" : true
}
6.3 インタラクション
操作
動作
トグル切替
ローカルステート更新(即反映はしない)
[変更を保存]
Server Action で DB 更新 + 監査ログ記録
保存成功
Toast 通知「設定を保存しました」
保存失敗
Toast 通知(エラーメッセージ)
7. 画面 4: 外部連携 (/integrations)
7.1 ワイヤーフレーム
┌─ Sidebar ─┬───────────────────────────────────────────────────┐
│ │ 外部連携 │
│ │ エージェントが利用する外部サービスの接続を管理。 │
│ │ │
│ │ ┌────────────────────────────────────────────┐ │
│ │ │ 💼 freee [接続済み] │ │
│ │ │ 従業員・勤怠・給与 API にアクセスします。 │ │
│ │ │ │ │
│ │ │ スコープ: employees:read, work_records:read│ │
│ │ │ 事業所 ID: 12345 │ │
│ │ │ 接続日時: 2026-04-15 09:20 │ │
│ │ │ │ │
│ │ │ [再認証] [切断] │ │
│ │ └────────────────────────────────────────────┘ │
│ │ │
│ │ ┌────────────────────────────────────────────┐ │
│ │ │ 📊 Google Sheets [接続済み] │ │
│ │ │ スプレッドシートへのデータ書き込み。 │ │
│ │ │ │ │
│ │ │ サービスアカウント: hr-agent@... │ │
│ │ │ 接続日時: 2026-04-15 10:30 │ │
│ │ │ │ │
│ │ │ [再認証] [切断] │ │
│ │ └────────────────────────────────────────────┘ │
│ │ │
│ │ ┌────────────────────────────────────────────┐ │
│ │ │ 💬 Slack [接続済み] │ │
│ │ │ DM 送信・チャンネル通知。 │ │
│ │ │ │ │
│ │ │ ワークスペース: HR Operations │ │
│ │ │ Bot User: @hr-ai-agent │ │
│ │ │ 接続日時: 2026-04-10 08:00 │ │
│ │ │ │ │
│ │ │ [切断] │ │
│ │ └────────────────────────────────────────────┘ │
└────────────┴───────────────────────────────────────────────────┘
7.2 データソース
SELECT * FROM integrations WHERE tenant_id = ? ORDER BY provider ASC ;
7.3 freee OAuth フロー
[接続] ボタンクリック → /api/integrations/freee/auth にリダイレクト
Backend が freee OAuth 認証 URL を生成し、ユーザーをリダイレクト
ユーザーが freee で認可 → コールバック /api/integrations/freee/callback
Backend がアクセストークン + リフレッシュトークンを取得
integrations テーブルに保存(credentials は暗号化)
/integrations にリダイレクト、接続状態を更新表示
7.4 インタラクション
操作
動作
[接続] (未接続時)
OAuth フロー開始
[再認証]
既存トークン破棄 → OAuth フロー再開
[切断]
確認ダイアログ → credentials 削除、status → disconnected
切断確認
「切断すると Agent がこのサービスを利用できなくなります」
8. 画面 5: 監査ログ (/audit) — Post-MVP
Backend 側の audit_logs テーブルへの書き込みは実装済み(docs/data-model.md §2.7)。Web UI は Post-MVP で追加予定。下記はワイヤーフレームとデータソースの設計メモ。
8.1 ワイヤーフレーム
┌─ Sidebar ─┬──────────────────────────────────────────────────────┐
│ │ 監査ログ │
│ │ 管理操作と業務イベントの監査ログを表示します。 │
│ │ │
│ │ [2026-04-11 ▾] 〜 [2026-04-18 ▾] [アクション ▾] │
│ │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ │ │ 日時 │ アクター │ アクション │▸│ │
│ │ ├───────────────────┼──────────┼─────────────────┼──┤ │
│ │ │ 04-18 14:35:42 │ system │ execution │▸│ │
│ │ │ │ │ .completed │ │ │
│ │ │ { task: "勤怠集計", execution_id: "01J...", │ │
│ │ │ elapsed: 38, steps_completed: 5 } │ │
│ │ ├───────────────────┼──────────┼─────────────────┼──┤ │
│ │ │ 04-18 14:34:08 │ yamada │ process │▸│ │
│ │ │ │ │ .approved │ │ │
│ │ ├───────────────────┼──────────┼─────────────────┼──┤ │
│ │ │ 04-18 14:33:12 │ yamada │ prompt │▸│ │
│ │ │ │ │ .approved │ │ │
│ │ ├───────────────────┼──────────┼─────────────────┼──┤ │
│ │ │ 04-18 14:32:01 │ system │ task.created │▸│ │
│ │ │ │ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
│ │ ← 前へ 1 / 5 ページ 次へ → │
└────────────┴──────────────────────────────────────────────────────┘
8.2 データソース
SELECT
al . id , al . timestamp , al . actor_type , al . actor_id ,
al . action , al . resource_type , al . resource_id , al . details
FROM audit_logs al
WHERE al . tenant_id = ?
AND ( ? IS NULL OR al . timestamp >= ? ) -- 開始日フィルタ
AND ( ? IS NULL OR al . timestamp <= ? ) -- 終了日フィルタ
AND ( ? IS NULL OR al . action = ? ) -- アクション種別フィルタ
ORDER BY al . timestamp DESC
LIMIT 20 OFFSET ? ;
8.3 アクション種別
アクション
actor_type
説明
task.created
system
タスク作成
prompt.approved
user
Prompt 承認
prompt.rejected
user
Prompt 却下
process.approved
user
Process 承認
process.rejected
user
Process 却下
execution.started
system
実行開始
execution.completed
system
実行完了
execution.failed
system
実行失敗
execution.cancelled
user
実行中止
settings.updated
user
設定変更
integration.connected
user
外部連携接続
integration.disconnected
user
外部連携切断
8.4 インタラクション
操作
動作
日付フィルタ
URL クエリ ?from=2026-04-11&to=2026-04-18
アクション種別フィルタ
URL クエリ ?action=prompt.approved
行展開 (▸)
Collapsible で details JSON を表示
ページネーション
?page=2
9. 共通パターン
9.1 Server Actions
設定保存・接続切断等の書き込み操作は Next.js Server Actions を使用。
"use server" ;
export async function updateSettings ( formData : FormData ) {
const config = {
prompt_approval_required : formData.get ( "prompt_approval" ) === "on" ,
process_approval_required : formData.get ( "process_approval" ) === "on" ,
model : formData.get ( "model" ) as string ,
l4_timeout_seconds : Number ( formData . get ( "timeout" )),
auto_approve_tools : formData.get ( "auto_approve" ) === "on" ,
};
await db . run ( "UPDATE settings SET config = ?, updated_at = ? WHERE tenant_id = ?" ,
JSON . stringify ( config ), new Date (). toISOString (), tenantId );
await insertAuditLog ( "settings.updated" , "user" , userId , "settings" , tenantId , config );
revalidatePath ( "/settings" );
}
9.2 Toast 通知
操作結果のフィードバックは shadcn/ui の Toast を使用。
種別
色
用途
success
緑
保存成功、接続完了
error
赤
保存失敗、接続失敗
info
青
情報通知
9.3 エラーハンドリング
DB 接続エラー: エラーページ(error.tsx)を表示
認証失敗: Middleware が 401 + WWW-Authenticate ヘッダを返し、ブラウザが Basic 認証ダイアログを表示
404: not-found.tsx を表示
9.4 ローディング
Server Components のストリーミングレンダリングを活用
各ページに loading.tsx を配置(Skeleton UI)
10. Caster 既存 UI との差分 — メリット・デメリット比較
項目
Caster 既存
本仕様
メリット
デメリット
認証
Firebase Auth + Google SSO
Basic 認証(MVP)
外部依存ゼロ、セットアップ即完了
セキュリティが弱い(ローカル運用前提)、Post-MVP で差し替え必須
DB
Firestore
SQLite
デプロイ不要・ファイル 1 つで完結、Backend と共有容易
同時書き込みに弱い、スケールアウト不可(1 人運用 MVP なら問題なし)
パイプライン一覧
3 カラム(Inbox + Stage + List + Detail)
テーブル + 詳細ページ分離
実装がシンプル、URL ベースで共有・ブックマーク可、Server Components で SSR 可
一覧と詳細を同時に見られない(画面遷移が必要)
詳細表示
右ペイン(URL 変化なし)
独立ページ /pipeline/[id]
URL で直リンク共有可能、ページ単位でキャッシュ・プリフェッチ可能
一覧 ↔ 詳細の行き来にページ遷移コスト
ルーティング
useState でインライン切替
App Router ページ遷移
ブラウザの戻る/進む対応、URL 設計がクリーン、コード分割が自然
useState 方式より初期実装がやや多い(ファイル数増)
外部連携
/mcp-auths 独立ページ
/integrations に統合
全プロバイダーを一覧で管理、画面数削減
将来プロバイダー増加時に画面が長くなる可能性
ステータス管理
useState (Client)
Server Components + URL params
サーバー側でデータ取得完結、JS バンドル削減、リロードで状態復元
リアルタイム更新にはポーリング or WebSocket の追加実装が必要
変更履歴
日付
バージョン
変更内容
2026-04-18
v1.0
初版作成
2026-04-18
v1.1
ダッシュボード画面を削除(/ はパイプライン一覧に変更)、監査ログ CSV エクスポート削除、Caster 既存 UI 差分にメリデメ追加
2026-04-20
v1.2
実装整合を反映。Next.js 16・better-sqlite3・ポート 3100 を明記。/login と /audit UI を Post-MVP 扱いに変更、Middleware の実装抜粋を差し替え