285 lines
14 KiB
PHP
285 lines
14 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Swagger\v1;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @OA\Tag(name="AI Reports", description="AI 리포트 관리")
|
||
|
|
*
|
||
|
|
* @OA\Schema(
|
||
|
|
* schema="AiReport",
|
||
|
|
* type="object",
|
||
|
|
* description="AI 리포트",
|
||
|
|
*
|
||
|
|
* @OA\Property(property="id", type="integer", example=1, description="리포트 ID"),
|
||
|
|
* @OA\Property(property="tenant_id", type="integer", example=1, description="테넌트 ID"),
|
||
|
|
* @OA\Property(property="report_date", type="string", format="date", example="2025-12-18", description="리포트 기준일"),
|
||
|
|
* @OA\Property(property="report_type", type="string", enum={"daily","weekly","monthly"}, example="daily", description="리포트 유형"),
|
||
|
|
* @OA\Property(property="content", type="array", description="리포트 내용",
|
||
|
|
*
|
||
|
|
* @OA\Items(
|
||
|
|
* type="object",
|
||
|
|
*
|
||
|
|
* @OA\Property(property="영역", type="string", example="지출분석", description="분석 영역"),
|
||
|
|
* @OA\Property(property="상태", type="string", enum={"경고","주의","긍정","양호"}, example="양호", description="상태 코드"),
|
||
|
|
* @OA\Property(property="메시지", type="string", example="당월 지출이 전월 대비 5% 감소했습니다.", description="핵심 메시지"),
|
||
|
|
* @OA\Property(property="상세", type="string", example="주요 비용 절감 항목: 외주비 (-15%), 소모품비 (-8%)", description="상세 설명")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="summary", type="string", example="전반적으로 재정 상태가 양호합니다. 매출이 5% 증가하고 지출이 3% 감소했습니다.", description="전체 요약"),
|
||
|
|
* @OA\Property(property="input_data", type="object", description="입력 데이터 (비즈니스 데이터 스냅샷)"),
|
||
|
|
* @OA\Property(property="status", type="string", enum={"pending","completed","failed"}, example="completed", description="처리 상태"),
|
||
|
|
* @OA\Property(property="error_message", type="string", nullable=true, example=null, description="오류 메시지 (실패 시)"),
|
||
|
|
* @OA\Property(property="created_by", type="integer", example=1, description="생성자 ID"),
|
||
|
|
* @OA\Property(property="created_at", type="string", format="date-time", example="2025-12-18T13:30:00Z", description="생성일시"),
|
||
|
|
* @OA\Property(property="updated_at", type="string", format="date-time", example="2025-12-18T13:30:05Z", description="수정일시")
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @OA\Schema(
|
||
|
|
* schema="AiReportPagination",
|
||
|
|
* type="object",
|
||
|
|
* description="AI 리포트 페이지네이션",
|
||
|
|
*
|
||
|
|
* @OA\Property(property="current_page", type="integer", example=1),
|
||
|
|
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/AiReport")),
|
||
|
|
* @OA\Property(property="first_page_url", type="string", example="https://api.example.com/api/v1/reports/ai?page=1"),
|
||
|
|
* @OA\Property(property="from", type="integer", example=1),
|
||
|
|
* @OA\Property(property="last_page", type="integer", example=5),
|
||
|
|
* @OA\Property(property="last_page_url", type="string", example="https://api.example.com/api/v1/reports/ai?page=5"),
|
||
|
|
* @OA\Property(property="next_page_url", type="string", nullable=true, example="https://api.example.com/api/v1/reports/ai?page=2"),
|
||
|
|
* @OA\Property(property="path", type="string", example="https://api.example.com/api/v1/reports/ai"),
|
||
|
|
* @OA\Property(property="per_page", type="integer", example=15),
|
||
|
|
* @OA\Property(property="prev_page_url", type="string", nullable=true, example=null),
|
||
|
|
* @OA\Property(property="to", type="integer", example=15),
|
||
|
|
* @OA\Property(property="total", type="integer", example=50)
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @OA\Schema(
|
||
|
|
* schema="AiReportGenerateRequest",
|
||
|
|
* type="object",
|
||
|
|
* description="AI 리포트 생성 요청",
|
||
|
|
*
|
||
|
|
* @OA\Property(property="report_date", type="string", format="date", example="2025-12-18", description="리포트 기준일 (오늘 이전, 기본값: 오늘)"),
|
||
|
|
* @OA\Property(property="report_type", type="string", enum={"daily","weekly","monthly"}, example="daily", description="리포트 유형 (기본값: daily)")
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @OA\Schema(
|
||
|
|
* schema="AiReportInputData",
|
||
|
|
* type="object",
|
||
|
|
* description="AI 리포트 입력 데이터",
|
||
|
|
*
|
||
|
|
* @OA\Property(property="report_date", type="string", format="date", example="2025-12-18", description="기준일"),
|
||
|
|
* @OA\Property(property="report_type", type="string", example="daily", description="리포트 유형"),
|
||
|
|
* @OA\Property(property="period", type="object", description="분석 기간",
|
||
|
|
* @OA\Property(property="start", type="string", format="date", example="2025-12-18"),
|
||
|
|
* @OA\Property(property="end", type="string", format="date", example="2025-12-18")
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="expense", type="object", description="지출 데이터",
|
||
|
|
* @OA\Property(property="current_total", type="number", format="float", example=5000000),
|
||
|
|
* @OA\Property(property="previous_total", type="number", format="float", example=5500000),
|
||
|
|
* @OA\Property(property="change_rate", type="number", format="float", example=-9.1)
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="sales", type="object", description="매출 데이터",
|
||
|
|
* @OA\Property(property="current_total", type="number", format="float", example=10000000),
|
||
|
|
* @OA\Property(property="previous_total", type="number", format="float", example=9500000),
|
||
|
|
* @OA\Property(property="change_rate", type="number", format="float", example=5.3)
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="purchase", type="object", description="매입 데이터",
|
||
|
|
* @OA\Property(property="current_total", type="number", format="float", example=3000000),
|
||
|
|
* @OA\Property(property="previous_total", type="number", format="float", example=2800000),
|
||
|
|
* @OA\Property(property="change_rate", type="number", format="float", example=7.1)
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="deposit_withdrawal", type="object", description="입출금 데이터",
|
||
|
|
* @OA\Property(property="total_deposit", type="number", format="float", example=15000000),
|
||
|
|
* @OA\Property(property="total_withdrawal", type="number", format="float", example=8000000),
|
||
|
|
* @OA\Property(property="net_flow", type="number", format="float", example=7000000)
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="card_account", type="object", description="카드/계좌 데이터",
|
||
|
|
* @OA\Property(property="active_cards", type="integer", example=3),
|
||
|
|
* @OA\Property(property="current_balance", type="number", format="float", example=50000000)
|
||
|
|
* ),
|
||
|
|
* @OA\Property(property="receivable", type="object", description="미수금 데이터",
|
||
|
|
* @OA\Property(property="total_amount", type="number", format="float", example=8000000),
|
||
|
|
* @OA\Property(property="count", type="integer", example=5),
|
||
|
|
* @OA\Property(property="overdue_amount", type="number", format="float", example=2000000),
|
||
|
|
* @OA\Property(property="overdue_count", type="integer", example=2)
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
class AiReportApi
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* @OA\Get(
|
||
|
|
* path="/api/v1/reports/ai",
|
||
|
|
* tags={"AI Reports"},
|
||
|
|
* summary="AI 리포트 목록 조회",
|
||
|
|
* description="AI 리포트 목록을 페이지네이션으로 조회합니다.",
|
||
|
|
* security={{"BearerAuth": {}}, {"ApiKeyAuth": {}}},
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="per_page",
|
||
|
|
* in="query",
|
||
|
|
* description="페이지당 항목 수 (1-100, 기본값: 15)",
|
||
|
|
* required=false,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="integer", minimum=1, maximum=100, example=15)
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="report_type",
|
||
|
|
* in="query",
|
||
|
|
* description="리포트 유형 필터",
|
||
|
|
* required=false,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="string", enum={"daily","weekly","monthly"}, example="daily")
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="status",
|
||
|
|
* in="query",
|
||
|
|
* description="처리 상태 필터",
|
||
|
|
* required=false,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="string", enum={"pending","completed","failed"}, example="completed")
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="start_date",
|
||
|
|
* in="query",
|
||
|
|
* description="시작일 필터 (YYYY-MM-DD)",
|
||
|
|
* required=false,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="string", format="date", example="2025-12-01")
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="end_date",
|
||
|
|
* in="query",
|
||
|
|
* description="종료일 필터 (YYYY-MM-DD, start_date 이상)",
|
||
|
|
* required=false,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="string", format="date", example="2025-12-31")
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="성공",
|
||
|
|
*
|
||
|
|
* @OA\JsonContent(
|
||
|
|
*
|
||
|
|
* @OA\Property(property="success", type="boolean", example=true),
|
||
|
|
* @OA\Property(property="message", type="string", example="AI 리포트 목록을 조회했습니다."),
|
||
|
|
* @OA\Property(property="data", ref="#/components/schemas/AiReportPagination")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||
|
|
* @OA\Response(response=422, description="유효성 검사 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
public function index() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @OA\Post(
|
||
|
|
* path="/api/v1/reports/ai/generate",
|
||
|
|
* tags={"AI Reports"},
|
||
|
|
* summary="AI 리포트 생성",
|
||
|
|
* description="Google Gemini AI를 사용하여 비즈니스 데이터 기반 리포트를 생성합니다. 지출, 매출, 매입, 입출금, 카드/계좌, 미수금 데이터를 종합 분석합니다.",
|
||
|
|
* security={{"BearerAuth": {}}, {"ApiKeyAuth": {}}},
|
||
|
|
*
|
||
|
|
* @OA\RequestBody(
|
||
|
|
* required=false,
|
||
|
|
* description="리포트 생성 요청 (모든 필드 선택적, 기본값 사용 가능)",
|
||
|
|
*
|
||
|
|
* @OA\JsonContent(ref="#/components/schemas/AiReportGenerateRequest")
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(
|
||
|
|
* response=201,
|
||
|
|
* description="리포트 생성 완료",
|
||
|
|
*
|
||
|
|
* @OA\JsonContent(
|
||
|
|
*
|
||
|
|
* @OA\Property(property="success", type="boolean", example=true),
|
||
|
|
* @OA\Property(property="message", type="string", example="AI 리포트가 생성되었습니다."),
|
||
|
|
* @OA\Property(property="data", ref="#/components/schemas/AiReport")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||
|
|
* @OA\Response(response=422, description="유효성 검사 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||
|
|
* @OA\Response(response=500, description="AI API 오류", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
public function generate() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @OA\Get(
|
||
|
|
* path="/api/v1/reports/ai/{id}",
|
||
|
|
* tags={"AI Reports"},
|
||
|
|
* summary="AI 리포트 상세 조회",
|
||
|
|
* description="특정 AI 리포트의 상세 정보를 조회합니다.",
|
||
|
|
* security={{"BearerAuth": {}}, {"ApiKeyAuth": {}}},
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="id",
|
||
|
|
* in="path",
|
||
|
|
* description="리포트 ID",
|
||
|
|
* required=true,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="integer", example=1)
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="성공",
|
||
|
|
*
|
||
|
|
* @OA\JsonContent(
|
||
|
|
*
|
||
|
|
* @OA\Property(property="success", type="boolean", example=true),
|
||
|
|
* @OA\Property(property="message", type="string", example="AI 리포트를 조회했습니다."),
|
||
|
|
* @OA\Property(property="data", ref="#/components/schemas/AiReport")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||
|
|
* @OA\Response(response=404, description="리포트 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
public function show() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @OA\Delete(
|
||
|
|
* path="/api/v1/reports/ai/{id}",
|
||
|
|
* tags={"AI Reports"},
|
||
|
|
* summary="AI 리포트 삭제",
|
||
|
|
* description="특정 AI 리포트를 삭제합니다.",
|
||
|
|
* security={{"BearerAuth": {}}, {"ApiKeyAuth": {}}},
|
||
|
|
*
|
||
|
|
* @OA\Parameter(
|
||
|
|
* name="id",
|
||
|
|
* in="path",
|
||
|
|
* description="리포트 ID",
|
||
|
|
* required=true,
|
||
|
|
*
|
||
|
|
* @OA\Schema(type="integer", example=1)
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="삭제 성공",
|
||
|
|
*
|
||
|
|
* @OA\JsonContent(
|
||
|
|
*
|
||
|
|
* @OA\Property(property="success", type="boolean", example=true),
|
||
|
|
* @OA\Property(property="message", type="string", example="AI 리포트가 삭제되었습니다."),
|
||
|
|
* @OA\Property(property="data", type="null")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
*
|
||
|
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||
|
|
* @OA\Response(response=404, description="리포트 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
public function destroy() {}
|
||
|
|
}
|