はじめに
ログインユーザーごとにSlack連携を許可 → そのユーザーのタスクを毎朝自動でSlackへ通知
…という仕組みをLaravelアプリで構築した手順をまとめます💪
🔧 ゴール
・タスク管理アプリ(Laravel)とSlackを連携
・ユーザーごとにSlack連携が可能(OAuth)
・毎朝決まった時間に、そのユーザーの今日のタスクをSlackへ自動DM通知
🗺 全体の流れ(設計〜実装)
graph TD
A[① Slackアプリ作成] --> B[② LaravelにSlack認証組込み]
B --> C[③ ユーザーごとに連携情報を保存]
C --> D[④ 通知バッチコマンド作成]
D --> E[⑤ スケジューラ登録]
E --> F[⑥ ngrok本番化 or 本番URLで運用]
① Slackアプリを作成
1. https://api.slack.com/apps へアクセス
2. 「Create New App」 → “From scratch”
3. 「App Name」 と 「Workspace」 を選択
→ 自由で良い
4. 左側メニュー「OAuth & Permissions」を開き以下を設定
設定項目 | 設定内容 |
---|---|
Redirect URL |
https://ドメイン/slack/callback (後で使う) |
Bot Token Scopes |
chat:write , channels:read , users:read 等 |
Redirect URL
「Add New Redirect URL」
↓
「https://ドメイン/slack/callback」を入力
Redirect URL
本番環境は、本番用のURLでOK
開発環境は、Slack側がhttpを許可してくれないので、httpsを用意する必要がある。
以下で準備する。
↓
「Save URLs」でOK
Bot Token Scopes
「Add an OAuth Scope」
↓
検索欄でchat:write
, channels:read
, users:read
らを入力し、選択でOK
5. 「Install App to Workspace」ボタンを押し、インストール
初回と以下の画像は違う。
「Install to AppName」という白いボタンが
インストール(=Install App to Workspace)に該当します。
6. 表示される以下の値を控える(Laravelで使う)
名前 | 意味 |
---|---|
Client ID | OAuthのID |
Client Secret | OAuthのSecret |
Bot User OAuth Token | (xoxb〜 )使わないが参考値 |
「Client ID」「Client Secret」の場所
「Settings」→「Basic Information」→「App Credentials」
「Bot User OAuth Token」の場所
「Features」→「OAuth & Permissions」→「OAuth Tokens」
② DB用意 & model
Slack連携に必要な情報は、既存の users(ユーザー)・tasks(タスク) テーブルとは別に
新たに slack_notifications テーブルを追加して管理します。
1. 📘 テーブル定義(slack_notifications)
カラム名 | 型 | NULL | 備考 |
---|---|---|---|
id | bigint | NO | 主キー AUTO_INCREMENT |
user_id | foreignId | NO | users.id 外部キー |
slack_user_id | string | YES | SlackのユーザーID(DM送信用) |
slack_team_id | string | YES | ワークスペースID |
bot_access_token | text | YES | OAuthトークン |
is_enabled | boolean | NO | 通知ON/OFF(初期値 false) |
last_sent_at | timestamp | YES | 最終通知日時 |
created_at | timestamp | YES | 作成日時 |
updated_at | timestamp | YES | 更新日時 |
2. 🔗 ER図(関連図)
3. 🛠 マイグレーションファイル
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up()
{
Schema::create('slack_notifications', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('slack_user_id', 100)->nullable();
$table->string('slack_team_id', 100)->nullable();
$table->text('bot_access_token')->nullable();
$table->boolean('is_enabled')->default(false);
$table->timestamp('last_sent_at')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('slack_notifications');
}
};
4. Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SlackNotification extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'slack_user_id',
'slack_team_id',
'bot_access_token',
'is_enabled',
'last_sent_at',
];
// ▼Userリレーション
public function user()
{
return $this->belongsTo(User::class);
}
}
public function slackNotification()
{
return $this->hasOne(SlackNotification::class);
}
③ .env
SLACK_CLIENT_ID=xxxxxxxxx
SLACK_CLIENT_SECRET=xxxxxxxx
SLACK_REDIRECT_URI=https://〜/slack/callback
④ routes → Blade →Controller
1. routes/web.php
Route::get('/slack/authorize', 'SlackController@redirectToSlack')->name('slack.authorize');
Route::get('/slack/callback', 'SlackController@handleCallback')->name('slack.callback');
2. 「Slack連携」ボタン(Blade)
// blade
<a href="{{ route('slack.authorize') }}" class="btn btn-primary">
Slack連携
</a>
3. SlackController
class SlackController extends Controller
{
public function redirectToSlack()
{
$url = "https://slack.com/oauth/v2/authorize";
$params = [
'client_id' => env('SLACK_CLIENT_ID'),
'scope' => 'chat:write,channels:read,users:read',
'redirect_uri' => env('SLACK_REDIRECT_URI'),
];
return redirect($url . '?' . http_build_query($params));
}
public function handleCallback(Request $request)
{
$code = $request->code;
$response = Http::asForm()->post('https://slack.com/api/oauth.v2.access',[
'client_id' => env('SLACK_CLIENT_ID'),
'client_secret' => env('SLACK_CLIENT_SECRET'),
'code' => $code,
'redirect_uri' => env('SLACK_REDIRECT_URI'),
])->json();
// ユーザーごとのアクセストークンを保存
$token = $response['access_token']; // ユーザー用
$team_id = $response['team']['id'];
$slack_user = $response['authed_user']['id'];
SlackNotification::updateOrCreate(
['user_id' => auth()->id()], // ログイン中ユーザー
[
'slack_user_id' => $slack_user,
'slack_team_id' => $team_id,
'bot_access_token' => $token,
'is_enabled' => true
]
);
return redirect()->route('tasks.one_day')->with('success','Slack連携が完了しました!');
}
}
⑤ 通知の作成
1. バッチ用 Artisanコマンドを作る
php artisan make:command SendDailySlackNotification
2. バッチ用 Artisanコマンド内に記入
<?php
namespace App\Console\Commands;
use App\Models\SlackNotification;
use App\Models\Task;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class SendDailySlackNotification extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'send:daily-slack';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Slackに毎日通知する';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$users = SlackNotification::where('is_enabled', true)->get();
foreach($users as $sn) {
// 本日のタスクを取り出す例
$tasks = Task::where('user_id', $sn->user_id)
->whereDate('end_at', now()->toDateString())
->get();
$text = "今日のタスク一覧:\n";
foreach($tasks as $t){
$text .= "- {$t->title} ({$t->end_at})\n";
}
Http::withToken($sn->bot_access_token)
->post('https://slack.com/api/chat.postMessage',[
'channel' => $sn->slack_user_id,
'text' => $text,
]);
}
}
3. Kernel に登録
protected function schedule(Schedule $schedule)
{
$schedule->command('send:daily-slack')->dailyAt('04:00');
}
⑥ 開発環境でのテスト
1. Kernel.phpで、->everyMinute()に変更
protected function schedule(Schedule $schedule)
{
// $schedule->command('send:daily-slack')->dailyAt('04:00');
$schedule->command('send:daily-slack')->everyMinute();
}
2. アプリがある箇所で、ngrokを起動
pwd
# 例 /Users/hondaakihito/Laravel/Docker/task-reminder
ngrok http 8080
Docker内で、コマンドを打つ
php artisan schedule:run
⑦ 本番環境
cron に登録
* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1
↓