マナリンクにおける社内Slack通知の活用と実装の工夫

2021/11/12に公開

マナリンクを運営する株式会社NoSchool社内で、どのようにSlack通知を活用しているかをまとめてみます。

  • 社内全体向けの通知
  • エンジニア向けの通知
  • Slack通知をどうやって実装しているか
  • 今後やっていきたいこと

の順番で書いていきます。

マナリンクの概要

マナリンクはオンライン家庭教師とご家庭のマッチングサービスを主軸とする事業です。

マナリンクの売上は現在保護者さんが先生に支払う指導料金の一定割合をいただく形で成り立っているので、サービスの売上が立つまでには、簡単に言うと以下のような手順をたどることになります。

  1. マナリンク上に登録した先生が、各自の指導内容を記した「指導コース」を公開する
  2. 指導コースをWebサイト上で閲覧した保護者さんや生徒さんが「お問合せ」する
  3. お問合せ後、先生とご家庭で費用面や指導内容の認識が擦りあったら「お支払い」する

それぞれにおいて、社内メンバーが都度都度データベースや管理画面をチェックしなくても受動的にチェックしたいために、Slack通知を活用しています。

※逆に言えば、まだSlack通知さえすれば皆ある程度把握できる程度の規模のサービスということです。もっと成長して通知が追いきれなくなったら社内管理画面への統合など別の仕組みが必要でしょう。

社内全体向けの通知

指導コース作成通知

まずは先生が指導コースを作成するたびにSlack通知が届きます。先生はいくつでも指導コースを作れるので、先生ごとにどれくらいの量の指導コースを作っているかが分かることはもちろん、各指導コースがWebページ上に表示される際のサムネイル画像は、希望した先生には社内でCanvaで作成したものを当てているので、それを担当者が見てサムネイル画像を作るための通知でもあります。

スクリーンショット 2021-11-12 15 33 03

指導コースの「検討リスト」への追加を通知

先生を探している保護者さんや生徒さんは、マナリンクを回遊して一旦ブックマークとして検討リストという機能に追加することがあります。これも社内通知します。

特に初めてマナリンクで指導コースを公開した先生は、初お問合せがあるまではプロフィールやコースの内容を改善してお問合せされやすいプロフィールを追求していきます。検討リストに追加されたことを先生と担当営業で共通認識を持って改善に役立てています。

スクリーンショット 2021-11-12 15 38 02

お問合せ通知

ご家庭から先生にお問合せがあったときもSlack通知されます。

スクリーンショット 2021-11-12 15 43 47

売上通知

そして先生と保護者さんとの打ち合わせの結果、無事に指導お願いしますとなったら決済が行われ、以下の通知が届きます!若干Slackボット名で遊んでいるのはご愛想で。細かいですが、手数料を頂いている弊社の場合、ご家庭からお支払いされた金額は流通額で会社の売上とイコールではないのでタイトルは「流通額通知」としています。

スクリーンショット 2021-11-12 15 55 36

多くの先生が人生で初めてオンライン家庭教師という職業に挑むので、初めて売上が立つのはおめでたいことです。以下のように代表がよくSlackの雑談板で初めて決済された先生をシェアします。

スクリーンショット 2021-11-12 16 23 08

ユーザーの声

最後に、実際に指導が行われたら保護者さんや生徒さんから先生や我々に向けてお礼のコメントが届くことがあります。これは感謝の声という機能で、投稿された内容は一部マナリンクのサイト上でも公開されています。

そして届いた感謝の声には先生が返信することもできます。その一連の流れが全部Slackの「ユーザーの声」チャンネルに流れます。

実際にWebページ上でも感謝の声が見れるのでよかったら見てみてください!

▼上記のスクショの内容はこちら

https://manalink.jp/teacher/10736/thanks-messages/185

他の例

https://manalink.jp/teacher/6346/thanks-messages/178

その他の通知

他にもいろいろと通知があります。通知は全部同じチャネルに通知すると秒で流れてしまうため、数種類のカテゴリに分けて個別のSlackチャネルに通知させています。

  • お問合せを受けた先生が一定時間ご家庭に返信していないと、社内アラート板に通知→担当営業が念の為に連絡
  • 月額課金していたご家庭が支払いを停止すると通知

エンジニア向けの通知

本記事では詳細を割愛しますが、エンジニア向けのSlack通知もあります。たとえば以下のようなものです。

  • アプリケーション上でエラーが検知された際の通知
    • SentryやCloudWatch + Lambdaを活用
  • ステージングおよび本番環境へのデプロイ開始/終了通知
    • GitHub Actionsから通知
    • CodeDeploy -> SNS -> Lambdaで通知
  • サーバーやサイトマップの監視結果の通知
    • AWS SNSやStep Functionsから実行するLaravelバッチから通知

