- AdminFcmApi, BillApi, ExpectedExpenseApi 개선 - PositionApi, ProcessApi, QuoteApi 개선 - ReceivablesApi, ShipmentApi, StockApi, VendorLedgerApi 개선 Co-Authored-By: Claude <noreply@anthropic.com>
567 lines
22 KiB
PHP
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() {}
|
|
}
|