TickTickとReclaim.aiを連携させて、タスクを自動でカレンダーにスケジューリングする
はじめに
タスク管理にTickTickを使っていますが、タスクをいつやるかを決めるのが面倒でした。Reclaim.aiはタスクを自動でカレンダーにスケジューリングしてくれる便利なサービスですが、残念ながらTickTickとのネイティブ連携がありません。
「なければ作ればいい」ということで、TickTickとReclaim.aiを繋ぐブリッジを開発しました。
この記事では、その開発過程と実装方法を紹介します。
やりたいこと
条件:
- 無料で運用したい(SaaSの有料プランは使わない)
- リアルタイムじゃなくてもいい(5分程度の遅延は許容)
- 優先度の低いタスクは同期しない
調査:実現可能か?
Reclaim.aiの対応サービス
まずReclaim.aiの公式連携を確認しました。
| サービス | 対応状況 |
|---|---|
| Todoist | 対応 |
| Asana | 対応 |
| ClickUp | 対応 |
| Linear | 対応 |
| Jira | 対応 |
| Google Tasks | 対応 |
| TickTick | 未対応 |
やはりTickTickは対象外。カスタム開発が必要です。
APIの調査
TickTick Open API:
- OAuth 2.0認証
- タスク・プロジェクトのCRUD操作が可能
- 開発者登録: https://developer.ticktick.com/manage
Reclaim.ai API:
- Bearer Token認証
- タスク作成・スケジューリングが可能
- APIキー取得: https://app.reclaim.ai/settings/developer
両方のAPIにアクセスできることが確認できたので、開発を進めることにしました。
技術選定
なぜCloudflare Workers?
無料で定期実行したいので、いくつかの選択肢を検討しました。
| サービス | 無料枠 | 適性 |
|---|---|---|
| Cloudflare Workers | 10万リクエスト/日 | 最適 |
| Vercel | 100GB帯域/月 | 可 |
| GitHub Actions | 2,000分/月 | 可 |
Cloudflare Workersは無料枠が十分で、Cron Triggersによる定期実行も可能。今回の用途にぴったりです。
アーキテクチャ
5分ごとにCronで実行し、新しいタスクをReclaim.aiに同期します。
実装
TickTick APIクライアント
TickTick APIはOAuth 2.0認証です。
const BASE_URL = "https://api.ticktick.com/open/v1";
export class TickTickClient {
private accessToken: string;
async getProjects(): Promise<Project[]> {
const response = await fetch(`${BASE_URL}/project`, {
headers: {
Authorization: `Bearer ${this.accessToken}`,
},
});
return response.json();
}
async getProjectTasks(projectId: string): Promise<Task[]> {
const response = await fetch(`${BASE_URL}/project/${projectId}/data`, {
headers: {
Authorization: `Bearer ${this.accessToken}`,
},
});
const data = await response.json();
return data.tasks || [];
}
}
Reclaim.ai APIクライアント
Reclaim.ai APIはBearer Token認証です。
const BASE_URL = "https://api.app.reclaim.ai/api";
export class ReclaimClient {
private accessToken: string;
async createTask(task: ReclaimTaskCreate): Promise<ReclaimTask> {
const response = await fetch(`${BASE_URL}/tasks`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(task),
});
return response.json();
}
async getTimeSchemes(): Promise<TimeScheme[]> {
const response = await fetch(`${BASE_URL}/timeschemes`, {
headers: {
Authorization: `Bearer ${this.accessToken}`,
},
});
return response.json();
}
}
ハマりポイント:タスクが勤務時間外にスケジュールされる
同期したタスクがなぜか勤務時間外に配置されていました。
調査したところ、Reclaim.aiには「Time Schemes」という概念があり、タスク作成時に指定が必要でした。
// Time Schemesを取得してWorking HoursのIDを確認
const schemes = await client.getTimeSchemes();
// → Working Hours: "3f6beef9-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// タスク作成時にtimeSchemeIdを指定
const task = {
title: "タスク名",
timeSchemeId: "3f6beef9-xxxx-xxxx-xxxx-xxxxxxxxxxxx", // Working Hours
};
これで勤務時間内(Focus Time)にスケジュールされるようになりました。
同期ロジック
優先度でフィルタリングして、重複を防ぐロジックです。
function shouldSync(task: TickTickTask): boolean {
// 完了済みはスキップ
if (task.status !== 0) return false;
// 優先度なし(0)はスキップ
if (task.priority < 1) return false;
return true;
}
async function sync() {
const ticktickTasks = await ticktick.getIncompleteTasks();
for (const task of ticktickTasks) {
if (!shouldSync(task)) continue;
if (alreadySynced(task.id)) continue;
await reclaim.createTask(convertTask(task));
markAsSynced(task.id);
}
}
デプロイ
wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "ticktick-reclaim-bridge",
"main": "src/worker.ts",
"compatibility_date": "2024-01-01",
"triggers": {
"crons": ["*/5 * * * *"] // 5分ごと
},
"kv_namespaces": [
{
"binding": "SYNC_STATE",
"id": "your-kv-namespace-id"
}
]
}
Secrets設定
npx wrangler secret put TICKTICK_CLIENT_ID
npx wrangler secret put TICKTICK_CLIENT_SECRET
npx wrangler secret put TICKTICK_ACCESS_TOKEN
npx wrangler secret put RECLAIM_ACCESS_TOKEN
npx wrangler secret put RECLAIM_TIME_SCHEME_ID
デプロイ
npm run deploy
これで5分ごとに自動同期が走ります。
完成
TickTickでタスクを追加すると、数分後にはReclaim.aiに同期され、カレンダーに自動配置されるようになりました。
動作イメージ
運用コスト
¥0
Cloudflare Workersの無料枠で十分です。
まとめ
- TickTickとReclaim.aiは公式連携がないが、APIを使えば繋げられる
- Cloudflare Workersなら無料で定期実行が可能
- Reclaim.aiのTime Schemesでスケジューリングポリシーを制御できる
ソースコードはGitHubで公開しています。
Discussion