🔄

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:

Reclaim.ai API:

両方の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で公開しています。

https://github.com/kyo-ogawa/ticktick-reclaim-bridge

参考リンク

Discussion