当日のGitHubContributesの変更有無を取得し、コミットがない場合通知するWebサービス作ってみました！！



## 概要

当サービスは、GitHubに当日のリポジトリへのプッシュ(又はcontributionsの記録)がなかった場合、任意の時間にユーザが登録したメールアドレスへ通知を送るシステムです！

これはユーザの毎日の継続的な学習をサポートし、プログラミング能力の向上と学習習慣を養うサービスです！

サービス名: Github Contribute System (GCS)
(以下GCS)

GCSでは大きく分けて2つのシステムのが存在します。

<b>1:PythonでのGoogle Cloud プラットフォーム上でのバッチ処理
<b>2:React(JavaScript)+Spring(Java)のWebページ



上記のWebページは利用者にはGitHubのアカウント名と通知に必要な情報
- メールアドレス
- github名
- 通知時間

を登録できるサイトを用意しました↓
<B>URL      : https://githubcontributesystem.netlify.app/

詳細はサービス構成で説明します！

このシステムが狙っているのは以下の点です：
- Gitへの毎日のプッシュが技術力向上につながる
- コードに毎日触れることで継続的な学習意欲を養う
- WebサイトでGitHubへの継続プッシュ数がランキング表示されることで、他のユーザーと競争心を煽り、モチベーションを保つ
:::note warn
(ランキング機能は作成途中となっております!ご了承ください![2025年3月23日現在])
:::

と、長々と書きましたがほぼ自分用のサービスです:rolling_eyes:


## 作成のきっかけ

バックエンドエンジニアとしての経験がメインで、業務ではフロントエンド技術に触れる機会が少なかったため、学習も兼ねて人気のあるReactの勉強と、Springフレームワークの復習を始めました。

また、IT業界に入り駆け出しのエンジニアとして、学習のアウトプットも兼ねて何かサービスを作りたいと考えたのがきっかけです。何より、自分の手でサービスを作り上げることに挑戦したいという思いが大きかったです。

調べたところ、GitHubのContributionsをスクレイピングする技術はあるものの、「当日のGitHubへのpushがない場合に通知してくれるサービス」は見当たらなかったため、今回開発しました！

## 画面構成
ホーム画面
![welcome画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/9f27d569-f952-4095-bbc2-0d7c8574fe3b.png)