Slack通知をどうやって実装しているか

現在のマナリンクでは、社内向けSlack通知は基本的にLaravelアプリケーション上で起こったイベントに対する通知なので、Laravelから直接SlackのSDKを叩いて通知を実行しています。

Slack通知を送信する処理は、LaravelのFacade機能を使ってメール通知と同じような実装で送信できるようにしてあります。

SlackNotification::send(new HogeNotificationToSlack($hogeEntity));

sendメソッドの引数に渡すHogeNotificationToSlackクラスがSlack通知の内容を管理しているクラス(以下SlackNotificationクラス)です。

final class HogeNotificationToSlack extends BaseSlackNotification
{
    public HogeEntity $hogeEntity;

    /**
     * HogeNotificationToSlack constructor.
     * @param HogeEntity $inquiry
     */
    public function __construct(HogeEntity $hogeEntity)
    {
        $this->hogeEntity = $hogeEntity;
    }

    public function toSlack($notifiable): SlackMessage
    {
        return (new SlackMessage())
            ->warning()
            ->content('ほげほげ')
            ->attachment(function (SlackAttachment $attachment) {
                $attachment
                    ->fields([
                        'hoge' => $this->hogeEntity->getTitle(),
                        'hoge' => 'fuga',
                        'hoge' => 'fuga',
                        'hoge' => 'fuga',
                        'hoge' => 'fuga',
                    ]);
            });
    }

    public function getChannel(): SlackChannel
    {
        return new SlackChannel(SlackChannel::USER_ACTION);
    }
}

getChannelメソッドが独自の工夫で、各SlackNotificationクラスが必ず実装するメソッドになります。これがSlackChannelというENUMを返します。

SlackNotificationクラスは必ずBaseSlackNotificationを拡張する必要があるのですが、以下のように抽象クラスで抽象メソッドgetChannelを持っています。

abstract class BaseSlackNotification extends Notification
{
    /**
     * Get the notification's delivery channels.
     *
     * @param mixed $notifiable
     * @return array
     */
    public function via($notifiable): array
    {
        return ['slack'];
    }

    // 中略

    /**
     * このSlackメッセージをPOSTすべきチャネルを返す
     * 前提として、特定のメッセージを複数のチャネルで使い回すことがないはずなのでSlackMessage側に依存させる
     * @return SlackChannel
     */
    abstract public function getChannel(): SlackChannel;
}

現状、同じSlack通知を複数のチャネルに流したいというニーズはなく、今後追加されることも想像しにくいため、SlackNotificationクラスがチャネルを持つように設計するときれいかなと思いました。

他にも、Slack通知を飛ばすUseCaseクラスでSlackチャネルを指定する方法もありますが、同じSlack通知を複数のUseCaseから呼び出すことは普通にありえる事象なので設計としては今回の指針のほうが妥当と考えています。

SlackChannelクラスは以下のようなEnumクラスです。基底クラスとなるEnumの実装はよく言われるやつなので割愛します。

final class SlackChannel extends \App\Domain\Base\Domain\ValueObject\Enum
{
    public const MONITORING = 'monitoring';
    public const USER_ACTION = 'userAction';
    public const USER_VOICE = 'userVoice';
    // 以下略
}

逆にFacadeで実装しているSlackNotificationの実装クラスでは、受け取ったSlackNotificationクラスからgetChannelメソッドを実行して得たEnumをもとに、適切なSlackチャネル情報を環境変数から取得してきて、実際の通知処理を実行する感じです。

今後やっていきたいこと

最近Redashをセットアップしたので、たとえば都度都度の流通額を通知するのではなく、月ごとに毎日積み上げられていく累計の売上を毎朝流したり、それらをグラフ化して流すことも可能になってきました。

Slack通知の効果は、自分から見に行かなくても情報が入ってくるという点が大きいと思っていて、やはり売上やユーザーの声などのKPI(サービスの価値)に関わる部分を流すのが全職種にとって効果的なのかなと思っています。

実装面で言うと、Laravelから直接Slackに通知しちゃうと横展開ができないので、本当は通知の形式をあらかじめ決めたJSON形式にしてS3にアップロードするとAWS SQSやSNSを通して任意の箇所に通知したりそれを蓄積するような基盤を引くのも良いんだろうなと思ったりします。

このように事業の数値やユーザーの反応に距離が近い環境で開発を進めていきたいエンジニアの方を絶賛採用中です。ぜひ話を聞きに来てください!

マナリンク Tech Blog

Discussion