Files
sam-docs/plans/notification-sound-system-plan.md
kent c00d74a04f docs: 알림음 시스템 구현 계획 문서 추가
- Phase 1~4 완료 (73%)
- Phase 5 테스트 및 검증 대기

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-07 20:10:19 +09:00

15 KiB

알림음 시스템 구현 계획

작성일: 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개 채널):

public static final String CHANNEL_DEFAULT = "push_default";
public static final String CHANNEL_URGENT  = "push_urgent";

목표 코드 (6개 채널):

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):

'android' => [
    'notification' => [
        'channel_id' => $channelId,
        'sound' => 'default',  // 하드코딩
    ],
],

목표:

'android' => [
    'notification' => [
        'channel_id' => $channelId,
        'sound' => $this->getSoundForChannel($channelId),
    ],
],

2.2 채널-사운드 매핑

// 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

<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 타입 → 채널 매핑

$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

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 메서드)

/** 생성 */
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

임시 방안

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

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

무료 알림음 리소스


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