ホーム画面での新規登録/ログインボタン押下時画面
(Firebase AuthによるGoogleアカウント登録orログイン）
![welcome画面からのGoogleIDログイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/305d1f01-2cfd-4123-81f3-fc1ee94a46ac.png)

今回Googleアカウントで新規登録を行い、
新規登録もログインも同じボタンで行う事ができます

初回新規登録画面
![新規登録画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/04a28972-811d-4be0-8c04-fa5f549a1e00.png)

既にサイトにてユーザ情報登録済みの場合、ダッシュボード画面へ遷移します
![ダッシュボード画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/ef557ed4-d6b4-4dc9-8551-4bdae507545d.png)


サイトについての画面
![サイトについて画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/04236b15-49a3-4970-8f4f-0c787c1c7de9.png)

ユーザー情報編集_ユーザ情報編集画面
![ユーザ情報編集画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/9432c708-d182-4410-b881-987cc803c324.png)

ユーザ情報編集画面_ユーザ情報削除画面
![ユーザ情報削除画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/5b2d7f55-34f5-4583-be1b-233a7b7a0e0f.png)

ナビバーのサインアウトを押す事でログアウト処理を行う事ができます

またスマホでの使用を想定して全画面レスポンシブデザイン対応しております
![全画面レスポンシブデザイン対応.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/ffd5f50d-dd54-4b52-8cbf-3a5bfe43bf24.png)

# 構成
概要でも少し説明させていただきましたがこのシステムはバッチ処理とWebサイトの構成で成り立っています

  

### -バッチ処理-

<b>使用言語:</b>pyhon
<b>ホスティングサービス:</b>Google Cloud Platform

<b>説明:</b>15分単位でGitHubAPIとDBに接続し、
任意の時間にpushが無ければユーザーにメールを送る24時間稼働させる定期的ジョブ

### -フロント(Webサイト)-
<b>使用言語:</b>JavaScript
<b>フレームワーク:</b>React
<b>ホスティングサービス:</b>Netlify

<b>説明:</b>以下の情報の表示
- ユーザ情報登録編集 
- 今日のコミットの有無
- 1週間のコミット率
- 最終更新リポジトリの使用言語率

### -バックエンド(Webサイト)-

<b>使用言語:</b>Java
<b>フレームワーク:</b>Spring
<b>ホスティングサービス:</b>fly.io

<b>説明:</b>
- 新規登録ロジック
- GitHubAPIを叩き、ユーザ情報取得
- その他ビジネスロジック処理 
- DBへのユーザ情報CRUD操作


少し長くなってしまいますが一つづ説明させていただきます！

# -バッチ処理-
これはGoogle Cloud プラットフォーム上でpythonを15分毎に動かしメールを送るを送るか否かの判断をしています
<b>-使用技術-
<dt>言語: Python</dt>
<dt>データベース:MongoDB Atlas(アトラス)</dt>
<dt>メールサービス:Gmail SMTPサーバー</dt>
  <dt>クラウドサービス(GCP):</dt>
  <dd>Cloud Scheduler</dd>
  <dd>Cloud Run Functions</dd>
  <dd>Cloud Storage</dd>

サービス概要図がありますので以下をご覧ください
![python構成_修正済み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641722/cebe84fa-bdc5-4011-832c-e4146f75eb80.png)

簡単にサービス概要を説明しますと
<b>Cloud Run FunctionsをGoogle Cloud Schedulerで定期実行し、Cloud StorageのZIP(.py)を動かす</b>
という流れになっております

1. Cloud Schedulerを使用し、15分毎Cloud Storageにあるpythonファイルを実行
1. Pythonファイル内ではまずMongoDBAtlasに接続し、登録されているユーザ情報を全件取得
1. GitHubAPIを叩きで取得したユーザ情報のGithubアカウントを元に今日のContributesの記録があるか確認する
1. 記録がない場合Gmail SMTPサービスを利用しメールを送信する



# -フロント(Webサイト)-
<b>-使用技術-</B>
###### フレームワーク
React.js

###### 認証
Firebase Authentication

### -説明-</b>
#### 認証システム
#### Firebase Authentication
- Googleアカウントによるシングルサインオン（SSO）を実装
- ユーザー管理をFirebaseに委譲することで:
  - セキュアな認証基盤の活用
  - パスワード管理リスクの軽減
  - ユーザーの利便性向上



コンテキストでGoogle認証情報を保持し、バックエンドへのAPIに問い合わせる際、
JWTを送信する事で誰に送られたか判断しております(トークンベースの認証（JWT）)
バックエンドでFirebase Admin SDKを用いて検証を行っております
#### Context APIによる認証状態管理
- `AuthContext`: ユーザー認証状態のグローバル管理(JWTトークンによる認証状態の維持)
- `GitHubDataContext`: GitHub関連データの一元管理
```javascript
const getAuthHeaders = async () => {
    const token = await user.getIdToken();
    return {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
    };
};
```

基本的に認証済みのユーザーのみアクセス出来るようにルーティング管理を行っております
認証情報を持っていないユーザはホーム画面(Welcome画面)と新規登録画面のみアクセス可能です


またログイン後のホーム画面(dashboard画面)はgithubAPIを叩くAPIに接続しに行っている為、5分間隔でのデータ更新制限を行っています
この為初回接続時にダッシュボード画面のデータをSessionStorageにキャッシュとして保持し、5分以内に再度アクセスした場合そのデータを使用し画面構築しています

SessionStorageのデータはログアウト時orブラウザを消したときに削除するようなっています
### データ取得の最適化
- GitHubデータの取得を5分間隔に制限
- SessionStorageによるキャッシュ管理
```javascript
const [lastFetchTime, setLastFetchTime] = useState(() => {
    const savedTime = sessionStorage.getItem('lastFetchTime');
    return savedTime ? new Date(savedTime) : null;
});
```



# -バックエンド(Webサイト)-

### 使用技術スタック
- **フレームワーク**: Spring Boot 
- **認証基盤**: Firebase Authentication
- **データベース**: MongoDB Atlas
- **セキュリティ**: Spring Security


### バックエンドアーキテクチャの特徴

### 1. 認証システム
- Firebase Authenticationを採用し、堅牢な認証基盤を実現
- JWTトークンベースの認証により、ステートレスなセッション管理を実装

説明:認証回りはFirebaseに丸投げしました
ユーザからJWT取得後SDKで検証後UIDを取り出し、
DBにあるUIDとそれに紐づいているユーザ情報から新規登録かログイン処理判断しており、ログイン処理を同じ方法で行っています


### 2. スケーラブルなデータベース設計
- MongoDB Atlasを採用し、クラウドネイティブな環境を実現
- ドキュメント指向データベースによる柔軟なデータモデリング
- 高可用性と自動スケーリングをサポート

説明:今まで使用してきたMySQLやSQL Server,oracle SQLとは違う
RDBではなくNoSQLを採用しました
選定理由として単純に今まで使ってこなかった技術を使用したいというのもありますが
GCP上でフルマネージド運用可能な点が魅力的で採用しました
(今回のサービスではあまり想定出来ませんが)簡単にスケールアウトできる点も魅力の一つでした

### 3. クリーンアーキテクチャの採用
- レイヤードアーキテクチャによる関心の分離
  - Controller層: APIエンドポイントの提供
  - Service層: ビジネスロジックの実装
  - Repository層: データアクセス処理
- 依存性注入（DI）による疎結合な設計

説明:コントローラー層ではResuFUl APIのエンドポイントの提供を心掛けました
Firebase認証を採用している為、基本的にフロントからの応答が来た場合のエラーハンドリングや検証処理を必ず行う為、コードの保守性、再利用性にこだわりました
また効率よくフロントへデータを返すためにGithubAPIを取得の際はSpring MVC機能を使い非同期処理を行っています
(詳しくは後述するレポジトリを参照ください)

### 4. CORS対策
- 環境変数による柔軟なCORS設定
- セキュアなクロスオリジンリクエストの制御



## 4.コストについて
今回の副題として兎に角、安く済ます事を考えていました
しかし登録フォームを24/365起動する必要があり、それを考慮する必要がありました

<b>-1カ月当たりのコスト-</b>
Google プラットフォーム上で合わせて1~3円ほど(ほぼCloud Storageの料金)
Netlifyは無料枠での使用
fly.ioはRegion:Ashburn, Virginia (US)
1CPU,512MBのアーキテクチャを採用しており
1か月の起動コストは約312~400円程になります
MongoDB Atlasも無料枠での使用です

fly.ioは以前無料枠があったらしいですが、今はクレカを人質に取られ、完全に従量課金制になったみたいです
故に総コストは起動コスト+アクセスにより変動するので実際はもう少し費用が膨れる見込みです

費用が1コイン以上になった場合、環境の構築を見直す予定です
## 5.感想まとめ

製作期間:2024年6月20日～2025年3月22日
まさかの制作に9カ月かかってしまいました...!

こんなに時間がかかってしまったのは完全に言い訳ですが、あまりにも知識が無さ過ぎた事です
普段バックエンド(C言語)の知識だけではあまりにもReactフレームワーク知識、認証回りの技術やクラウド技術がモダン技術すぎて平日仕事終わり+土日だけだと学習に時間がかかりすぎました
途中バックエンドをGoに移行しようとしてみたり、DDD設計を取り入れようとしたりしたのも時間を食う原因でしたね....

しかし業務で使用する事が少ない、フロントエンドやインフラの技術を学べた事、自分で初のサービスを作成できた事の達成感が何よりも楽しかったです:blush:





まだまだ作りたいサービス&学習したい言語が沢山ありますのでこのサービスを使って日々の学習を継続させていきたい所存です！
次はFlutterとGo言語を使用したサービスを作成したいと思っていますので、また機会がありましたら覗いてみてください！！

最後にGitHubにソースをまとめたものがありますのでよろしければ見てみてください～！

バッチ処理(python)
https://github.com/YuuuDays/GCS_python

Webフロントエンド
https://github.com/YuuuDays/GCS_frontend

Webバックエンド
https://github.com/YuuuDays/GCS_backend