SlackWF→GoogleSheet→NotionDB連携による問い合わせ管理

# はじめに
:::note warn
本記事に記載のコードの中身については、全てを1から私が記載したわけではありません。あくまでも参照元に倣って自分でも作ってみて、一部改造を記録した記事です。詳細は参照記事をご覧ください。
また、本ページは備忘録であり、ご覧いただいた皆さんからの問い合わせなどは受け付けていません。
:::



# 概要
- 現状、以下に記載の課題と対応が必要。

| 事実 | 課題 | 対応 |
| --- | --- | --- |
| 投稿内容・粒度が統一されていない。 | 内容確認（緊急度、事象のスクショ・エラーコードなど）に一定回数のラリーが必要。| SlackWFで投稿内容をフォーマット化 |
| メンション先が統一されていない。 | メンションがついていない・特定人物のみを指定している場合、他の情シスメンバーが気付きづらい | SlackWFに投稿された際に、helpdeskチームにメンションされる設定にする |
| 対応状況を一元管理できていない。 | 対応状況の管理ができておらず、対応漏れが起きやすい | SlackWFに投稿された内容はNotionDBに起票され、対応状況を管理できるようにする |

- 最終的にはSlack botなどを用いて完全自動化を目指したいが、工数・現運用メンバーでは対応が難しいため、暫定的な運用として本運用を実施する。

## 必要なもの
- Notion インテグレーショントークン
- 有料版Slack（SlackWFを構築するために必要）
- SpreadSheet


## フローの概要
```mermaid
sequenceDiagram

%% ステークホルダーを定義
    participant User    as ユーザ
    participant WF      as SlackWF
    participant Admin   as 管理者
    participant Sheet   as SpredSheet
    participant DB      as NotionDB

%% 具体的なフローを記載
    Note over User: 情シスへの相談・質問の発生
    User ->> WF : 投稿
    WF -->> Sheet : 内容を転記
    Sheet -->> DB : 内容を転記
    Admin ->> Admin: helpdeskチームメンションにきづき<br>内容を把握する
    Admin ->> User : 会話
    User ->> Admin : 会話
    Admin ->> DB : ステータスを更新する
```

# 詳細
## 問い合わせフロー
#### 凡例

- ❗：課題
- 🤔：検討事項
- 実線：手動
- 点線：自動

#### フロー図

```mermaid
sequenceDiagram

%% ステークホルダーを定義
    participant User    as ユーザ
    participant WF      as SlackWF
    participant Admin   as 管理者
    participant Sheet   as SpredSheet
    participant DB      as NotionDB

%% 具体的なフローを記載
    Note over User: Adminへの相談・質問の発生
    User ->> User : Public/Privateを判断
    note right of User:🤔Public/Privateの判断基準
    note right of User:❗本来Privateで投稿すべき内容の誤投稿
    note right of User:🤔Privateの場合は＃helpdeskに<br>投稿されない仕組みにできないか

alt PublicでOKな場合
    Note over User: ＃helpdesk
    User ->> WF : SlackWFにて相談内容を投稿
    WF -->> WF : ＃helpdesk に起票内容を投稿
    WF -->> Admin : helpdeskチームにメンション
    WF -->> Sheet : 起票内容を転記
    Sheet -->> DB : 起票内容を転記
    Admin ->> DB : 内容を確認
    Admin ->> DB : 対応ステータスを[進行中]に更新
    Admin ->> User : 会話
    User ->> Admin : 会話
    Admin ->> DB : 情報を更新

    %% 対応状況にあわせたステータスを選択
    alt 対応が完了した場合
        Admin ->> DB : ステータスを[完了]に更新
        Admin ->> WF : [done]スタンプをつける

    else 対応が不要な場合
        Admin ->> DB : ステータスを[アーカイブ]に更新
        Admin ->> WF : [done]スタンプをつける

    end

else Private必須な場合
    Note over User: ＃Private
    User ->> Admin : Privateチャンネルを作成・内容を投稿
    Admin ->> User : 会話
    Admin ->> DB : 内容を記載
    Admin ->> DB : 対応ステータスを[進行中]に更新
    User ->> Admin : 会話
    
    alt 対応が完了した場合
        Admin ->> DB : ステータスを[完了]に更新
        Admin ->> Admin : Privateチャンネルをアーカイブ

    else 対応が不要な場合
        Admin ->> DB : ステータスを[アーカイブ]に更新
        Admin ->> Admin : Privateチャンネルをアーカイブ

    end
end

Note over User,DB: 問い合わせ対応終了
note over Admin:🤔対応後の内容分析・再発防止のための手段
```

