Skip to content

シフト通知機能の本番移行と通知のグループ化 #246

@taminororo

Description

@taminororo

開発概要

目的

  • モックリポジトリ(/workspace/seeft-slack-notification_mock)のシフト通知機能を本番リポジトリ(/workspace/SeeFT)へ移植する
  • 1セル(15分)ごとのスパム通知を解消するグルーピングロジックを実装する
  • 同一ユーザー・同一日付の変更を1通にまとめ、連続時間を期間表示し、変更内容をリスト化する
  • 変更前: undefined バグを修正する

開発期間

  • 開始日:
  • 締切日:

考えられる開発内容

Phase 1: 基盤整備

データベーススキーマの追加

  • mysql/db/create_action_log.sql を作成(action_logテーブル定義)
    • id (SERIAL PRIMARY KEY)
    • shift_id (INTEGER, FOREIGN KEY to shifts)
    • user_id (INTEGER, FOREIGN KEY to users) - グルーピング用
    • date_id (INTEGER, FOREIGN KEY to dates) - グルーピング用
    • action_type (VARCHAR(50)) - "CREATE", "UPDATE", "DELETE"
    • diff_payload (JSONB) - 変更内容
    • is_sent (BOOLEAN DEFAULT FALSE) - 送信済みフラグ
    • created_at (TIMESTAMP)
  • mysql/db/add_slack_user_id_to_users.sql を作成(usersテーブルにslack_user_idカラム追加)
    • ALTER TABLE users ADD COLUMN slack_user_id VARCHAR(255)
  • api/lib/entity/action_log.go を作成(ActionLogエンティティ定義)
  • api/lib/entity/user.go を更新(SlackUserIDフィールド追加)

リポジトリ層の実装

  • api/lib/internals/repository/action_log_repository.go を作成
    • Create(ctx, shiftID, userID, dateID, actionType, diffPayload) error メソッド実装
    • GetUnsentLogs(ctx) (*sql.Rows, error) メソッド実装(未送信ログ取得)
    • GetUnsentLogsByUserAndDate(ctx, userID, dateID) (*sql.Rows, error) メソッド実装(グルーピング用)
    • MarkAsSent(ctx, logIDs []int) error メソッド実装(送信済みフラグ更新)

Phase 2: 通知機能の移植

