🤖

【個人開発】AIとペアプロしたら、一晩で日程調整ツールが「実用レベル」に進化した話

に公開

昨日の記事「【個人開発】GoogleのAI「Antigravity」とペアプロしたら、日程調整ツールが爆速で完成した話」では、AIエージェントとペアプログラミングをして、日程調整まとめアプリ「ScheduLinx(スケジュリンクス)」のプロトタイプを爆速で開発しました。

今回はその続編です。
「プロトタイプ完成」からわずか一晩で、**「Googleカレンダーと連携して、予定の仮押さえから確定までを完結できるツール」**へと進化させました。

この記事では、NextAuth.jsを使ったGoogle Calendar API連携の技術的なポイントや、個人開発アプリを「使われるプロダクト」にするためのUX/SEO改善について解説します。


1. 作ったもの:ScheduLinx (v1.0)

ScheduLinxは、複数の日程調整ツール(伝助、調整さんなど)のURLを登録するだけで、候補日を自動で取り込み、自分のGoogleカレンダーと重ねて表示できるアプリです。

URL: https://schedule-manager-beta.vercel.app
GitHub: https://github.com/NaokiKenmochi/schedule-manager

ScheduLinx Dashboard

今回実装した新機能

  1. Googleカレンダー双方向同期:
    • 候補日を取り込むと、Googleカレンダーに「[仮]」として予定を作成。
    • アプリで「確定」すると、Googleカレンダーの予定を正式登録し、他の候補日を自動削除。
  2. UXの磨き込み:
    • OGP画像の作成、Favicon設定、使い方ガイドの実装。

2. 技術ハイライト:Googleカレンダー連携の裏側

今回の最大の山場は、**「アプリでの操作をGoogleカレンダーにリアルタイムで反映させる」**ことでした。

認証スコープの昇格 (NextAuth.js)

これまでは読み取り専用(calendar.readonly)でしたが、予定の作成・削除を行うため、書き込み権限(calendar)を追加しました。

src/lib/auth.ts
GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    authorization: {
        params: {
            // calendar.readonly から calendar へ変更
            scope: "openid email profile https://www.googleapis.com/auth/calendar",
        },
    },
}),

「仮押さえ」と「確定」のロジック

日程調整で一番面倒なのは、**「候補日をカレンダーに仮登録する作業」と、「決まった後に不要な仮予定を消す作業」**です。これを全自動化しました。

Step 1: 候補日の取り込み(仮押さえ)

調整ツールのURLを解析して候補日を抽出したら、即座にGoogleカレンダーへPOSTします。この時、タイトルに [仮] を付けて区別します。

Step 2: 確定アクション(お掃除機能)

ユーザーが候補日の一つを「確定」した時の処理がこちらです。

src/components/Dashboard.tsx
const handleConfirmEvent = async (event: CalendarEvent) => {
    if (!window.confirm(`${event.title}」を確定しますか?`)) return;

    // Googleカレンダー連携済みの場合
    if (session?.accessToken && event.googleEventId) {
        try {
            // 1. 確定した予定を更新([仮] を削除)
            const newTitle = event.title.replace(/^\[\]\s*/, '');
            await fetch('/api/calendar/events', {
                method: 'PATCH',
                body: JSON.stringify({
                    eventId: event.googleEventId,
                    title: newTitle,
                }),
            });

            // 2. 同じグループの「選ばれなかった候補日」を全削除
            const otherEvents = events.filter(e => e.groupId === event.groupId && e.id !== event.id);
            await Promise.all(otherEvents.map(async (other) => {
                if (other.googleEventId) {
                    await fetch(`/api/calendar/events?eventId=${other.googleEventId}`, {
                        method: 'DELETE',
                    });
                }
            }));
        } catch (error) {
            console.error('Failed to sync confirmation', error);
        }
    }
    // ...ローカルの状態更新
};

この「選ばれなかった候補日を消す」処理があるだけで、カレンダーがスッキリし、ダブルブッキングのリスクが激減します。


3. プロダクトとしての「磨き込み」

機能ができたら、次は「使いたくなる見た目」と「見つけてもらう工夫」です。ここでもAIエージェントが大活躍しました。

OGP画像の作成

SNSでシェアされた時の顔となるOGP画像。デザインセンスに自信がなくても、AIにイメージを伝えるだけで生成してくれます。

プロンプト:

A modern, sleek, and professional Open Graph (OGP) image for a schedule management application named 'ScheduLinx'. The design should be clean and minimalist...

生成された画像:
ScheduLinx OGP

これを layout.tsxmetadata に設定するだけで、X (Twitter) での表示が劇的に良くなりました。

使い方ガイド (Help Modal)

機能が増えてきたので、初見ユーザー向けのガイドも実装しました。
「ヘッダーの?ボタンを押すとモーダルが出る」という仕様も、AIに依頼してサクッと実装。

ScheduLinx Help Modal

SEO最適化

Next.js の Metadata API をフル活用して、JSON-LD(構造化データ)も埋め込みました。これで「日程調整ツール」として検索エンジンに正しく認識されるはずです。

src/app/layout.tsx
const jsonLd = {
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  "name": "ScheduLinx",
  "applicationCategory": "ProductivityApplication",
  // ...
};

4. まとめ

AIエージェントとのペアプログラミングにより、**「アイデア出し」→「プロトタイプ」→「実用的なプロダクト」**への進化を、驚くべきスピードで実現できました。

特に、Googleカレンダー連携のような少し複雑なAPI処理も、
「こういうロジックにしたい」
と伝えるだけで、エラーハンドリングまで含めたコードを提案してくれるのは圧巻です。

ScheduLinxは現在ベータ版として公開中です。ぜひ使ってみてください!

フィードバックやPull Requestもお待ちしています!

Discussion