1年半エンジニアが一人で作り切ったチャットシステムの開発記録

# はじめに

実務でチャットシステムの開発をインフラから開発まですべて一人で、約5か月かけて開発をしてきました。AWSを使ったインフラ構築からバックエンド、フロントエンドの実装まで、一気通貫で担当する機会を得て、多くの学びと課題に直面しました。実務経験約1年半のエンジニアとして、このような大きな責任を任されたプロジェクトでの経験は、私にとって大きな成長の機会となりました。今回は開発を終えて、技術選定から運用開始までの振り返りを行っていこうと思います。

# プロジェクト概要
## 1. システムの目的と背景
クライアントは広告業界で集客活動にLINEを活用していましたが、アカウント凍結のリスクが高く、代替となる独自のチャットシステムの開発が必要となりました。

#### 主要な要件

1. **LINEとの連携維持**
   - 既存のLINEユーザーとの接点は保持しつつ、メインのコミュニケーションを独自システムへ移行

2. **独自プラットフォームでのコミュニケーション基盤構築**
   - すべてのやり取りを自社管理のチャットシステムで完結
   - ユーザーの利便性を考慮し、ログインレス設計を採用

3. **必要な機能要件**
   - 基本的なチャット機能
   - 一斉配信機能
   - ユーザーブロック機能
   - 自動挨拶メッセージ機能
   - リアルタイム通知システム
   - LINE連携通知機能
   - アカウント凍結時のアカウント切り替え機能

このような要件を満たすシステムの構築により、LINEアカウント凍結のリスクを軽減しつつ、効果的な集客活動の継続を目指しました。

## 2. 技術スタック

システムの大規模な利用を想定し、スケーラビリティを重視した技術選定を行いました。特に、リアルタイムチャット機能の実現とシステムの安定性を両立させることを意識しています。

### 2.1 インフラ（AWS）
高可用性とスケーラビリティを確保するため、AWSをプラットフォームとして選択しました：

- **EC2**
  - アプリケーションサーバーのホスティング
  - オートスケーリングによる負荷対応
  
- **Application Load Balancer (ALB)**
  - 複数EC2インスタンス間での負荷分散
  
- **Amazon S3**
  - 画像の静的コンテンツ配信
  - サーバー負荷の軽減と高速なコンテンツ提供
  
- **RDS**
  - データベースのスケーラビリティ確保
  - 必要に応じた簡単なスペック変更
  
- **Route 53**
  - DNSの管理
  - 信頼性の高いドメイン管理

### 2.2 フロントエンド
シンプルながら効率的なUI/UXを実現するため、以下の技術を採用：

- **JavaScript**
  - WebSocketを使用したリアルタイム通信の実装
  - 非同期処理によるスムーズな操作感の実現
  
- **Bootstrap**
  - レスポンシブデザインの効率的な実装
  - モバイルファーストの設計

### 2.3 バックエンド
安定性とリアルタイム性を両立するため、複数の技術を組み合わせ：

- **Laravel**
  - セキュアな認証システムの実装
    - @csrfディレクティブによるクロスサイトリクエストフォージェリ対策
    - Blade テンプレートエンジンによる自動エスケープ機能
    - プリペアドステートメントとEloquent ORMによるSQLインジェクション対策
    - bcryptによる安全なハッシュ化<br><br>
  
- **Node.js & WebSocket**
  - リアルタイムチャット機能の実装
  - 双方向通信の効率的な処理

### 2.4 外部API連携
- **LINE Messaging API**

  - プッシュ通知機能の実装<br><br>
  
- **LINE Webhook**

  - LINEからのイベント受信
  - リアルタイムな応答処理

### 2.5 データベース
- **MySQL (AWS RDS)**
  - ユーザー情報管理
  - メッセージ履歴の保存
  - アカウント管理　など

# 3. 開発プロセスと実装での課題


### 1. ログインなしでのユーザー認証
設計段階で一番最初に直面した課題は、ユーザーにログインをさせずに認証を行う方法です。一般のチャットシステムでは、ユーザーにログインをさせてからチャット画面を開くことが多いですが、そこの処理を省いてユーザー管理を行う必要がありました。

#### 課題の詳細
- 従来のセッション管理ができない
- セキュリティの担保が必要
- ユーザーの一意性の確保

#### 解決策：LINE Webhookを活用したユーザー管理
LINEのWebhookを活用することで、以下の利点を得られました：
- LINEの認証基盤を利用できる
- ユーザーIDの一意性が保証される
- セキュリティ面でもLINEのプラットフォームに依存できる

#### 実装フロー
下記の図は、ユーザーが友達追加をしてから挨拶メッセージを送信するまでの一連の流れを示しています：

![napkin-selection (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935088/056b38f4-a14a-aeb6-c673-24b6251a4348.png)


#### 技術的なポイント
1. **Webhookの受信処理**
   - イベントタイプの判別
   - ユーザー情報の抽出<br><br>

2. **データベース設計**
   - LINE userIDを識別キーとして活用
   - 必要最小限の個人情報のみを保存<br><br>

3. **セキュリティ対策**
   - WebhookのSignature検証
 
### 2. アカウント切り替え機能の仕組み作り
ユーザーとのやり取りを独自のチャットシステムに移行しても、LINEを経由しているのでアカウントは凍結されるリスクは0ではありません。そのため、万が一アカウント凍結された時に、スムーズにアカウントの切り替えをユーザーに促す必要がありました。

#### 課題の詳細
- ユーザーとの継続的なコミュニケーションの確保
- 切り替え時のユーザー体験の最適化

#### 実装した解決策
1. **マルチアカウント管理システム**
   - メインアカウントと予備アカウントを一つの画面で管理
   - アカウント間の紐付け機能の実装<br><br>

2. **ユーザーへの通知システム**
   - 事前の予備アカウント告知
   - アカウント切り替えの誘導<br><br>

3. **アカウント切り替えの利便性**
      - 管理画面でボタンを押すだけで全ての切り替え処理を自動実行


### 3. 大規模アクセス時のパフォーマンス改善

チャットシステムの負荷テストとして、20セッションから同時に5万件のメッセージを送信する検証を行いました。その結果、2万件を超えたあたりでメモリ不足（OOM）が発生し、サーバーがダウンしてしまう問題が見つかりました。

この問題に対して、以下の3つの対策を実施しました。

#### 実装した解決策

1.  **負荷分散の導入**
      - Application Load Balancer (ALB)を導入し、アクセスを複数のサーバーに分散
      - サーバーの負荷が分散されることで、同じ量のメッセージ送信でもサーバーダウンが発生しなくなった<br><br>

2.  **データ取得の最適化**
      - 当初は全データを一括取得していたため、データ量が増えるとページの表示に10秒以上かかる問題が発生
      - 20件ずつの無限スクロール方式に変更することで、表示速度が大幅に改善
      - ブラウザのタイムアウトも解消<br><br>

3. **データベースアクセスの効率化**
      - N+1問題（データベースへの無駄なアクセス）を特定
      - サブクエリを活用し、少ない回数のクエリでデータを取得するように改善
      - データベースへの負荷を軽減<br><br>
  
4. **プールでのデータベース接続管理**
    - データベース接続の都度確立により、接続のオーバーヘッドが発生
    - 接続プールを導入し、接続の再利用を実現
    - データベースへの接続時間を短縮し、レスポンスを改善

# 4. まとめと今後の展望
### 得られた成果
1. リアルタイム通信基盤の確立
    - WebSocketを活用した双方向通信の実現
    - スムーズなチャット体験の提供<br><br>


2. パフォーマンスの最適化

    - データベースアクセスの効率化
    - クエリ実行回数の削減
    - 無限スクロールによるデータ取得の最適化<br><br>


3. インフラストラクチャの強化

    - AWSを活用したスケーラブルな環境構築
    - ALBによる効果的な負荷分散の実現
    - 安定したサービス提供基盤の確立<br><br>

3. 技術面での成長
    - クラスベースの堅牢なコード設計の習得
    - オブジェクト指向プログラミングの実践的理解<br><br>
4. エンジニアとしての成長
    - 技術的な課題への自主的な取り組み
    - ドキュメントやベストプラクティスを参照した問題解決力の向上
    - デバッグやトラブルシューティングのスキル向上<br><br>

5. 運用管理の効率化

    - パフォーマンスのボトルネック特定と解消
    - 問題発生時の迅速な対応が可能に

### 今後の課題
1. 機能面の改善
    - チャット履歴の管理機能の最適化
    - ユーザーニーズに応じた新機能の実装
    - socket通信の効率化<br><br>

2. コード品質の向上
    - オブジェクト指向プログラミングの深い理解と実践
    - 保守性を考慮したクリーンなコード設計
    - クラス設計の見直しと改善<br><br>

3. テスト環境の整備
    - PHPUnitを使用した単体テストの導入
    - 結合テストによる機能検証の自動化
    - テストカバレッジの向上<br><br>

4. パフォーマンスの最適化
    - データベースクエリの更なる効率化
    - N+1問題の完全な解消
    - WebSocketコネクションの最適な管理

# おわりに
このプロジェクトを通じて、技術面での多くの知見を得ることができ、それらを実践的なソリューションとして実装することができました。また、一人で開発を進める中で、自己解決力や技術的な判断力も大きく向上しました。まだまだ課題となるところは多くあるので、日々の勉強を怠らず、常に向上心を持ち一人前のエンジニアを目指したいと思います！最後までご覧いただきありがとうございました。