2025-12-23 12:45:28 +09:00
< ? php
namespace App\Swagger\v1 ;
/**
* @ OA\Tag ( name = " Admin FCM " , description = " 관리자 FCM 푸시 알림 관리 (MNG 전용) " )
*/
/**
* Admin FCM 관련 스키마 정의
* -----------------------------------------------------------------------------
*/
/**
* @ OA\Schema (
* schema = " AdminFcmToken " ,
* type = " object " ,
* description = " FCM 디바이스 토큰 " ,
*
* @ OA\Property ( property = " id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " tenant_id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " user_id " , type = " integer " , example = 5 ),
* @ OA\Property ( property = " token " , type = " string " , example = " dGhpcyBpcyBhIHNhbXBsZSBGQ00gdG9rZW4... " ),
* @ OA\Property ( property = " platform " , type = " string " , enum = { " ios " , " android " , " web " }, example = " android " ),
* @ OA\Property ( property = " device_name " , type = " string " , nullable = true , example = " Samsung Galaxy S24 " ),
* @ OA\Property ( property = " app_version " , type = " string " , nullable = true , example = " 1.0.0 " ),
* @ OA\Property ( property = " is_active " , type = " boolean " , example = true ),
* @ OA\Property ( property = " has_error " , type = " boolean " , example = false ),
* @ OA\Property ( property = " error_message " , type = " string " , nullable = true , example = null ),
* @ OA\Property ( property = " last_used_at " , type = " string " , format = " date-time " , nullable = true , example = " 2025-12-18 10:30:00 " ),
* @ OA\Property ( property = " created_at " , type = " string " , format = " date-time " , example = " 2025-12-18 10:00:00 " ),
* @ OA\Property ( property = " updated_at " , type = " string " , format = " date-time " , example = " 2025-12-18 10:30:00 " ),
* @ OA\Property (
* property = " user " ,
* type = " object " ,
* nullable = true ,
* @ OA\Property ( property = " id " , type = " integer " , example = 5 ),
* @ OA\Property ( property = " name " , type = " string " , example = " 홍길동 " ),
* @ OA\Property ( property = " email " , type = " string " , example = " hong@example.com " )
* ),
* @ OA\Property (
* property = " tenant " ,
* type = " object " ,
* nullable = true ,
* @ OA\Property ( property = " id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " name " , type = " string " , example = " 테스트 회사 " )
* )
* )
*
* @ OA\Schema (
* schema = " AdminFcmSendLog " ,
* type = " object " ,
* description = " FCM 발송 이력 " ,
*
* @ OA\Property ( property = " id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " tenant_id " , type = " integer " , nullable = true , example = 1 ),
* @ OA\Property ( property = " sender_id " , type = " integer " , nullable = true , example = 10 , description = " 발송자 ID (MNG 관리자) " ),
* @ OA\Property ( property = " title " , type = " string " , example = " 공지사항 " ),
* @ OA\Property ( property = " body " , type = " string " , example = " 새로운 공지가 등록되었습니다. " ),
* @ OA\Property ( property = " channel_id " , type = " string " , nullable = true , example = " notice " ),
* @ OA\Property ( property = " type " , type = " string " , nullable = true , example = " notice " ),
* @ OA\Property ( property = " url " , type = " string " , nullable = true , example = " /notices/123 " ),
* @ OA\Property ( property = " total_tokens " , type = " integer " , example = 150 ),
* @ OA\Property ( property = " success_count " , type = " integer " , example = 148 ),
* @ OA\Property ( property = " failure_count " , type = " integer " , example = 2 ),
* @ OA\Property ( property = " status " , type = " string " , enum = { " pending " , " sending " , " completed " , " failed " }, example = " completed " ),
* @ OA\Property ( property = " error_message " , type = " string " , nullable = true , example = null ),
* @ OA\Property ( property = " created_at " , type = " string " , format = " date-time " , example = " 2025-12-18 10:00:00 " ),
* @ OA\Property ( property = " updated_at " , type = " string " , format = " date-time " , example = " 2025-12-18 10:01:00 " ),
* @ OA\Property (
* property = " tenant " ,
* type = " object " ,
* nullable = true ,
* @ OA\Property ( property = " id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " name " , type = " string " , example = " 테스트 회사 " )
* )
* )
*
* @ OA\Schema (
* schema = " AdminFcmSendRequest " ,
* type = " object " ,
* required = { " title " , " body " },
*
* @ OA\Property ( property = " title " , type = " string " , maxLength = 100 , example = " 공지사항 " , description = " 푸시 제목 " ),
* @ OA\Property ( property = " body " , type = " string " , maxLength = 500 , example = " 새로운 공지가 등록되었습니다. " , description = " 푸시 내용 " ),
* @ OA\Property ( property = " tenant_id " , type = " integer " , nullable = true , example = 1 , description = " 특정 테넌트만 대상 (미지정시 전체) " ),
* @ OA\Property ( property = " user_id " , type = " integer " , nullable = true , example = 5 , description = " 특정 사용자만 대상 " ),
* @ OA\Property ( property = " platform " , type = " string " , nullable = true , enum = { " ios " , " android " , " web " }, example = " android " , description = " 특정 플랫폼만 대상 " ),
* @ OA\Property ( property = " channel_id " , type = " string " , nullable = true , maxLength = 50 , example = " notice " , description = " 알림 채널 ID " ),
* @ OA\Property ( property = " type " , type = " string " , nullable = true , maxLength = 50 , example = " notice " , description = " 알림 유형 " ),
* @ OA\Property ( property = " url " , type = " string " , nullable = true , maxLength = 255 , example = " /notices/123 " , description = " 클릭 시 이동할 URL " ),
* @ OA\Property ( property = " sound_key " , type = " string " , nullable = true , maxLength = 50 , example = " default " , description = " 알림음 키 " )
* )
*
* @ OA\Schema (
* schema = " AdminFcmTokenListRequest " ,
* type = " object " ,
*
* @ OA\Property ( property = " tenant_id " , type = " integer " , nullable = true , example = 1 , description = " 테넌트 ID로 필터 " ),
* @ OA\Property ( property = " platform " , type = " string " , nullable = true , enum = { " ios " , " android " , " web " }, example = " android " , description = " 플랫폼으로 필터 " ),
* @ OA\Property ( property = " is_active " , type = " boolean " , nullable = true , example = true , description = " 활성 상태로 필터 " ),
* @ OA\Property ( property = " has_error " , type = " boolean " , nullable = true , example = false , description = " 에러 여부로 필터 " ),
* @ OA\Property ( property = " search " , type = " string " , nullable = true , maxLength = 100 , example = " 홍길동 " , description = " 사용자명/이메일 검색 " ),
* @ OA\Property ( property = " per_page " , type = " integer " , minimum = 1 , maximum = 100 , example = 20 , description = " 페이지당 항목 수 " )
* )
*
* @ OA\Schema (
* schema = " AdminFcmHistoryRequest " ,
* type = " object " ,
*
* @ OA\Property ( property = " tenant_id " , type = " integer " , nullable = true , example = 1 , description = " 테넌트 ID로 필터 " ),
* @ OA\Property ( property = " status " , type = " string " , nullable = true , enum = { " pending " , " sending " , " completed " , " failed " }, example = " completed " , description = " 발송 상태로 필터 " ),
* @ OA\Property ( property = " from " , type = " string " , format = " date " , nullable = true , example = " 2025-12-01 " , description = " 시작일 " ),
* @ OA\Property ( property = " to " , type = " string " , format = " date " , nullable = true , example = " 2025-12-31 " , description = " 종료일 " ),
* @ OA\Property ( property = " per_page " , type = " integer " , minimum = 1 , maximum = 100 , example = 20 , description = " 페이지당 항목 수 " )
* )
*
* @ OA\Schema (
* schema = " AdminFcmTokenStats " ,
* type = " object " ,
* description = " 토큰 통계 " ,
*
* @ OA\Property ( property = " total " , type = " integer " , example = 500 , description = " 전체 토큰 수 " ),
* @ OA\Property ( property = " active " , type = " integer " , example = 450 , description = " 활성 토큰 수 " ),
* @ OA\Property ( property = " inactive " , type = " integer " , example = 50 , description = " 비활성 토큰 수 " ),
* @ OA\Property ( property = " has_error " , type = " integer " , example = 10 , description = " 에러 발생 토큰 수 " ),
* @ OA\Property (
* property = " by_platform " ,
* type = " object " ,
* @ OA\Property ( property = " android " , type = " integer " , example = 300 ),
* @ OA\Property ( property = " ios " , type = " integer " , example = 180 ),
* @ OA\Property ( property = " web " , type = " integer " , example = 20 )
* )
* )
*
* @ OA\Schema (
* schema = " AdminFcmTokenPagination " ,
* type = " object " ,
*
* @ OA\Property ( property = " current_page " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " per_page " , type = " integer " , example = 20 ),
* @ OA\Property ( property = " total " , type = " integer " , example = 150 ),
* @ OA\Property ( property = " last_page " , type = " integer " , example = 8 ),
* @ OA\Property (
* property = " data " ,
* type = " array " ,
2026-01-13 19:48:54 +09:00
*
2025-12-23 12:45:28 +09:00
* @ OA\Items ( ref = " #/components/schemas/AdminFcmToken " )
* )
* )
*
* @ OA\Schema (
* schema = " AdminFcmHistoryPagination " ,
* type = " object " ,
*
* @ OA\Property ( property = " current_page " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " per_page " , type = " integer " , example = 20 ),
* @ OA\Property ( property = " total " , type = " integer " , example = 50 ),
* @ OA\Property ( property = " last_page " , type = " integer " , example = 3 ),
* @ OA\Property (
* property = " data " ,
* type = " array " ,
2026-01-13 19:48:54 +09:00
*
2025-12-23 12:45:28 +09:00
* @ OA\Items ( ref = " #/components/schemas/AdminFcmSendLog " )
* )
* )
*/
class AdminFcmApi
{
/**
* @ OA\Post (
* path = " /api/v1/admin/fcm/send " ,
* tags = { " Admin FCM " },
* summary = " FCM 푸시 발송 " ,
* description = " 대상 토큰에 FCM 푸시 알림을 발송합니다. 테넌트, 사용자, 플랫폼으로 대상을 필터링할 수 있습니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Header (
* header = " X-Sender-Id " ,
* description = " 발송자 ID (MNG 관리자 ID) " ,
* required = false ,
2026-01-13 19:48:54 +09:00
*
2025-12-23 12:45:28 +09:00
* @ OA\Schema ( type = " integer " , example = 10 )
* ),
*
* @ OA\RequestBody (
* required = true ,
*
* @ OA\JsonContent ( ref = " #/components/schemas/AdminFcmSendRequest " )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 발송 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " message " , type = " string " , example = " FCM 발송이 완료되었습니다. " ),
* @ OA\Property (
* property = " data " ,
* type = " object " ,
* @ OA\Property ( property = " log_id " , type = " integer " , example = 1 ),
* @ OA\Property ( property = " total_tokens " , type = " integer " , example = 150 ),
* @ OA\Property ( property = " success_count " , type = " integer " , example = 148 ),
* @ OA\Property ( property = " failure_count " , type = " integer " , example = 2 )
* )
* )
* }
* )
* ),
*
* @ OA\Response (
* response = 422 ,
* description = " 발송 대상 없음 또는 검증 실패 " ,
*
* @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " )
* ),
2026-01-13 19:48:54 +09:00
*
2025-12-23 12:45:28 +09:00
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function send () {}
/**
* @ OA\Get (
* path = " /api/v1/admin/fcm/preview-count " ,
* tags = { " Admin FCM " },
* summary = " 대상 토큰 수 미리보기 " ,
* description = " 발송 전 필터 조건에 맞는 활성 토큰 수를 미리 확인합니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " tenant_id " ,
* in = " query " ,
* required = false ,
* description = " 테넌트 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Parameter (
* name = " user_id " ,
* in = " query " ,
* required = false ,
* description = " 사용자 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 5 )
* ),
*
* @ OA\Parameter (
* name = " platform " ,
* in = " query " ,
* required = false ,
* description = " 플랫폼 " ,
*
* @ OA\Schema ( type = " string " , enum = { " ios " , " android " , " web " }, example = " android " )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 조회 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property (
* property = " data " ,
* type = " object " ,
* @ OA\Property ( property = " count " , type = " integer " , example = 150 )
* )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function previewCount () {}
/**
* @ OA\Get (
* path = " /api/v1/admin/fcm/tokens " ,
* tags = { " Admin FCM " },
* summary = " 토큰 목록 조회 " ,
* description = " 등록된 FCM 토큰 목록을 조회합니다. 테넌트, 플랫폼, 활성 상태, 에러 여부로 필터링할 수 있습니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " tenant_id " ,
* in = " query " ,
* required = false ,
* description = " 테넌트 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Parameter (
* name = " platform " ,
* in = " query " ,
* required = false ,
* description = " 플랫폼 " ,
*
* @ OA\Schema ( type = " string " , enum = { " ios " , " android " , " web " }, example = " android " )
* ),
*
* @ OA\Parameter (
* name = " is_active " ,
* in = " query " ,
* required = false ,
* description = " 활성 상태 " ,
*
* @ OA\Schema ( type = " boolean " , example = true )
* ),
*
* @ OA\Parameter (
* name = " has_error " ,
* in = " query " ,
* required = false ,
* description = " 에러 여부 " ,
*
* @ OA\Schema ( type = " boolean " , example = false )
* ),
*
* @ OA\Parameter (
* name = " search " ,
* in = " query " ,
* required = false ,
* description = " 사용자명/이메일 검색 " ,
*
* @ OA\Schema ( type = " string " , example = " 홍길동 " )
* ),
*
* @ OA\Parameter (
* name = " per_page " ,
* in = " query " ,
* required = false ,
* description = " 페이지당 항목 수 " ,
*
* @ OA\Schema ( type = " integer " , minimum = 1 , maximum = 100 , example = 20 )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 조회 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " data " , ref = " #/components/schemas/AdminFcmTokenPagination " )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function tokens () {}
/**
* @ OA\Get (
* path = " /api/v1/admin/fcm/tokens/stats " ,
* tags = { " Admin FCM " },
* summary = " 토큰 통계 조회 " ,
* description = " FCM 토큰의 전체 통계를 조회합니다. 활성/비활성, 플랫폼별 분포 등을 확인할 수 있습니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " tenant_id " ,
* in = " query " ,
* required = false ,
* description = " 테넌트 ID (미지정시 전체) " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 조회 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " data " , ref = " #/components/schemas/AdminFcmTokenStats " )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function tokenStats () {}
/**
* @ OA\Patch (
* path = " /api/v1/admin/fcm/tokens/ { id}/toggle " ,
* tags = { " Admin FCM " },
* summary = " 토큰 상태 토글 " ,
* description = " 토큰의 활성/비활성 상태를 토글합니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " id " ,
* in = " path " ,
* required = true ,
* description = " 토큰 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 상태 변경 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " message " , type = " string " , example = " 토큰 상태가 변경되었습니다. " ),
* @ OA\Property ( property = " data " , ref = " #/components/schemas/AdminFcmToken " )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 404 , description = " 토큰을 찾을 수 없음 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " )),
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function toggleToken () {}
/**
* @ OA\Delete (
* path = " /api/v1/admin/fcm/tokens/ { id} " ,
* tags = { " Admin FCM " },
* summary = " 토큰 삭제 " ,
* description = " FCM 토큰을 삭제합니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " id " ,
* in = " path " ,
* required = true ,
* description = " 토큰 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 삭제 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " message " , type = " string " , example = " 삭제되었습니다. " ),
* @ OA\Property (
* property = " data " ,
* type = " object " ,
* @ OA\Property ( property = " deleted " , type = " boolean " , example = true )
* )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 404 , description = " 토큰을 찾을 수 없음 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " )),
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function deleteToken () {}
/**
* @ OA\Get (
* path = " /api/v1/admin/fcm/history " ,
* tags = { " Admin FCM " },
* summary = " 발송 이력 조회 " ,
* description = " FCM 발송 이력을 조회합니다. 테넌트, 상태, 기간으로 필터링할 수 있습니다. " ,
* security = {{ " ApiKeyAuth " : {}}},
*
* @ OA\Parameter (
* name = " tenant_id " ,
* in = " query " ,
* required = false ,
* description = " 테넌트 ID " ,
*
* @ OA\Schema ( type = " integer " , example = 1 )
* ),
*
* @ OA\Parameter (
* name = " status " ,
* in = " query " ,
* required = false ,
* description = " 발송 상태 " ,
*
* @ OA\Schema ( type = " string " , enum = { " pending " , " sending " , " completed " , " failed " }, example = " completed " )
* ),
*
* @ OA\Parameter (
* name = " from " ,
* in = " query " ,
* required = false ,
* description = " 시작일 " ,
*
* @ OA\Schema ( type = " string " , format = " date " , example = " 2025-12-01 " )
* ),
*
* @ OA\Parameter (
* name = " to " ,
* in = " query " ,
* required = false ,
* description = " 종료일 " ,
*
* @ OA\Schema ( type = " string " , format = " date " , example = " 2025-12-31 " )
* ),
*
* @ OA\Parameter (
* name = " per_page " ,
* in = " query " ,
* required = false ,
* description = " 페이지당 항목 수 " ,
*
* @ OA\Schema ( type = " integer " , minimum = 1 , maximum = 100 , example = 20 )
* ),
*
* @ OA\Response (
* response = 200 ,
* description = " 조회 성공 " ,
*
* @ OA\JsonContent (
* allOf = {
*
* @ OA\Schema ( ref = " #/components/schemas/ApiResponse " ),
* @ OA\Schema (
*
* @ OA\Property ( property = " data " , ref = " #/components/schemas/AdminFcmHistoryPagination " )
* )
* }
* )
* ),
*
* @ OA\Response ( response = 401 , description = " 인증 실패 " , @ OA\JsonContent ( ref = " #/components/schemas/ErrorResponse " ))
* )
*/
public function history () {}
2026-01-13 19:48:54 +09:00
}