
Slackの中に“ダッシュボード”を作る。Block Kitで組み立てるApp Home
こんにちは!Accel-Hack(アクセルハック) 開発チームです。
社内AIアシスタント「Airi」の開発プロセスをお届けする開発記ブログ。
第12回目の今回は、ユーザーが Airi と出会う「顔」となる場所――Slack App Home(ホームタブ)の作り方をお届けします。
前回までで、Vol.10 のコマンド、Vol.11 の外部連携と、Airi の中身は着実に充実してきました。
ですが、機能がいくら増えても、ユーザーがそれに気づけなければ意味がありません。
「Airi って何ができるの?」「私の freee 連携、今どうなってる?」――そんな疑問に一目で答える常設の入り口が欲しい。
そこで作ったのが、Slack の中に住むダッシュボード、App Home です。
1. コマンドを打つ前の「入り口」が欲しい
スラッシュコマンドは強力ですが、弱点もあります。
「何が使えるか」を、ユーザーがあらかじめ知っている必要があるのです。入社したばかりの人が、いきなり /airi attendance summary と打てるはずもありません。
そこで役立つのが Slack App Home です。
Slack のサイドバーから Airi を選ぶと現れる、アプリ専用の「ホームタブ」。
ここに、使える機能の一覧や、各種連携の状況、その日の情報などをまとめて表示しておけば、ユーザーはコマンドを覚えていなくても、ボタンをポチッと押すだけで操作を始められます。
Airi にとっての「トップページ」であり「受付」でもある場所です。
2. Block Kit:SlackのUIを“部品”で組み立てる
では、この画面をどう作るのか。
ここで登場するのが Slack の UI フレームワーク Block Kit です。
Block Kit の考え方はとてもシンプルで、HTML や CSS を書く代わりに、「ブロック」という決められた部品を並べていくだけ。
見出しの header、本文の section、ボタン置き場の actions、区切り線の divider、小さな補足の context……こうした部品を、TypeScript のオブジェクトとして宣言的に記述します。
たとえば、Airi のホームにある「Web UI を開く」セクションは、こう書かれています。
export function buildWebUiBlocks(): AnyHomeTabBlock[] {
return [
{
type: "header",
text: { type: "plain_text", text: "🌐 Web UI", emoji: true },
},
{
type: "section",
text: {
type: "mrkdwn",
text: "ダッシュボードや各種設定にアクセスできます。",
},
},
{
type: "actions",
elements: [
{
type: "button",
text: { type: "plain_text", text: "Web UIを開く ↗" },
style: "primary",
action_id: "open_web_ui",
},
],
},
];
}見出し・説明文・ボタン。
この3つの部品を配列に並べるだけで、Slack がリッチな見た目に描画してくれます。
ピクセル単位のデザインに悩む必要はなく、私たちは「何を、どの順で見せるか」に集中できます。
3. app_home_opened を起点に描画する
このホーム画面は、いつ作られるのでしょうか。
答えは「ユーザーがホームタブを開いた瞬間」です。
ユーザーがホームを開くと、Slack から app_home_opened というイベントが飛んできます。
Airi は Vol.9 で紹介した仕組みでこのイベントを受け取り、publishHomeView(userId) を呼び出して、そのユーザー専用のホーム画面を組み立てます。
export function registerHomeHandlers(app: SlackApp<AppEnv>): void {
app.event("app_home_opened", appHomeOpened); // → publishHomeView(userId)
}開くたびに最新の状態で描き直されるので、常に「今」の情報が表示される、というわけです。
4. 設計の肝:各機能がブロックを「持ち寄る」
この App Home の設計で最も気に入っているのが、「各機能が自分のブロックを持ち寄る」という点です。
publishHomeView の中身は、拍子抜けするほど素直です。
勤怠、ニュース、有給、リモートワーク、GitHub連携……各機能が用意した「ブロックビルダー」を順に呼び出し、返ってきたブロックの配列をただ連結していくだけ。
const sections = [
webUi.buildWebUiBlocks(),
await newsUi.buildNewsBlocks(),
await attendanceUi.buildAttendanceBlocks(db, userId),
await githubOauthUi.buildGithubBlocks(db, userId),
// ...(機能ごとに続く)
].filter((blocks) => blocks.length > 0); // 空の機能は自動でスキップこれは、Vol.4 で紹介した Feature-First アーキテクチャの思想が、UIの世界にもそのまま貫かれている姿です。
ホームに新しいセクションを追加したくなったら、その機能に build*Blocks() を1つ用意して、この配列に一行足すだけ。
ホーム全体を管理する巨大なファイルは存在しません。
表示すべきものが無い機能は空配列を返し、filter で自動的にスキップされます。
各セクションの間には区切り線(divider)が入り、最後に「AccelHackのAI秘書 あいり より」という context フッターが添えられます。
この流れを図にすると、次のようになります。

