docs: 알림음 시스템 구현 계획 문서 추가

- Phase 1~4 완료 (73%)
- Phase 5 테스트 및 검증 대기

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-07 20:10:19 +09:00
parent 3bfe30ee1c
commit c00d74a04f

View File

@@ -0,0 +1,423 @@
# 알림음 시스템 구현 계획
> **작성일**: 2025-01-07
> **목적**: FCM 푸시 알림 타입별 커스텀 알림음 구현
> **영향 범위**: app (Capacitor), api (Laravel), mng (Laravel)
> **상태**: 🔄 진행중
---
## 📍 현재 진행 상태
| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | Phase 4.1/4.2 - 이벤트 기반 자동 푸시 서비스 생성 및 연동 ✅ |
| **다음 작업** | Phase 5 - 테스트 및 검증 |
| **진행률** | 8/11 (73%) |
| **마지막 업데이트** | 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` | ✅ |
---
## 7. 참고 문서
- **FCM 푸시 계획**: `docs/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 스킬로 생성되었습니다.*