Slack Appの力を借りて、自分でも続けられそうなToDoアプリをつくる
はじめに
かくひとと申します。Web開発とゲーム制作の勉強をしています。
今回はSlack Appを作成してみたので、その紹介記事となります。会社やコミュニティ等、あちこちで使われている印象だったのですが、仕組みを一切知らなかったので、その勉強が主目的でした。
最初の題材として、「ゆるく続けるToDoアプリ」を作成してみました。この記事ではその紹介と、ざっくりとした開発の流れ、躓いたところ等もまとめてみました。
概要をかいつまんで、浅く広くお話します。やけに広く書いてしまった部分もあるので、とくに「余談」と書いている箇所は読みづらければ飛ばしてください。。
Slack Appについて
その名の通り、Slackを介して使えるアプリです。Slackのコマンドから実行させたり、日ごと週ごとに自動実行させたり、他アプリと連携して実行させたり、様々です。発言やメンション、リアクションなど、Slack内のあらゆる情報を入力にできます。
下のSlack MarketPlaceからインストールが可能です。ひと目だとNotionやGithubなどの企業アプリがたくさん公開されていますが、個人でも作成・公開が可能です。
社内でSlackを利用している方、Slack上のコミュニティに所属している方だと、Slack Appはなじみ深いのかなと思っています。
アプリの用途について、主観で種類分けを考えてみると、この3つになりました。
-
Slackのワークスペースに役立つ/盛り上げるようなアプリ
例)チャンネル入退出を簡単にするツール(大規模チーム向け)、チャットボット、リアクション数ランキング、発言のまとめや分析 -
Slackと他サービスを連携して、プロセス自動化を実施するアプリ
例)開発プロセスの自動化(デプロイなど)、打刻ツール -
Slackを便利ツールとして使うアプリ
例)勉強時間の記録アプリ、Todoリスト
2.や3.をSlack Appとして作成するモチベとしては、「使い慣れているから」というのが大きいと思います。聞いた話として、ビルド・デプロイなどプロジェクトに詳しくないとできない(怖くてやりたくない)作業をSlackに組み込むことで、新任の人や開発に疎い方でも触わりやすくなるメリットがあるそうです。
つくったもの
ゆるスプリントというアプリをつくってみました。先ほどの分類だとがっつり3.です(なんとなくロゴも作ってみました)。
作ったきっかけとしては、「なるべく続けられるTodoアプリをつくりたい」というのがあります。日常で眺めているSlackワークスペースがあったので、ここに組み込んでリマインドさせればいやでも続くのでは...?と思い、作成してみました。
使い方
おもに3つのフェーズがあります。
-
目標設定
日曜9時にメッセージが届きます。ポチポチ入力して、今週の目標を設定します。 -
スプリント実施
目標に取り組む期間です。目標が完了次第、対応するスタンプを押します。 -
週間レポート
土曜17時にレポートが届きます。スタンプの有無で達成状況が決まります。感想を送信することで、Notionに記録されます。
このアプリの主目的は、「週一で目標設定すること」です。それさえやっていれば、目標が厳しければサボっていいし、次週で変えてもいいという、ゆるい目標管理です。走らないスプリント。
これらがアピールポイントかなと思ってます。
- ゆる~く1週間の目標管理できる
- よく見るSlackのワークスペースでリマインドさせるから続けやすい
- Notionで振り返りができる
しくみの詳細
フロー自体は簡単で、このようになっています。
Slack Appを開発するには、①サーバーと②Slackとサーバーの紐づけ、③サーバー内で動かすスクリプトが必要になります。また、このフローが動くための仕組みとして、2つに分かれています。
- スケジューリング:日曜9時や土曜17時に送信する
- イベント駆動:Slackの操作を受け取って(リクエスト)、処理結果をレスポンスする
この①サーバー、②Slackとサーバーの紐づけ、③スクリプトについて、以降で話していきます。
1. サーバー
このアプリでは、Google Cloud Runを利用してサーバーを立ち上げています。
Cloud Runは、Dockerで作成したコンテナをデプロイさえすれば、そのままGoogleのクラウド環境で動かすことができるサービスです。Webサービスも簡単にデプロイできます。また今回は、こちらの方法でGithub Actionsでの自動デプロイを設定しています。
ここから余談です。開発時に悩んだ話ですが、開発環境と本番環境を分けることを考えると少し面倒に感じました。というのも、どちらの環境でもSlackを介さないと動作確認ができません(localhostをブラウザで眺めるなどができない)。そのため手間ですが、Slack Appを個別に2つ作成しました。
本番環境は前述の通りですが、開発環境は「ローカル立ち上げ+ngrokにより外部公開」しています(こちらの記事が参考になりました)。
この開発環境、本番環境の公開URLをもとに、2つのSlack Appそれぞれで設定を行う必要がありました。URL設定自体は必須だと思いますが、うまいことすればSlack App1つでも完結できるかもしれません。自分はよくわかりませんでした...
2. Slackとサーバーとの紐づけ
こちらは概要のみで、詳細は割愛します。Slack APIの管理画面にて、以下のような設定をする必要があります。
- Appの作成
- ワークスペースにインストール
- Scopes(Appがどこまでリクエストを拾える権限を持つか)の指定
- Events APIやInactivity(後述)のエンドポイントURLを設定
ここに関しては公式Quickstartで一度試してみると、イメージが掴みやすかったです。
ただチュートリアルとはいえ、ローカルサーバーを立てる必要があり少し大変です。詰まったらこちらの記事を合わせて参考にしてください。
3. スクリプト
「しくみの詳細」の冒頭で話しましたが、イベント駆動とスケジューリングの2つのフローがあります。
イベント駆動
サーバーがSlackの操作を受け取って(リクエスト)、処理結果をレスポンスするフローになります。
Slackから受け取るレスポンスには、Events APIとInteractivityの2種類があります。
Events APIはワークスペース上での様々なイベントを送ってくれるもので、例としてこのような種類があります。
- メンション:メンションされた(アプリに対して)
- メッセージ:チャンネルに投稿された, DMに投稿された(アプリに対して), ...
- チャンネル:作成された, 削除された, リネームされた, ...
- リアクション:押された, 削除された
Interactivityがやや特殊ですが、Slackでは下のようにボタン操作やフォーム入力など、インタラクティブな操作ができるメッセージを送信することができ、これをInteractive Messageと呼びます。Interactivityはこれらのメッセージに対する操作を指します。
今回は、Interactivityのアクションの受信だけで十分でした。疑似コードですが、こういうスクリプトを書いています。
// Interactive APIの受信
app.post('/slack/interactive', async (req, res) => {
:
// アクション
if (payload.type === 'block_actions') {
:
// 目標追加ボタン
if (action.action_id === 'add_goal') {
目標追加;
// 目標削除ボタン(1, 2, ...)
} else if (action.action_id.startsWith('delete_goal_')) {
目標削除;
// 目標設定完了ボタン
} else if (action.action_id === 'finalize_goals') {
スプリント開始メッセージを送信
// 感想送信ボタン
} else if (action.action_id === 'submit_reflection') {
Notionに記録;
:
スケジューリング
(半分余談な内容かもしれませんが、せっかくなので記載します)
定期実行させるためのフローで、このアプリだと日曜9時と土曜17時にメッセージを定期送信させます。
通常のサーバー、常に稼働しているサーバーであれば、スクリプトにてサーバー自らスケジューリングを実施すれば問題ないです。
しかし、今回使用したのがGoogle Cloud Runでした。サーバーレスサービスなので基本イベント駆動であり、誰かからリクエストが来ない限りスリープします。つまり「自分で起きれない」ので、サーバー自らでスケジューリングすることができません。
そのため代わりにスケジューリングしてくれる人、「時間になったら起こす役」が必要になります。そこでこんな構成になりました。
起こし役にGoogle Cloud Schedulerを使用しています。とても単純で、日曜9時に「目標設定だよ」、土曜17時に「週間レポートだよ」とHTTPリクエストを送っているだけです。スクリプトは疑似的にこんな感じです。サーバーにこの2種類のリクエストが来たら、そのレスポンスとしてSlackにメッセージ送信します。
app.post('/trigger/goal-setting', async (req, res) => {
目標設定メッセージを送信
});
app.post('/trigger/weekly-report', async (req, res) => {
週間レポートを送信
});
そのためCloud Runだけみると、一貫してイベント駆動(リクエストが来たらレスポンス)です。サーバーレスサービスだと外部のスケジューラーが必要になるのだなと、作りながらわかりました。
作った感想や学び
一番の感想としては、思っていた以上に大変だったということです。。何も知らない状態だからスタートし、Slack App特有の難しさや、クラウドの構築で苦労した部分もあり、思った数倍の時間がかかりました(最初はサーバーが必要なことも知りませんでした)。
とはいえSlackやバックエンドのとてもよい勉強になりました。今後Slackを使う上で、こういうことできるんじゃないかという視野が1つ増えたように感じました。
また今回説明を省いたのですが、Notionの連携はとても楽に実施できました!こちらの記事を参考にすると、DBへの書き込みを簡単に試せました。Notion API自体がとても使いやすいので、Slack App問わず使える場面が多そうに感じました。
あとは、このアプリを使った感想についても。正直本格的に稼働させたのが3週間ほどなのでなんともですが、今のところは続けられています。リマインドさせるので必ず気づくのと、そこまで手間ではないのでポンと設定できるのがありがたいです。週一での目標設定さえすればよい、というゆるさにも助けられつつ、今週はこれやるか〜という意識づけになってます。
最後に、「よかったら使ってください」と言いたいところですが、まだMarketplaceにてアプリ公開できていません……(今だとGithubからClone後にSlack Appをセットアップしてもらうしかない)。
まだあまり調べられてないですが、アプリ公開するには認証や審査など、やることが多そうです。1個人のワークスペースでの使用から、公開していろんなワークスペースで使ってもらえるように至るまで、また1つ壁がありそうに感じました。
せっかくだから公開までしたい気持ちがあるので、ゆっくり勉強しようと思います。
参考
Discussion