5. 状態に応じて“出し分ける”リッチさ
App Home のもう一つの強みは、ユーザーや状況に応じて表示を動的に変えられることです。
ブロックはコードで組み立てるので、条件分岐でいくらでも出し分けられます。
たとえば GitHub 連携のセクションは、そのユーザーが連携済みかどうかで表示を変えています。
if (user) {
blocks.push({
type: "section",
text: { type: "mrkdwn", text: `✅ *連携済み* (@${user.githubUsername})` },
});
} else {
blocks.push(/* ⚠️ 未連携メッセージ +「GitHubと連携する」ボタン */);
}連携済みの人には緑のチェックとアカウント名を、未連携の人には連携をうながすボタンを。
Vol.11 で触れた freee 連携の「連携済み/未連携」表示も、まさにこの仕組みです。
一人ひとりに最適化された入り口を、その場で組み立てられるのです。
6. 描画:views.publish に渡すだけ
こうして組み上がったブロックの配列は、最後に Slack の views.publish API へ渡します。
await fetch("https://slack.com/api/views.publish", {
method: "POST",
headers: { Authorization: `Bearer ${slackToken}` /* ... */ },
body: JSON.stringify({
user_id: userId,
view: { type: "home", blocks },
}),
});view.type に "home" を指定し、組み立てたブロックを渡すだけ。これでそのユーザーのホームタブが更新されます。
しかもこの呼び出しは、ホームを開いたときだけでなく、任意のタイミングで実行できるのがポイントです。
Vol.11 で「連携が完了したら publishHomeView を呼んで表示を更新する」と書いたのは、まさにこれ。
ユーザーが何もしなくても、状態の変化に合わせてホームが自動で描き直されるのです。
7. おわりに
今回は、Slack の中にリッチなダッシュボードを作る App Home の仕組みを見てきました。
Block Kit で部品を宣言的に並べ、各機能がブロックを持ち寄り、状態に応じて出し分け、views.publish で描画する。
ブロックの「足し算」で成り立つこの設計のおかげで、機能がいくら増えてもホームは散らからず、Airi の顔はいつも整っています。
土台となる仕組み(インフラ・コマンド・認証・UI)が、これでひととおり揃いました。
次回からはいよいよ、これらを組み合わせた具体的な業務機能の実装編に入ります。
まずは 「Vol.13: 勤怠管理をシームレスに『attendance機能』」 として、Slackのボタン一つで freee に打刻する仕組みと、その裏側のエラーハンドリングの工夫をお届けします。お楽しみに!
この記事は以下の体制で作成されました。
ドラフト作成・執筆: Airi (社内AIアシスタント)
アイデア出し・レビュー: CTO
デザイン: 事務スタッフ
Accel-Hackでは、テクノロジーを駆使して世の中の課題を解決していく仲間を募集しています。
私たちの取り組みに少しでも興味を持っていただけたら、ぜひ採用ページや会社サイトも覗いてみてくださいね。