【個人開発】Googleカレンダーと連携！飼い主のための「ペット飼育管理アプリ」を作ってみた

## はじめに
2回目の個人開発は、ペットの飼育管理を効率化し、安心してお世話を続けられる、ペット飼育管理アプリを作成しました。

私自身、ペットの投薬やトリミング、健康チェックの記録を、カレンダーやメモアプリにバラバラに記録しており、「もっと一元管理できたら楽なのに…」と感じていた背景があり、作成に至りました。

この記事ではアプリの概要や構成、こだわりポイントなどをご紹介します。

[※参考_初回の個人開発はこちら](https://qiita.com/n-okutomi/items/974e4702b72fde1aece7)

:::note warn
このアプリは、現在はローカル環境でのみ動作する形で作成されています。
:::

![pet_app.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762672/1650eef6-23ea-46ee-b443-747594903222.gif)


## 1.  作ったアプリの概要

### アプリの目的
- ペットの健康や日々のお世話に必要な情報を一元管理し、管理を楽にする飼育管理アプリ。
- このアプリを使用することで、ユーザーはペットの健康管理が楽になる。
また記録を見返すことで、日々の努力が形として残り、ペットの健康をしっかりと守っているという達成感と安心感を得られる。


### ターゲット
- 愛犬を飼っているすべての飼い主さん
- 特に、日々のケア記録を「見える化」したいと感じている方


### 背景
- ペットの世話は定期的なケア（投薬日・健康チェック・トリミング・診察）の記録が必要だが、管理が煩雑になりがち。
- このアプリによって、飼い主が簡単にペットのケア情報を管理しやすくなる。

## 2.  ユースケース整理

### 主な利用シーン
- 健康記録の振り返り（例：体重・メモ）
- トリミングや病院受診のスケジュール確認
- 月1のフィラリア薬などの投薬日

### 利用場所とタイミング
- 自宅のPCから、思い出した時に気軽に確認・入力

### 具体的なアクション
- ペットの基本情報を登録
- ケアスケジュールをGoogleカレンダーと同期して一覧表示
- 予定をカレンダーで見返す


## 3.  機能一覧
以下はアプリが提供する主な機能です。

| #  | 機能名                | 概要                                        |
|----|-----------------------|---------------------------------------------|
| 1  | ログイン機能（Google認証）          | ペット飼育管理アプリにGoogleアカウントでログインする。            |
| 2  | ログアウト機能        | ペット飼育管理アプリからログアウトする。        |
| 3  | アカウント登録機能    | ログインに必要なユーザー登録を行う。        |
| 4  | ペット基本情報の登録/編集/削除    | 名前、体重、性別、誕生日、お迎えした日、メモを管理 |
| 5  | Googleカレンダー同期機能  | Googleカレンダーの予定を取得して表示     |

:::note warn
下記の機能は今回スケジュールの都合で未実装（今後拡張予定です）
- ケア記録機能：
定期的なケア（投薬日・健康状態・トリミング・診察）を入力し記録。
カレンダーで特定の日付を選択してボタンを押すと入力ページに移動し、ケア内容を登録できる。
登録後、カレンダーにアイコンやスタンプが反映される。

- ケア内容詳細表示・更新・削除機能：
カレンダーの日付をクリックすると、詳細情報（ケア内容、健康状態、薬情報など）が表示される。
:::

## 4.構成
- 技術スタックは以下の通りです。

| 分類               | 技術 / ツール名             |
|--------------------|------------------------------|
| プログラミング言語 | TypeScript                   |
| フロントエンド     | React.js（Vite.js）          |
|                    | TailwindCSS                  |
| バックエンド       | Express           |
| データベース       | PostgreSQL                   |
| 認証               | Google アカウント認証 |
| 外部 API           | Google Calendar API（OAuth 2.0）          |
| 画像アップロード   | Multer                       |

## 5.デモ
ローカル環境で動作する本アプリのデモとして、下記の通り紹介します。
- **ログイン**：
![ログイン_pet.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762672/2d9b38c0-8dfd-47d9-955d-96effdc7e2f3.gif)

- **ペット基本情報の登録・編集・削除**：
![info.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762672/3ce5f263-2c5b-43fa-8504-0bd8765b3d08.gif)

- **Googleカレンダー同期機能**：
![google_calen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762672/a6f40305-ff20-498d-9f5e-8acfa2caf156.gif)



---

## 6.こだわったポイント
- **UIの可愛さと温かみ**：
ペット好きの方に親しみやすいように、背景色やアイコンにこだわった。
TailwindCSSで柔らかい配色を使い、絵文字を使うことで見た目も分かりやすく表現した。

- **Googleカレンダー連携の実装**：
APIで取得した予定をカレンダーに反映する処理では、終日イベントと時刻付きイベントを分けて表示。
予定が多すぎる日は「＋X件」とまとめ表示。

## 7.躓いたポイント
- **Googleカレンダーの「終日イベント」が1日ズレること**： 
`start.date`がUTC基準で返されるため、タイムゾーン補正が必要だった。

- **カレンダーのデザインがTailwindCSSで反映されないこと**：
`react-calendar`に対して`TailwindCSS`で見た目を整えようとしたが、ライブラリ側のCSSが強く効いていてうまく反映されなかった。
結果的に、`react-calendar`を直接カスタマイズすることでデザインが意図通りに反映された。

- **基本設計の詰めが甘かった部分が実装で影響したこと**：
ペットの登録が完了したあとの表示画面や、モーダル内に画像が未登録だった場合に何を表示するか（デフォルト画像の扱い）など、当初の要件定義や設計で具体的に決めきれていなかった部分が、実装フェーズに入ってから浮き彫りになった。
その場しのぎで対応してしまうとコードに無理が出てくるため、結果的に仕様を見直したり、デザインを調整したりといった後戻りの作業が何度か発生した。
この経験を通じて、「仕様が曖昧なまま実装に入るリスク」や「UI/UXを事前に具体化しておくことの重要性」を痛感。

## おわりに
今回のペット管理アプリの開発は、前回のレシピ管理アプリに続く2回目の個人開発でしたが、「Google認証」「Googleカレンダーとの連携」など、前回よりも実装範囲や機能の複雑さが広がり、新たな壁にぶつかる場面も多くありました。

特に設計の甘さが後から問題になることも多く、「登録後の画面遷移はどうする？」「画像がないときの表示は？」といった細かな部分が実装フェーズで初めて明らかになるケースが目立ちました。
そのたびに仕様を再検討したり、表示方法を見直したりと、後戻りの作業が発生し、「設計の具体性がアプリ全体の完成度に直結する」ということを身をもって学びました。

また、思うようにスタイルが反映されず悩んだ結果、ライブラリ本体に手を加えることで解決するなど、CSSやライブラリの挙動についてもより深く理解できるきっかけになりました。

この開発で得られたのは、技術的なスキルだけでなく、
「事前にどこまで想像し、詰めておけるかが実装効率に大きく影響する」という気づきや、
「不完全な設計でも、手を動かしながら軌道修正していく力も大切である」というマインドでした。

「作ること」に対して自信が少しついた一方で、まだまだ足りないこと、見えていないことも多いと実感しています。
この経験を次に活かして、もっと使いやすく、もっと人の役に立つアプリを作れるように、また一歩ずつ前に進んでいきたいと思います。