Slack通知サービスの実装

  • api/lib/externals/slack/slack_service.go を作成
    • Slack APIクライアントの初期化
    • メッセージ送信機能(チャンネル + DM)
    • 環境変数から設定読み込み(SLACK_BOT_TOKEN, SLACK_CHANNEL_ID
    • 参考: /workspace/seeft_slackNotification_mock/backend/internal/service/slack_service.go

ShiftUseCaseへの統合

  • api/lib/usecase/shift_usecase.goUpdateShiftsFromGAS メソッドを更新
    • シフト変更時にaction_logへ記録する処理を追加
    • oldValnilの場合のハンドリング(CREATE時)
    • newValnilの場合のハンドリング(DELETE時)
    • undefinedバグの修正(nilチェック追加)
    • 参考: /workspace/seeft_slackNotification_mock/backend/internal/service/shift_service.gologAction メソッド

Phase 3: グルーピングロジック実装(最重要)

NotificationUseCaseの実装

  • api/lib/usecase/notification_usecase.go を作成
    • ProcessUnsentNotifications(ctx) error メソッド実装(未送信通知を処理)
    • GroupNotificationsByUserAndDate(logs []ActionLog) map[string][]ActionLog メソッド実装(ユーザー・日付でグルーピング)
    • CalculateTimeRange(timeIDs []int) (startTime, endTime string) メソッド実装(連続時間を計算)
      • 例: [25, 26, 27] -> "07:30 〜 09:00"
    • BuildGroupedMessage(group []ActionLog) string メソッド実装(グルーピング済みメッセージ生成)
    • メッセージフォーマット例:
      ✨ シフト変更通知
      
      ユーザー: 田中太郎
      日付: 1日目
      天気: 晴れ
      
      【変更内容】
      07:30 〜 09:00
        - タスク: 受付 → 案内
        - タスク: 受付 → 撤収
      
      09:30 〜 10:30
        - タスク: 撤収 → 受付
      

Phase 4: バッチ処理実装

通知ワーカーの実装

  • api/lib/usecase/notification_worker.go を作成(オプション、またはNotificationUseCaseに統合)
    • 定期的に未送信ログを取得する処理(例: 5分ごと)
    • NotificationUseCase.ProcessUnsentNotifications()を呼び出し
    • エラーハンドリングとリトライロジック
  • api/main.go を更新
    • ワーカーをgoroutineで起動する処理を追加
    • 例:
      go func() {
          ticker := time.NewTicker(5 * time.Minute)
          defer ticker.Stop()
          for range ticker.C {
              if err := notificationUseCase.ProcessUnsentNotifications(ctx); err != nil {
                  log.Printf("Failed to process notifications: %v", err)
              }
          }
      }()

DI(依存性注入)の更新

  • api/lib/di/di.go を更新
    • ActionLogRepositoryの初期化を追加
    • SlackServiceの初期化を追加
    • NotificationUseCaseの初期化を追加(必要な依存関係を注入)

環境変数の追加

  • api/env/dev.env を更新
    • SLACK_BOT_TOKEN=xoxb-... を追加
    • SLACK_CHANNEL_ID=C1234567890 を追加

備考

  • usersテーブルのslack_user_id: 既存データへの影響を考慮し、NULL許可とする
  • 送信タイミング: 即座送信ではなく、バッチ処理で定期的に送信(5分間隔を推奨)
  • エラーハンドリング: Slack送信失敗時もログを残し、リトライ可能にする
  • パフォーマンス: 大量の未送信ログがある場合の処理時間を考慮
  • 確認事項:
    • usersテーブルにslack_user_idカラムを追加する方針で問題ないか
    • 通知の送信間隔(5分)で問題ないか
    • Slackチャンネルへの通知も必要か(現状はDMのみの想定)

参考

データフロー

GASからのシフト変更
  ↓
UpdateShiftsFromGAS (ShiftUseCase)
  ↓
action_logに記録 (ActionLogRepository)
  ↓
action_logテーブル (DB保存)
  ↓
NotificationWorker (定期的に未送信ログ取得)
  ↓
user_id, date_idでグルーピング (NotificationUseCase)
  ↓
連続時間を計算
  ↓
グルーピング済み通知
  ↓
Slack送信 (SlackService)
  ↓
送信済みフラグ更新

ディレクトリ構造

api/lib/
├── entity/
│   ├── action_log.go (新規)
│   └── user.go (slack_user_idフィールド追加)
├── internals/
│   ├── repository/
│   │   └── action_log_repository.go (新規)
│   └── controller/
│       └── notification_controller.go (新規、オプション)
├── externals/
│   └── slack/
│       └── slack_service.go (新規)
└── usecase/
    ├── notification_usecase.go (新規)
    └── notification_worker.go (新規、オプション)

参考ファイル

  • モックリポジトリ: /workspace/seeft_slackNotification_mock/backend/internal/service/slack_service.go
  • モックリポジトリ: /workspace/seeft_slackNotification_mock/backend/internal/service/shift_service.go
  • モックリポジトリ: /workspace/seeft_slackNotification_mock/backend/internal/repository/action_log_repository.go
  • 本番リポジトリ: /workspace/SeeFT/api/lib/usecase/shift_usecase.go (1360行目〜)
  • 本番リポジトリ: /workspace/SeeFT/api/lib/internals/repository/shift_repository.go

開発の流れ

  1. PMにIssue(タスク)をもらう
  2. 開発をする(↓の「リンク」の『開発のやり方』を見よう!)
  3. チェックボックスを押していこう
  4. ヤバい状況になったらIssueの右側にあるStatusを「Help」にしてPMにSlackで連絡しよう
  5. チェックボックスが全部押せたらプルリクを作ろう
  6. レビューを待とう
  7. 修正点があれば修正しよう。なければPMがマージします!お疲れ様!

SeeFTのタスク管理のルール

  1. タスクは全てGit-Hub Projectで管理する
  2. 全てのタスクに期日を決める
  3. 毎週タスクの進捗を確認する(MTに出られない人はSlackで報告)
  4. 毎週忙しさ(消化できるタスク量)を共有する
  5. Helpは余裕のある人がいれば巻き取る。いなければ期日を変更する

リンク

Sub-issues

Metadata

Metadata

Labels

Size-L開発時間の目安は20時間✨Backendバックエンドのタスク. 主にGo, TypeScriptを使用✨Databaseデータベースのタスク. 主にPostgreSQLを使用優先度0Must, Minimum・最低限実装しないといけない枠

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions