Files
sam-api/app/Swagger/v1/AdminFcmApi.php
kent e571f8c38e docs(API): Swagger API 문서 업데이트
- AdminFcmApi, BillApi, ExpectedExpenseApi 개선
- PositionApi, ProcessApi, QuoteApi 개선
- ReceivablesApi, ShipmentApi, StockApi, VendorLedgerApi 개선

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-13 19:48:54 +09:00

567 lines
22 KiB
PHP

<?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",
*
* @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",
*
* @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,
*
* @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")
* ),
*
* @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() {}
}