## SlackWFの構成
#### ユーザの投稿内容

| 質問事項 | 回答方法 | 補足 |
| --- | --- | --- |
| 緊急度を教えてください。 | プルダウン。低（1週間以上）/中（1週間以内）/高（3日以内）/緊急（当日） | 必須回答 |
| 参考情報があれば教えてください。 | 自由記述 | 任意回答。エラーメッセージやURLなどの記載を想定。 |
| 参考となる画像・ファイルがあればアップしてください。 | ファイルをアップロード | 任意回答 |
| 備考 | 自由記述 | 自由記述。明確な期日がある場合や捕捉事項などの記載を想定。 |

#### イメージ画像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/621a2e10-acee-14b4-5306-eb15ebedaee1.png)
![test_helpdesk_-_Belong_Inc__-_Slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/4a2c2937-f844-ba52-8535-ccb0cded3306.png)

## SpreadSheetの構成
#### 実際のシート
![NotionDB書き込み用SS_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/ca90fcc9-838f-f516-36ea-71d13a835001.png)

#### NotionDBに転記するためのGAS
- スプレッドシートが編集されると実行されるトリガーを設定


```jsx
function getLastRowData() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('rawdata');
  const dbId = PropertiesService.getScriptProperties().getProperty('NOTION_DB_ID'); // dbId を取得

  // 最終行の行番号を取得
  const lastRow = sheet.getLastRow();

  // 列の数を取得（ここでは5列まであると仮定）
  const numColumns = 5; // 適切な列の数に変更してください

  // 最終行のデータを取得
  const rowData = sheet.getRange(lastRow, 1, 1, numColumns).getValues()[0];

  // オブジェクトを生成
  const pageObj = {
    parent: {
      database_id: dbId,
    },
    properties: {
      "送信者": {
        "title": [
          {
            "text": {
              "content": rowData[1]
            }
          }
        ]
      },
      "緊急度": {
        "rich_text": [
          {
            "text": {
              "content": rowData[2]
            }
          }
        ]
      },
      "相談内容": {
        "rich_text": [
          {
            "text": {
              "content": rowData[3]
            }
          }
        ]
      },
      "備考": {
        "rich_text": [
          {
            "text": {
              "content": rowData[4]
            }
          }
        ]
      },

      // 他のプロパティも同様に修正してください
    }
  };

  // NotionAPIにポストしデータを追加
  postToNotion(dbId, pageObj);
}

function postToNotion(dbId, data) {
  const token  = PropertiesService.getScriptProperties().getProperty('NOTION_TOKEN');
  const apiUrl = 'https://api.notion.com/v1/pages';

  // NotionAPIにポストしデータを追加
  const options = {
    method: "POST",
    headers: {
      "Content-type": "application/json",
      "Authorization": "Bearer " + token,
      "Notion-Version": '2022-06-28',
    },
    payload: JSON.stringify(data),
  };

  UrlFetchApp.fetch(apiUrl, options);
}
```

## NotionDBの構成

![テストDB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/10fe087d-0f4a-ccd2-6137-6ba53a8f65ae.png)


# 参考
https://note.com/kawamura_/n/n66910a3d3743