Slack だけで動作する勤怠/時間管理を実装した話

こんにちは、Slack の[公式 SDK 開発](https://github.com/slackapi)と日本の Developer Relations を担当している瀬良 (@seratch) と申します :wave:

先日、いくつかの技術検証も兼ねて、日本ではよく話題に上がる「**勤怠/時間管理**」を Slack だけでできるサンプルアプリをつくりました。

https://twitter.com/seratch_ja/status/1718769213098315967

https://twitter.com/seratch_ja/status/1731575417633644872

ソースコードを MIT ライセンスで公開しています。コードは 100% TypeScript で書かれており、[Deno](https://deno.com/) で動作するものです。

https://github.com/seratch/slack-timesheet

このアプリは Slack [ワークフロービルダー](https://slack.com/features/workflow-automation)の基盤である「[オートメーションプラットフォーム](https://api.slack.com/automation)」の機能だけで実装されており、**Slack 以外のインフラを一切必要としない**ことが特徴的です。

この記事では、このアプリの使い勝手などについて詳しく解説します。

## そもそも「オートメーションプラットフォーム」って何？

なお、「オートメーションプラットフォーム（以前は次世代プラットフォームと呼んでいました）って何？」という方は、以下の記事で詳しく解説しましたので、まずはそちらをお読みください。

https://qiita.com/seratch/items/ecc16b845483c9d6f9e1

https://qiita.com/seratch/items/b1449132add003e61de6

なお、これらの記事でも繰り返し注意書きがありますが、これまでの Slack アプリ開発と異なり、オートメーションプラットフォームは**有料プランの Slack ワークスペースでのみ利用可能**です。有料プランのワークスペースをご用意の上でお試しください :bow: 

## とりあえず動かしてみよう

### 最低限の設定でアプリをデプロイする

Slack CLI をインストールしていない方は以下のページの手順でインストールして `slack login` でデプロイしたいワークスペースとの接続までを完了させてください。

https://api.slack.com/automation/quickstart

用意ができたら、以下のコマンドでデプロイしましょう。

```bash
slack create -t https://github.com/seratch/slack-timesheet slack-timesheet-demo
cd slack-timesheet-demo/
slack deploy
```

`slack deploy` で二つほどプロンプトで聞かれますが、以下の通り指定してください。

* **Install to a new team**: アプリをインストールしたいワークスペース/OrG を選択してください 
* **Choose a trigger definition file**: 選択肢から `triggers/open_timesheet_ja-jp.ts` を選択してください

万事うまく行った場合のターミナル上の出力は以下のようになるはずです。

```
$ slack create -t https://github.com/seratch/slack-timesheet slack-timesheet-demo
⚙️  Creating a new Slack app in ~/tmp/slack-timesheet-demo

📦 Installed project dependencies

✨ slack-timesheet-demo successfully created

🧭 Explore the documentation to learn more
   Read the README.md or peruse the docs over at api.slack.com/automation
   Find available commands and usage info with slack help

📋 Follow the steps below to begin development
   Change into your project directory with cd slack-timesheet-demo/
   Develop locally and see changes in real-time with slack run
   When you're ready to deploy for production use slack deploy

$ cd slack-timesheet-demo/

$ slack deploy
? Choose a deployed environment Install to a new team
? Install to a new team seratch T03******

🔔 If you leave this team, you can no longer manage the installed apps
   Installed apps will belong to the team if you leave the workspace

📚 App Manifest
   Created app manifest for "slack-timesheet-demo" in "Acme Corp"

🏠 App Install
   Installing "slack-timesheet-demo" app to "Acme Corp"
   Updated app icon: assets/icon.png
   Finished in 6.5s

⚡ Listing triggers installed to the app...
   There are no triggers installed for the app

⚡ Create a trigger
   Searching for trigger definition files under 'triggers/*'...
   Found 4 trigger definition files

? Choose a trigger definition file: triggers/open_timesheet_ja-jp.ts

⚡ Trigger successfully created!

   タイムシート Ft0691****** (shortcut)
   Created: 2023-12-08 13:16:20 +09:00 (1 second ago)
   Collaborators:
     Kaz Sera @seratch U03******
   Can be found and used by:
     everyone in the workspace
   https://slack.com/shortcuts/****

🎁 App packaged and ready to deploy
   0.088MB was packaged in 4.6s

🚀 slack-timesheet-demo deployed in 10.1s
   Dashboard:  https://slack.com/apps/A069W******
   App Owner:  seratch (U03******)
   Workspace:  Acme Corp (T03******)

🌩  Visit Slack to try out your live app!
   When you make any changes, update your app by re-running slack deploy

💌 We would love to know how things are going
   Survey your development experience with slack feedback --name platform-improvements

$
```

トリガーの `https://slack.com/shortcuts/****` という URL をコピーしておいてください。次の手順で使います。

### Slack 内で早速使ってみる

トリガーの URL をチャンネルのメッセージに貼り付けたり、canvas ドキュメントに埋め込むとカードの表示となり、ワークフローを開始するための緑色のボタンが表示されるはずです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/c1074e1f-5839-8b35-38e0-810b1f6dd60c.png" width=500 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/eb7a5d98-38a9-8c48-2fe1-5d4b71378c9c.png" width=500 />

このアプリはこのボタンをクリックして起動することができます。モーダルウィンドウが開くので、そこから先はそれを別ウィンドウにして退勤まで開きっぱなしにしておくとよいでしょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/70ac24f4-effa-a3b7-bf4b-a8626fb9aabb.png" width=400 />

### 初期設定

後からでも変更できるので、一旦そのままでもよいのですが、各項目について説明しておきます。

#### 言語

Slack を日本語で使っている場合はあらかじめ日本語で画面が表示されるようになっています。この記事投稿時点では英語と日本語に対応しています。

#### 国

この記事投稿時点では、「日本」「アメリカ合衆国」を選択できるようになっていますが、実際には日本に関する機能のみが実装されている状態です。

現時点で提供されている機能は二つです。日本の祝日データを 2024 年分まで登録してあるので、それが月次レポートや当日画面に反映されます。また、6/8 時間以上勤務していて休憩時間が不足している場合、画面上で注意喚起されるようになっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/a0512fca-ab15-a1b7-4e9e-baa2fc192731.png" width=400 />

他にも一般的なニーズには対応していきたいと思っています。ご要望がある方は、ぜひニーズを教えていただけるとありがたいです。

#### アプリ利用モード

「勤務管理のみ」「勤務管理とライフログ」の二つから選ぶことができます。

勤務時間・休憩時間・休暇のみ管理したいという場合にはライフログは不要ですが、休憩時間中の自己研鑽、ランチの記録、個人的なタスクに使った時間など、勤務時間とは別で何らかの時間管理をしたい場合には便利かもしれません。

ライフログについては管理者がエクスポートできる月次レポート（後述）には含まれません。とはいえ、**このアプリのデータストアに直接アクセスする権限を持つユーザーがクエリを実行すれば閲覧できる**データではあるので、その旨理解された上で活用されるのがよいかと思います。

### 打刻利用イメージ

一日が始まった時点で画面を開くとこちらのような画面が表示されます。

**とにかくワンリクックで「勤務開始」を押すだけ！** です。これなら誰でも迷うことなく使えるはずです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/9da2f3ce-56b5-7378-d5ba-329bd48c87e2.png" width=400 />

なお、ライフログを有効にしている場合、「ライフログ開始」のボタンも表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/afff8f68-7039-a709-3a27-7cd0aad91fd3.png" width=400 />

勤務が始まってからは **「休憩開始」「勤務終了」のボタンだけ** が表示されます。これも直感的に使えるはずです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/1d7656d2-cd28-15e9-57c1-f860ccd034ef.png" width=400 />

休憩中は **「休憩終了」だけ** が表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/a8d945ea-1b67-fa0f-adcf-c43ff5cf43b3.png" width=400 />

このように次にやるべきことがシンプルにボタン配置されていますので、モバイルからでも簡単に使えるはずです。

また、真に打刻した時間だけを勤怠ログとして認めたいという場合、「管理者メニュー」の「組織ポリシー」で履歴の修正や手入力を禁止することもできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/02ca6f25-5131-bf12-7077-d4573ad5a150.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/640a3632-3d3f-da4e-a80e-5d5a63f0a69c.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/4e3fe0f0-a571-9e19-ca21-b32225830b84.png" width=400 />

この状態だと画面上から履歴の編集と手入力メニューがなくなって、ワンクリックの打刻ボタンだけが使えるようになります。メニューに表示されている「終了」は打刻ボタンと同じ操作です。また、「削除」はクリックミスなどで発生した不要データの対処のために残してあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/dd528950-3215-b159-0a99-d7340be00ca6.png" width=400 />

### カレンダービュー

勤怠データの入力は基本的に今日のデータしか扱わないですが、過去データの確認や未来の休暇予定をあらかじめ登録しておきたいという場合のために他の日に移動できるようになっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/8c16533c-82cb-e7b9-8e1c-78081c538ae0.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/714015b6-6744-2606-c0cb-e3f1a658f75f.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/71866db1-75b0-80e8-d7e1-5b6b12b6d7ba.png" width=400 />

### 月次レポート

勤怠管理で一番重要なのは、毎月のデータを正しくシステムで管理することです。

理想的には組織で利用されている勤怠システムと自動で連動できるとよいのですが、それはなかなか難しい現実もあります。そのため、このアプリでは画面上でのサマリー表示とその生データである JSON 形式のフルデータをダウンロードできるようにしています。構造化されたデータなので、それをうまく処理してデータ連携を自動化したり、手作業を楽にすることも（ある程度は）可能ではあると思います。

そして、組織のポリシーに合わせて二つの利用方法を想定しています。

1. 各ユーザーが自分の月次レポートを元に自ら勤怠システムに連携する
1. 上記の打刻のみモードを有効にして、管理者が全員の月次レポートを取得して勤怠システムに連携する

1 の形で運用しているケースも多々あるとは思いますが、厳格な運用が必要な場合は 2 の設定で利用するとよいかと思います。

自分向けの月次レポートはこのような画面表示です（ライフログを有効にしている場合はライフログのサマリーも含めることを選択できます）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/7b931555-8a62-aeef-e323-05a4f4433a88.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/20e82955-59e8-ecc2-613e-bc3ebbc4e806.png" width=400 />

「このレポートを DM で送る」をクリックすると、以下の通り、同じ内容と生データの JSON 形式のファイルが添付されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/eb1c91ab-f9b5-b273-e7a6-54e0d131b9c3.png" width=400 />

管理者がデータ管理する場合は、管理メニューから全員分のデータをまとめた JSON 形式のデータのダウンロードを依頼できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/40d7175e-8b56-cb29-6218-bd5f8cb20b2a.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/211205b5-e24c-1f1f-06f9-61f2478dc1cd.png" width=400 />

現時点では、あらゆる入力パターンに対応できるということもあり JSON データのみで出力していますが、シンプルな勤怠の形（例：一日の中で勤務時間が細切れになることが一切なく、休憩も一回だけを想定している場合）であれば、CSV 形式で出力できるようなオプションを追加しても良いかもしれないと思っています。

### 管理者メニュー

このアプリでは管理者向けの機能をいくつか提供しています。アプリをデプロイした直後は、プレビューの目的ですべてのユーザーがこのメニューにアクセスできるようになっていますが、データストアに管理者を登録することでアクセス可能なユーザーを制限することができます。

実運用する前に、管理者の Slack ユーザー ID を調べて、以下のようなコマンドで管理者を登録してください。管理者は何人でも登録できます。

```bash
slack datastore put '{"datastore": "admin_users","item": {"user": "W111111"}}'
slack datastore put '{"datastore": "admin_users","item": {"user": "W222222"}}'
```

それでは、管理者メニューでできることを紹介していきます。

#### 管理者向けレポートダウンロード

こちらは上で紹介したので割愛します。

#### 組織ポリシー

現時点では、上で説明した手入力の可・不可と新規ユーザーが利用開始する際にあらかじめ国を指定するか、の二点を設定できるようになっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/6e29a8a0-9742-fe12-4a50-61b268c8e95f.png" width=400 />

これについても一般的なご要望があれば、取り込んでいきたいなと思っています。

#### プロジェクト設定

精緻な勤怠管理が必要となる場合、一日の中でどのプロジェクト・プロダクト・組織についてどれだけ時間を使ったかを管理する機能が必要です。

このユースケースをサポートするために「プロジェクト管理」という概念で各勤務時間にタグをつけられるようにしています。

プロジェクト管理画面で一つでも有効なプロジェクトコードを登録すると、勤務を入力するときにプロジェクトコードを選択するよう促されるようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/df48fd8e-97d7-d565-173a-876dc6a35e79.png" width=400 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/ea4610a3-1ad3-c686-983c-c2ef75232cda.png" width=400 />

使い終わったコードは無効化することができます。以下の画面だと FY22 のものだけ無効化されています。無効化されたものは勤務登録時に選択できなくなります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/4c0375e6-5dcb-6523-f538-3e9cbb85939b.png" width=400 />

勤務ログにつけたプロジェクトコードは月次レポートにも反映されます。

### ライフログ

最後にオプションであるライフログ機能について紹介します。ライフログは勤務時間とは連動せず、自由に使った時間にタグをつけられる機能です。

メニューの「ユーザー設定」から「アプリ利用モード」を変更すると有効にできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/94d565e5-f7c8-db18-5de5-963b2dfa1b44.png" width=400 />

初めて使うときは何もライフログの候補がありません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/0d497e8d-b2b0-438f-f872-5b5a2a046b7b.png" width=400 />

検索ウィンドウの中でわかりやすい名前を自由に入力して選択してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/c20a4f8f-fbf0-1c2c-a76e-bf1a6c5ec595.png" width=400 />

次回からは候補に表示されるようになります。また、直近でよく使っているものが上位に表示されるように実装されていますので、わざわざキーワード検索しないといけないということはなく、簡単に使えるようになっているはずです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/8fdb93f5-7e95-b522-1774-459ee02f460d.png" width=400 />

上で説明した通り、管理者は画面上ではアクセスできないものの、データストアを検索すれば閲覧可能なデータですので、その点留意の上活用してみてください。

### ウィンドウ自動更新

ウィンドウを開きっぱなしで利用していると、最新の状態にするためにいちいち「更新」ボタンを押すことが煩わしく感じられるかもしれません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/64a23f8e-693f-1acc-202b-a3a46ebf880d.png" width=400 />

その場合は以下のコマンドで新しいスケジュールトリガーを作ってください。

```bash
slack trigger create --trigger-def triggers/start_active_view_refresher.ts
```

このトリガーは 30 分おきに開かれているウィンドウを自動更新してくれるワークフローを実行します。このワークフローは毎日一度起動して 30 分おきにメインの画面を開いているアクティブなウィンドウを最新化してくれるものです。

~~これを有効にすると、[こちらのページ](https://slack.com/intl/ja-jp/help/articles/15363357403411)に記載の「プレミアムワークフロー」としての追加コストが一日につき一回だけかかります。~~ **2024/9/26 追記: 米国時間 2024/9/25 以降、[全ての機能は Slack の有料プランに含まれ、一切の追加請求は行わない](https://slack.com/intl/ja-jp/help/articles/31660994380179)というポリシー変更が発表されました。**

### 終わりに

最後にいくつか注意点がありますので、必ずご確認ください :bow:

* ~~このワークフローは、トリガーからの起動毎に **「プレミアムワークフロー」としての利用料金がかかります**（一度ウィンドウを開いて、それを閉じずに操作している間は追加費用はかかりません）。大規模なご利用は[こちらのページ](https://slack.com/intl/ja-jp/help/articles/15363357403411)をご確認の上でご検討いただくようお願いいたします。~~ **2024/9/26 追記: 米国時間 2024/9/25 以降、[全ての機能は Slack の有料プランに含まれ、一切の追加請求は行わない](https://slack.com/intl/ja-jp/help/articles/31660994380179)というポリシー変更が発表されました。**
* こちらは **プラットフォームの啓蒙活動の一環として提供しているサンプルコード**となります。そのため、Slack のカスタマーサポートではサポート対象外であることをご了承ください。技術的なご質問等ございましたら[こちら](https://github.com/seratch/slack-timesheet/issues)からご連絡ください（日本語で OK です）。
* こちらのアプリコードは **MIT ライセンスで公開しているオープンソースソフトウェア**です。ご自由に改変・再利用してお役立てください。

最後までお読みいただき、ありがとうございました！

ぜひ `slack deploy` して動かしてみてください。また、色々とカスタマイズしたいという場合は `slack run` で起動してコードを直接変更してみてください。

それでは！ :rocket: