# 알림음 시스템 구현 계획

> **작성일**: 2025-01-07
> **목적**: FCM 푸시 알림 타입별 커스텀 알림음 구현
> **영향 범위**: app (Capacitor), api (Laravel), mng (Laravel)
> **상태**: ✅ 핵심 기능 완료 (4.3 알림 설정 테이블은 후순위)

---

## 📍 현재 진행 상태

| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | Phase 5 - 테스트 및 검증 완료 ✅ |
| **다음 작업** | 완료 (4.3 알림 설정 테이블은 후순위) |
| **진행률** | 10/11 (91%) - 핵심 기능 완료 |
| **마지막 업데이트** | 2025-01-07 |

---

## 1. 개요

### 1.1 배경

현재 SAM 앱은 FCM 푸시 알림 시 2개 채널(`push_default`, `push_urgent`)만 지원합니다.
비즈니스 요구사항에 따라 알림 타입별로 다른 알림음이 필요합니다:

- 결제 알림 → 결제 전용 알림음
- 수주 알림 → 수주 전용 알림음
- 발주 알림 → 발주 전용 알림음
- 계약 알림 → 계약 전용 알림음
- 일반 알림 → 기본 알림음
- 신규업체 등록 → 긴급 알림음

### 1.2 목표 구조

| 타입 | 채널 ID | 알림음 파일 | 설명 |
|------|---------|------------|------|
| 결제 | `push_payment` | `push_payment.wav` | 결제 관련 알림 |
| 수주 | `push_sales_order` | `push_sales_order.wav` | 수주 관련 알림 |
| 발주 | `push_purchase_order` | `push_purchase_order.wav` | 발주 관련 알림 |
| 계약 | `push_contract` | `push_contract.wav` | 계약 관련 알림 |
| 일반 | `push_default` | `push_default.wav` | 일반 알림 (기존) |
| 신규업체 등록 | `push_urgent` | `push_urgent.wav` | 신규업체 등록 (기존) |

### 1.3 현재 상태 분석

#### App (Capacitor Android)
- **파일**: `app/android/app/src/main/java/com/codebridgex/webapp/MainActivity.java`
- **현재**: 2개 채널 (`push_default`, `push_urgent`)
- **알림음**: `res/raw/push_default.wav`, `res/raw/push_urgent.wav`

#### API (Laravel)
- **파일**: `api/app/Services/Fcm/FcmSender.php`
- **현재**: `channel_id` 파라미터 지원, 사운드는 `'default'` 하드코딩
- **문제**: 커스텀 사운드 미지원

#### MNG (Laravel)
- **파일**: `mng/app/Http/Controllers/FcmController.php`
- **현재**: `sound_key` 파라미터 존재하나 실제 활용 안됨

### 1.4 시스템 흐름

```
┌─────────────────────────────────────────────────────────────────────────┐
│                         FCM 알림음 시스템 흐름                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  MNG (발송 UI)                                                          │
│  ┌─────────────────┐                                                    │
│  │ 타입 선택       │  ← 결제/수주/발주/계약/일반/신규업체                 │
│  │ channel_id 설정 │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                             │
│           ▼                                                             │
│  API (FCM 발송)                                                         │
│  ┌─────────────────┐                                                    │
│  │ FcmSender       │                                                    │
│  │ channel_id →    │                                                    │
│  │ android.channel │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                             │
│           ▼                                                             │
│  Firebase Cloud Messaging                                               │
│  ┌─────────────────┐                                                    │
│  │ FCM Server      │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                             │
│           ▼                                                             │
│  App (Capacitor)                                                        │
│  ┌─────────────────┐                                                    │
│  │ NotificationChannel │  ← channel_id로 매칭                           │
│  │ 채널별 사운드 재생  │  ← push_payment.wav 등                         │
│  └─────────────────┘                                                    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 2. 대상 범위

### 2.1 Phase 1: App - 채널 및 알림음 추가

| # | 작업 항목 | 상태 | 파일 |
|---|----------|:----:|------|
| 1.1 | 알림음 파일 준비 (4개) | ✅ | `res/raw/*.wav` |
| 1.2 | MainActivity.java 채널 추가 (4개) | ✅ | `MainActivity.java` |

### 2.2 Phase 2: API - FcmSender 수정

| # | 작업 항목 | 상태 | 파일 |
|---|----------|:----:|------|
| 2.1 | buildMessage() 사운드 동적 처리 | ✅ | `FcmSender.php` |
| 2.2 | 채널-사운드 매핑 (FcmSender 내부 통합) | ✅ | `FcmSender.php` |

### 2.3 Phase 3: MNG - 발송 UI 수정

| # | 작업 항목 | 상태 | 파일 |
|---|----------|:----:|------|
| 3.1 | 타입 선택 드롭다운 추가 | ✅ | `fcm/send.blade.php` |
| 3.2 | 타입-채널 매핑 로직 | ✅ | `FcmController.php` |

### 2.4 Phase 4: 이벤트 기반 자동 푸시

| # | 작업 항목 | 상태 | 파일 |
|---|----------|:----:|------|
| 4.1 | PushNotificationService 생성 | ✅ | `api/app/Services/PushNotificationService.php` |
| 4.2 | 신규 거래처 등록 시 푸시 | ✅ | `api/app/Services/ClientService.php` |
| 4.3 | 알림 설정 테이블 (추후) | ⏭️ | 후순위 |

### 2.5 Phase 5: 테스트 및 검증

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 5.1 | 각 타입별 푸시 발송 테스트 | ✅ | 6개 타입 |
| 5.2 | 알림음 재생 확인 | ✅ | Android 실기기 |

---

## 3. 상세 작업 내용

### 3.1 Phase 1: App - 채널 및 알림음 추가

#### 1.1 알림음 파일 준비

**위치**: `app/android/app/src/main/res/raw/`

| 파일명 | 상태 | 비고 |
|--------|------|------|
| `push_default.wav` | ✅ | 일반 알림 |
| `push_urgent.wav` | ✅ | 신규업체 등록 |
| `push_payment.wav` | ✅ | 결제 알림 |
| `push_sales_order.wav` | ✅ | 수주 알림 |
| `push_purchase_order.wav` | ✅ | 발주 알림 |
| `push_contract.wav` | ✅ | 계약 알림 |

> **완료**: 6개 알림음 파일 모두 준비됨 (2025-01-07)

#### 1.2 MainActivity.java 수정

**현재 코드** (2개 채널):
```java
public static final String CHANNEL_DEFAULT = "push_default";
public static final String CHANNEL_URGENT  = "push_urgent";
```

**목표 코드** (6개 채널):
```java
public static final String CHANNEL_DEFAULT        = "push_default";
public static final String CHANNEL_URGENT         = "push_urgent";
public static final String CHANNEL_PAYMENT        = "push_payment";
public static final String CHANNEL_SALES_ORDER    = "push_sales_order";
public static final String CHANNEL_PURCHASE_ORDER = "push_purchase_order";
public static final String CHANNEL_CONTRACT       = "push_contract";
```

### 3.2 Phase 2: API - FcmSender 수정

#### 2.1 buildMessage() 수정

**현재** (`FcmSender.php:112`):
```php
'android' => [
    'notification' => [
        'channel_id' => $channelId,
        'sound' => 'default',  // 하드코딩
    ],
],
```

**목표**:
```php
'android' => [
    'notification' => [
        'channel_id' => $channelId,
        'sound' => $this->getSoundForChannel($channelId),
    ],
],
```

#### 2.2 채널-사운드 매핑

```php
// config/fcm.php 또는 FcmSender 내부
private function getSoundForChannel(string $channelId): string
{
    return match($channelId) {
        'push_payment'        => 'push_payment',
        'push_sales_order'    => 'push_sales_order',
        'push_purchase_order' => 'push_purchase_order',
        'push_contract'       => 'push_contract',
        'push_urgent'         => 'push_urgent',
        default               => 'push_default',
    };
}
```

### 3.3 Phase 3: MNG - 발송 UI 수정

#### 3.1 타입 선택 UI

```html
<select name="notification_type" id="notification_type">
    <option value="general">일반</option>
    <option value="payment">결제</option>
    <option value="sales_order">수주</option>
    <option value="purchase_order">발주</option>
    <option value="contract">계약</option>
    <option value="new_company">신규업체 등록</option>
</select>
```

#### 3.2 타입 → 채널 매핑

```php
$channelMap = [
    'general'        => 'push_default',
    'payment'        => 'push_payment',
    'sales_order'    => 'push_sales_order',
    'purchase_order' => 'push_purchase_order',
    'contract'       => 'push_contract',
    'new_company'    => 'push_urgent',
];
```

### 3.4 Phase 4: 이벤트 기반 자동 푸시

#### 4.1 PushNotificationService 생성

**파일**: `api/app/Services/PushNotificationService.php`

```php
<?php

namespace App\Services;

use App\Models\PushDeviceToken;
use App\Services\Fcm\FcmSender;

class PushNotificationService extends Service
{
    public function __construct(
        private readonly FcmSender $fcmSender
    ) {}

    /**
     * 비즈니스 이벤트별 푸시 발송
     */
    public function sendByEvent(
        string $event,
        int $tenantId,
        string $title,
        string $body,
        array $data = []
    ): void {
        $channelId = $this->getChannelForEvent($event);

        // 해당 테넌트의 활성 토큰 조회
        $tokens = PushDeviceToken::where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->pluck('token')
            ->toArray();

        if (empty($tokens)) {
            return;
        }

        $this->fcmSender->sendToMany(
            $tokens,
            $title,
            $body,
            $channelId,
            $data
        );
    }

    /**
     * 이벤트 → 채널 매핑
     */
    private function getChannelForEvent(string $event): string
    {
        return match($event) {
            'payment'        => 'push_payment',
            'sales_order'    => 'push_sales_order',
            'purchase_order' => 'push_purchase_order',
            'contract'       => 'push_contract',
            'new_client'     => 'push_urgent',
            default          => 'push_default',
        };
    }
}
```

#### 4.2 ClientService에서 푸시 호출

**파일**: `api/app/Services/ClientService.php` (store 메서드)

```php
/** 생성 */
public function store(array $data)
{
    $tenantId = $this->tenantId();

    $data['client_code'] = $this->generateClientCode($tenantId);
    $data['tenant_id'] = $tenantId;
    $data['is_active'] = $data['is_active'] ?? true;

    $client = Client::create($data);

    // 신규 거래처 등록 푸시 발송
    app(PushNotificationService::class)
        ->setTenantId($tenantId)
        ->sendByEvent(
            'new_client',
            $tenantId,
            '신규 거래처 등록',
            "새로운 거래처 '{$client->name}'이(가) 등록되었습니다.",
            ['client_id' => $client->id]
        );

    return $client;
}
```

#### 4.3 이벤트 타입 정의

| 이벤트 | 채널 | 발생 시점 |
|--------|------|----------|
| `new_client` | `push_urgent` | 거래처 신규 등록 |
| `payment` | `push_payment` | 결제 완료/요청 |
| `sales_order` | `push_sales_order` | 수주 등록/변경 |
| `purchase_order` | `push_purchase_order` | 발주 등록/변경 |
| `contract` | `push_contract` | 계약 등록/만료 |

---

## 4. 변경 승인 정책

| 분류 | 예시 | 승인 |
|------|------|------|
| ✅ 즉시 가능 | 알림음 파일 추가, 채널 추가 | 불필요 |
| ⚠️ 컨펌 필요 | FcmSender 로직 변경, UI 수정 | **필수** |
| 🔴 금지 | FCM 구조 변경, 기존 채널 삭제 | 별도 협의 |

---

## 5. 컨펌 대기 목록

| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|------|----------|----------|------|
| 1 | 알림음 파일 | 6개 wav 파일 준비 | app | ✅ 완료 |

---

## 6. 변경 이력

| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|------|------|----------|------|------|
| 2025-01-07 | - | 계획 문서 초안 작성 | - | - |
| 2025-01-07 | 1.2 | MainActivity.java 6개 채널 추가 | `MainActivity.java` | ✅ |
| 2025-01-07 | 2.1/2.2 | FcmSender 사운드 동적 처리 + getSoundForChannel 추가 | `FcmSender.php` | ✅ |
| 2025-01-07 | 3.1 | MNG 알림 타입 드롭다운 추가 (6개 타입) | `fcm/send.blade.php` | ✅ |
| 2025-01-07 | 3.2 | FcmController channel_id 검증 + sound_key 제거 | `FcmController.php` | ✅ |
| 2025-01-07 | 4.1 | PushNotificationService 생성 (이벤트 기반 푸시) | `PushNotificationService.php` | ✅ |
| 2025-01-07 | 4.2 | ClientService.store()에 푸시 알림 연동 | `ClientService.php` | ✅ |
| 2025-01-07 | 5.1/5.2 | 테스트 및 검증 완료 | 서버 배포 후 실기기 테스트 | ✅ |

---

## 7. 참고 문서

- **FCM 푸시 계획**: `docs/dev_plans/react-fcm-push-notification-plan.md`
- **API 규칙**: `docs/standards/api-rules.md`

---

## 8. 알림음 파일 준비 가이드

### 요구사항
- **포맷**: WAV (권장) 또는 MP3
- **길이**: 1-3초 권장
- **샘플레이트**: 44.1kHz
- **비트레이트**: 16bit

### 임시 방안
알림음 파일이 준비되지 않은 경우, 기존 파일을 복사하여 사용:

```bash
cd app/android/app/src/main/res/raw/
cp push_default.wav push_payment.wav
cp push_default.wav push_sales_order.wav
cp push_default.wav push_purchase_order.wav
cp push_default.wav push_contract.wav
```

### 무료 알림음 리소스
- [Pixabay Sound Effects](https://pixabay.com/sound-effects/)
- [Freesound](https://freesound.org/)
- [Zapsplat](https://www.zapsplat.com/)

---

*이 문서는 /sc:plan 스킬로 생성되었습니다.*