Files
sam-react-prod/claudedocs/api/[API-SPEC-2026-03-03] ceo-dashboard-backend-api.md
유병철 cde9333652 feat: CEO 대시보드 API 연동 강화 및 회계/결재/HR 개선
- CEO 대시보드: 예상비용, 현황이슈, 일별매출/매입 등 모달 API 연동 확대
- dashboard transformers 리팩토링 (hr, sales-purchase, production-logistics 분리)
- useCEODashboard 훅 대폭 확장 (모달 데이터 fetching 로직)
- DailyReport: USD 섹션 추가 및 레이아웃 개선
- VendorManagement/ApprovalBox: 소폭 개선
- VacationManagement: 소폭 수정
- component-registry previews 업데이트
- claudedocs: 대시보드 API 스펙, 분석 문서 추가
2026-03-03 22:18:48 +09:00

23 KiB
Raw Blame History

CEO Dashboard 백엔드 API 명세서

작성일: 2026-03-03 기획서: SAM_ERP_Storyboard_D1.7_260227.pdf p33~60 프론트엔드 타입: src/lib/api/dashboard/types.ts 대상: 백엔드 팀 (Laravel sam-api)


공통 규칙

응답 형식

{
  "success": true,
  "message": "조회 성공",
  "data": { ... }
}

인증

  • 모든 API는 Authorization: Bearer {access_token} 필수
  • Next.js API route 프록시(/api/proxy/...) 경유

캐싱

  • sam_stat 테이블 5분 캐시 (기존 구현 유지)
  • 대시보드 API는 실시간성보다 성능 우선

날짜/기간 파라미터 규칙

  • 날짜: YYYY-MM-DD (예: 2026-03-03)
  • 월: YYYY-MM (예: 2026-03)
  • 분기: year=2026&quarter=1
  • 기본값: 파라미터 미지정 시 당월/당분기 기준

검수 중 발견된 누락 API

N1. 오늘의 이슈 — 과거 이력 저장 및 조회

우선순위: 상 페이지: p34 현상: GET /api/v1/today-issues/summary?date=2026-02-17 호출 시 항상 {"items":[], "total_count":0} 반환. 과거 이슈를 저장하는 구조가 없어서 이전 이슈 탭이 항상 빈 목록.

요구사항:

  1. 이슈 이력 테이블 필요 (예: dashboard_issue_history)
    • 매일 자정(또는 배치) 시점에 당일 이슈 스냅샷 저장
    • 또는 이슈 발생 시점에 이력 테이블에 INSERT
  2. 기존 API 수정: GET /api/v1/today-issues/summary
    • date 파라미터가 있을 때 해당 날짜의 이력 데이터 반환
    • date 파라미터가 없으면 기존대로 실시간 집계

Response (기존 TodayIssueApiResponse와 동일):

{
  "items": [
    {
      "id": "issue-20260302-001",
      "badge": "수주",
      "notification_type": "sales_order",
      "content": "대한건설 수주 3건 접수",
      "time": "14:30",
      "date": "2026-03-02",
      "path": "/ko/sales/order-management",
      "needs_approval": false
    }
  ],
  "total_count": 5
}

Laravel 힌트:

  • 배치 저장 방식: App\Console\Commands\SnapshotDailyIssues (Schedule::daily)
  • 또는 이벤트 기반: 수주/채권/재고 변동 시 dashboard_issue_history INSERT

N2. 자금현황 — 전일 대비 변동률 (daily_change)

우선순위: 중 페이지: p33 현상: GET /api/v1/daily-report/summary 응답에 daily_change 필드가 없음. 프론트엔드에서 하드코딩 fallback 값(+5.2%, +2.1%, +12.0%, -8.0%)을 사용 중.

요구사항:

  1. 기존 API 수정: GET /api/v1/daily-report/summary
  2. 응답에 daily_change 객체 추가
  3. 각 항목의 전일 대비 변동률(%) 계산 로직:
    • cash_asset_change_rate: (오늘 현금성자산 - 어제 현금성자산) / 어제 현금성자산 × 100
    • foreign_currency_change_rate: (오늘 외국환 - 어제 외국환) / 어제 외국환 × 100
    • income_change_rate: (오늘 입금 - 어제 입금) / 어제 입금 × 100
    • expense_change_rate: (오늘 지출 - 어제 지출) / 어제 지출 × 100
  4. 어제 데이터 없을 시 해당 필드 null (프론트에서 fallback 처리)

Response (기존 응답에 daily_change 추가):

{
  "date": "2026-03-03",
  "day_of_week": "화",
  "cash_asset_total": 1250000000,
  "foreign_currency_total": 85000,
  "krw_totals": { "income": 45000000, "expense": 32000000, "balance": 1250000000 },
  "daily_change": {
    "cash_asset_change_rate": 5.2,
    "foreign_currency_change_rate": 2.1,
    "income_change_rate": 12.0,
    "expense_change_rate": -8.0
  }
}

Laravel 힌트:

  • DailyReportService에서 전일 데이터 조회 추가
  • sam_stat 캐시 테이블에 전일 스냅샷 있으면 활용
  • 프론트 타입: DailyChangeRate (src/lib/api/dashboard/types.ts:23)

N3. 일일일보 — daily-accounts에 입출금관리 데이터 미반영

우선순위: 상 페이지: 일일일보 페이지 (/ko/accounting/daily-report) 현상: 입금관리/출금관리에서 당일 거래를 등록하면 대시보드 자금현황(daily-report/summary)의 합계에는 즉시 반영되지만, 일일일보 페이지의 계좌별 상세 테이블(daily-report/daily-accounts)에는 표시되지 않음. (출금 테스트로 확인됨, 입금도 동일 구조로 미반영 추정)

영향 범위:

데이터 관리 테이블 summary (합계) daily-accounts (상세)
입금 deposits (/api/v1/deposits) 반영 추정 미반영 추정
출금 withdrawals (/api/v1/withdrawals) 반영 확인 미반영 확인
외국환 (USD) 별도 관리 페이지 미확인 반영 확인 필요

원인 분석:

  • GET /api/v1/daily-report/summarykrw_totalsdeposits/withdrawals 테이블 데이터 포함
  • GET /api/v1/daily-report/daily-accountsbank_accounts 단위 집계만 반환, deposits/withdrawals 테이블 미포함

데이터 흐름:

입금관리 등록 → deposits 테이블 INSERT (bank_account_id 포함)
출금관리 등록 → withdrawals 테이블 INSERT (bank_account_id 포함)
  ├─ summary API → krw_totals.income/expense에 합산 → 대시보드 ✅
  └─ daily-accounts API → bank_accounts 기준만 조회 → 일일일보 상세 ❌

요구사항:

  1. GET /api/v1/daily-report/daily-accounts 수정
  2. 각 계좌별로 deposits 테이블의 당일 income과 withdrawals 테이블의 당일 expense를 합산
  3. 또는 입금/출금 등록 시 해당 계좌의 거래 내역(bank_account_transactions)에도 자동 반영

해결 방안 (택 1):

  • 방안 A (daily-accounts 쿼리 수정): bank_accounts LEFT JOIN deposits/withdrawals WHERE date = 당일 → 계좌별 income/expense에 합산
  • 방안 B (트랜잭션 연동): 입금/출금 등록 시 bank_account_transactions에도 INSERT → daily-accounts가 자연스럽게 포함

Response (기존 DailyAccountItemApi[]와 동일, 데이터만 보완):

[
  {
    "id": "acc_1",
    "category": "우리은행 123-456",
    "match_status": "matched",
    "carryover": 50000000,
    "income": 1000000,
    "expense": 50000,
    "balance": 50950000,
    "currency": "KRW"
  }
]

Laravel 힌트:

  • DailyReportServicegetDailyAccounts() 메서드 확인
  • deposits 테이블: deposit.bank_account_id로 해당 계좌 income 합산
  • withdrawals 테이블: withdrawal.bank_account_id로 해당 계좌 expense 합산
  • USD 계좌도 동일 패턴 적용 필요

N4. 현황판 purchases(발주) — path 오류 + 데이터 정합성 이슈

우선순위: 중 페이지: p34 (현황판)

이슈 A: path 하드코딩 오류

현상: purchases 항목의 실제 데이터는 purchases 테이블(매입, 공통)에서 조회하면서, path는 건설 모듈 경로로 하드코딩되어 있음.

문제 코드 (StatusBoardService.phpgetPurchaseStatus()):

$count = Purchase::query()
    ->where('tenant_id', $tenantId)
    ->where('status', 'draft')
    ->count();

return [
    'id' => 'purchases',
    'label' => '발주',
    'path' => '/construction/order/order-management',  // ← 매입 데이터인데 건설 경로
];
  • 데이터 출처: purchases 테이블 (모든 테넌트 공통 매입 테이블)
  • path: /construction/order/order-management (건설 전용 페이지)
  • 데이터와 path가 불일치 — 매입 draft 건수를 보여주면서 건설 발주 페이지로 링크

현재 프론트 임시 대응: status-issue.ts에서 /accounting/purchase(매입관리)로 오버라이드 중

요구사항:

  1. path를 /accounting/purchase로 변경 (데이터 출처와 일치시키기)
  2. 또는 테넌트 업종에 따라 path 동적 분기 (건설: /construction/order/order-management, 기타: /accounting/purchase)
  3. 라벨도 재검토: "발주"가 맞는지, "매입(임시저장)"이 더 정확한지

이슈 B: 데이터 정합성 의심

현상: StatusBoard API에서 purchases count=9건 반환, 하지만 매입관리 페이지(/accounting/purchase)에서 전체 조회 시 1건만 표시.

확인 사항 (DB 직접 확인 필요):

-- 현재 테넌트의 purchases 테이블 전체 건수
SELECT COUNT(*), status FROM purchases WHERE tenant_id = {현재 테넌트 ID} GROUP BY status;

-- draft 상태 건수 (StatusBoard가 조회하는 조건)
SELECT COUNT(*) FROM purchases WHERE tenant_id = {현재 테넌트 ID} AND status = 'draft';

가능한 원인:

  1. StatusBoard와 매입관리 페이지가 다른 tenant_id 스코프로 조회
  2. DummyDataSeeder가 다른 tenant_id로 데이터 생성
  3. 매입관리 API에 추가 필터 조건이 있어서 draft 건이 제외됨
  4. StatusBoard가 실제와 다른 데이터를 집계

기대 결과: StatusBoard 9건 클릭 → 매입관리 페이지에서 9건 확인 가능해야 함


신규 API (10개)

1. 매출 현황 Summary

우선순위: 중 페이지: p39

GET /api/v1/dashboard/sales/summary

Query Params:

파라미터 타입 필수 설명
year int N 조회 연도 (기본: 당해)
month int N 조회 월 (기본: 당월)

Response (SalesStatusApiResponse):

{
  "cumulative_sales": 312300000,
  "achievement_rate": 94.5,
  "yoy_change": 12.5,
  "monthly_sales": 312300000,
  "monthly_trend": [
    { "month": "2026-08", "label": "8월", "amount": 250000000 },
    { "month": "2026-09", "label": "9월", "amount": 280000000 }
  ],
  "client_sales": [
    { "name": "대한건설", "amount": 95000000 },
    { "name": "삼성테크", "amount": 78000000 }
  ],
  "daily_items": [
    {
      "date": "2026-02-01",
      "client": "대한건설",
      "item": "스크린 외",
      "amount": 25000000,
      "status": "deposited"
    }
  ],
  "daily_total": 312300000
}

Laravel 힌트:

  • 매출: sales_orders 합계 (confirmed 상태)
  • 달성률: 매출 목표 대비 (sales_targets 테이블)
  • YoY: 전년 동월 대비 변화율
  • 거래처별: GROUP BY vendor_id → TOP 5
  • status 코드: deposited (입금완료), unpaid (미입금), partial (부분입금)

2. 매입 현황 Summary

우선순위: 중 페이지: p40

GET /api/v1/dashboard/purchases/summary

Query Params:

파라미터 타입 필수 설명
year int N 조회 연도 (기본: 당해)
month int N 조회 월 (기본: 당월)

Response (PurchaseStatusApiResponse):

{
  "cumulative_purchase": 312300000,
  "unpaid_amount": 312300000,
  "yoy_change": -12.5,
  "monthly_trend": [
    { "month": "2026-08", "label": "8월", "amount": 180000000 }
  ],
  "material_ratio": [
    { "name": "원자재", "value": 55, "percentage": 55, "color": "#3b82f6" },
    { "name": "부자재", "value": 35, "percentage": 35, "color": "#10b981" },
    { "name": "소모품", "value": 10, "percentage": 10, "color": "#f59e0b" }
  ],
  "daily_items": [
    {
      "date": "2026-02-01",
      "supplier": "한국철강",
      "item": "철판 외",
      "amount": 45000000,
      "status": "paid"
    }
  ],
  "daily_total": 312300000
}

Laravel 힌트:

  • 매입: purchase_orders 합계
  • 미결제: 결제 미완료 건 합계
  • 원자재/부자재/소모품: item_categories 기준 분류
  • status 코드: paid (결제완료), unpaid (미결제), partial (부분결제)

3. 생산 현황 Summary

우선순위: 상 페이지: p41

GET /api/v1/dashboard/production/summary

Query Params:

파라미터 타입 필수 설명
date string N 조회 일자 (기본: 오늘, YYYY-MM-DD)

Response (DailyProductionApiResponse):

{
  "date": "2026-02-23",
  "day_of_week": "월요일",
  "processes": [
    {
      "process_name": "스크린",
      "total_work": 10,
      "todo": 3,
      "in_progress": 4,
      "completed": 3,
      "urgent": 2,
      "sub_line": 1,
      "regular": 5,
      "worker_count": 8,
      "work_items": [
        {
          "id": "wo_1",
          "order_no": "SO-2026-001",
          "client": "대한건설",
          "product": "스크린 A형",
          "quantity": 50,
          "status": "in_progress"
        }
      ],
      "workers": [
        {
          "name": "김철수",
          "assigned": 5,
          "completed": 3,
          "rate": 60
        }
      ]
    }
  ],
  "shipment": {
    "expected_amount": 150000000,
    "expected_count": 12,
    "actual_amount": 120000000,
    "actual_count": 9
  }
}

Laravel 힌트:

  • 공정: work_processes 테이블 (스크린, 슬랫, 절곡 등)
  • 작업: work_orders JOIN work_process_id
  • status: pending → todo, in_progress, completed
  • urgent: 납기 3일 이내
  • 출고: shipments 테이블 (당일 예상 vs 실적)

4. 출고 현황 (생산 현황에 포함)

우선순위: 하 페이지: p41

생산 현황 API의 shipment 필드로 포함됨. 별도 API 불필요.


5. 미출고 내역

우선순위: 하 페이지: p42

GET /api/v1/dashboard/unshipped/summary

Query Params:

파라미터 타입 필수 설명
days int N 납기 N일 이내 (기본: 30)

Response (UnshippedApiResponse):

{
  "items": [
    {
      "id": "us_1",
      "port_no": "P-2026-001",
      "site_name": "강남 현장",
      "order_client": "대한건설",
      "due_date": "2026-02-25",
      "days_left": 2
    }
  ],
  "total_count": 7
}

Laravel 힌트:

  • shipment_items WHERE shipped_at IS NULL AND due_date >= NOW()
  • days_left: DATEDIFF(due_date, NOW())
  • ORDER BY due_date ASC (납기 임박 순)

6. 시공 현황

우선순위: 중 페이지: p42

GET /api/v1/dashboard/construction/summary

Query Params:

파라미터 타입 필수 설명
month int N 조회 월 (기본: 당월)

Response (ConstructionApiResponse):

{
  "this_month": 15,
  "completed": 5,
  "items": [
    {
      "id": "cs_1",
      "site_name": "강남 현장",
      "client": "대한건설",
      "start_date": "2026-02-01",
      "end_date": "2026-02-28",
      "progress": 85,
      "status": "in_progress"
    }
  ]
}

Laravel 힌트:

  • constructions 테이블
  • status: in_progress, scheduled, completed
  • completed: 최근 7일 이내 완료 건

7. 근태 현황

우선순위: 중 페이지: p43

GET /api/v1/dashboard/attendance/summary

Query Params:

파라미터 타입 필수 설명
date string N 조회 일자 (기본: 오늘, YYYY-MM-DD)

Response (DailyAttendanceApiResponse):

{
  "present": 42,
  "on_leave": 3,
  "late": 1,
  "absent": 0,
  "employees": [
    {
      "id": "emp_1",
      "department": "생산부",
      "position": "과장",
      "name": "김철수",
      "status": "present"
    }
  ]
}

Laravel 힌트:

  • attendances WHERE date = :date
  • status: present, on_leave, late, absent
  • employees: 이상 상태(late, absent, on_leave) 위주 표시

8. 일별 매출 내역

우선순위: 하 페이지: p47 (설정 팝업에서 별도 ON/OFF)

매출 현황 API의 daily_items로 이미 포함. 별도 API 필요 시:

GET /api/v1/dashboard/sales/daily

Query Params:

파라미터 타입 필수 설명
start_date string N 시작일 (기본: 당월 1일)
end_date string N 종료일 (기본: 오늘)
page int N 페이지 (기본: 1)
per_page int N 건수 (기본: 20)

9. 일별 매입 내역

우선순위: 하

매입 현황 API의 daily_items로 이미 포함. 별도 API 필요 시:

GET /api/v1/dashboard/purchases/daily

(매출 일별과 동일 구조)


10. 접대비 상세

우선순위: 상 페이지: p53-54

GET /api/v1/dashboard/entertainment/detail

Query Params:

파라미터 타입 필수 설명
year int N 연도
quarter int N 분기 (1-4)
limit_type string N annual/quarterly
company_type string N large/medium/small

Response:

{
  "summary": {
    "total_used": 10000000,
    "annual_limit": 40120000,
    "remaining": 30120000,
    "usage_rate": 24.9
  },
  "limit_calculation": {
    "base_limit": 36000000,
    "revenue_additional": 4120000,
    "total_limit": 40120000,
    "revenue": 2060000000,
    "company_type": "medium"
  },
  "quarterly_status": [
    {
      "quarter": 1,
      "label": "1분기",
      "limit": 10030000,
      "used": 3500000,
      "remaining": 6530000,
      "exceeded": 0
    }
  ],
  "transactions": [
    {
      "id": 1,
      "date": "2026-01-15",
      "user_name": "홍길동",
      "merchant_name": "강남식당",
      "amount": 350000,
      "counterpart": "대한건설",
      "receipt_type": "법인카드",
      "risk_flags": ["high_amount"]
    }
  ]
}

수정 API (6개)

1. 가지급금 Summary (수정)

현재: 카드/가지급금/법인세/종합세 변경: 카드/경조사/상품권/접대비/총합계 (5카드)

GET /api/proxy/card-transactions/summary

Response 변경:

{
  "cards": [
    { "id": "cm1", "label": "카드", "amount": 3123000, "sub_label": "미정리 5건", "count": 5 },
    { "id": "cm2", "label": "경조사", "amount": 3123000, "sub_label": "미증빙 5건", "count": 5 },
    { "id": "cm3", "label": "상품권", "amount": 3123000, "sub_label": "미증빙 5건", "count": 5 },
    { "id": "cm4", "label": "접대비", "amount": 3123000, "sub_label": "미증빙 5건", "count": 5 },
    { "id": "cm_total", "label": "총 가지급금 합계", "amount": 350000000 }
  ],
  "check_points": [
    {
      "id": "cm-cp1",
      "type": "warning",
      "message": "법인카드 사용 총 850만원이 가지급금으로 전환되었습니다.",
      "highlights": [{ "text": "850만원", "color": "red" }]
    }
  ],
  "warning_banner": "가지급금 인정이자 4.6%, 법인세 및 연말정산 시 대표자 종합세 가중 주의"
}

Laravel 힌트:

  • 분류: card_transactions.category 기준 (card/congratulation/gift_card/entertainment)
  • 미정리/미증빙: evidence_status = 'pending' COUNT

2. 접대비 Summary (수정)

현재: 매출/한도/잔여한도/사용금액 변경: 주말심야/기피업종/고액결제/증빙미비 (리스크 4종)

GET /api/proxy/entertainment/summary

Response 변경:

{
  "cards": [
    { "id": "et1", "label": "주말/심야", "amount": 3123000, "sub_label": "5건", "count": 5 },
    { "id": "et2", "label": "기피업종 (유흥, 귀금속 등)", "amount": 3123000, "sub_label": "불인정 5건", "count": 5 },
    { "id": "et3", "label": "고액 결제", "amount": 3123000, "sub_label": "5건", "count": 5 },
    { "id": "et4", "label": "증빙 미비", "amount": 3123000, "sub_label": "5건", "count": 5 }
  ],
  "check_points": [...]
}

리스크 감지 로직 (p60 참조):

  • 주말/심야: 토일, 22:0006:00 거래
  • 기피업종: MCC 코드 기반 (유흥업소 7273, 귀금속 5944, 골프장 7941 등)
  • 고액 결제: 설정 금액(기본 50만원) 초과
  • 증빙 미비: 적격증빙(세금계산서/카드매출전표) 없는 건

3. 복리후생비 Summary (수정)

현재: 한도/잔여한도/사용금액 변경: 비과세한도초과/사적사용의심/특정인편중/항목별한도초과 (리스크 4종)

GET /api/proxy/welfare/summary

Response 변경:

{
  "cards": [
    { "id": "wf1", "label": "비과세 한도 초과", "amount": 3123000, "sub_label": "5건", "count": 5 },
    { "id": "wf2", "label": "사적 사용 의심", "amount": 3123000, "sub_label": "5건", "count": 5 },
    { "id": "wf3", "label": "특정인 편중", "amount": 3123000, "sub_label": "5건", "count": 5 },
    { "id": "wf4", "label": "항목별 한도 초과", "amount": 3123000, "sub_label": "5건", "count": 5 }
  ],
  "check_points": [...]
}

리스크 감지 로직:

  • 비과세 한도 초과: 항목별 비과세 기준 초과 (식대 20만원, 교통비 10만원 등)
  • 사적 사용 의심: 주말/야간 + 비업무 업종 조합
  • 특정인 편중: 직원별 사용액 편차 > 평균의 200%
  • 항목별 한도 초과: 설정 금액 초과

4. 가지급금 Detail (수정)

기존 LoanDashboardApiResponse에 AI분류 컬럼 추가.

GET /api/v1/loans/dashboard

Response 추가 필드:

{
  "items": [
    {
      "...기존 필드...",
      "ai_category": "카드",
      "evidence_status": "미증빙"
    }
  ]
}

5. 복리후생비 Detail (수정)

기존 WelfareDetailApiResponse에 계산방식 파라미터 추가.

GET /api/proxy/welfare/detail?calculation_type=fixed&fixed_amount_per_month=200000

(기존 구현 유지, 계산 파라미터만 반영 확인)


6. 부가세 Detail (수정)

기존 VatApiResponse에 신고기간 파라미터 반영.

GET /api/proxy/vat/summary?period_type=quarter&year=2026&period=1

(기존 구현 유지, 기간별 필터링 확인)


리스크 감지 로직 참고 (p58-60)

MCC 코드 기피업종

MCC 업종 분류
7273 유흥업소 기피업종
5944 귀금속 기피업종
7941 골프장 기피업종
5813 주점 기피업종
7011 호텔/리조트 주의업종

리스크 판별 규칙

규칙1: 시간대 이상 → 22:00~06:00 또는 토~일
규칙2: 업종 이상 → MCC 기피업종 해당
규칙3: 금액 이상 → 설정 금액 초과 (기본 50만원)
규칙4: 빈도 이상 → 월 10회 이상 동일 업종
규칙5: 증빙 미비 → 적격증빙 없음

리스크 등급:
- 2개 이상 해당 → 🔴 고위험
- 1개 해당 → 🟡 주의
- 0개 → 🟢 정상

계산 공식 참고

가지급금 인정이자 (p58)

인정이자 = 가지급금잔액 × (4.6% / 365) × 경과일수
법인세 추가 = 인정이자 × 19%
대표자 소득세 = 인정이자 × 35%

접대비 손금한도 (p59)

기본한도:
  일반법인: 1,200만원/년
  중소기업: 3,600만원/년

수입금액별 추가:
  100억 이하: 수입금액 × 0.2%
  100~500억: 2,000만원 + (수입금액-100억) × 0.1%
  500억 초과: 6,000만원 + (수입금액-500억) × 0.03%

복리후생비 (p60)

방식1 (정액): 직원수 × 월정액 × 12
방식2 (비율): 연봉총액 × 비율%

비과세 한도:
  식대: 20만원/월
  교통비: 10만원/월
  경조사: 5만원/건
  건강검진: 연간 총액/12 환산
  교육훈련: 8만원/월
  복지포인트: 10만원/월

우선순위 정리

우선순위 API 이유
🔴 접대비 summary 수정, 복리후생비 summary 수정 D1.7 카드 구조 변경
🔴 가지급금 summary 수정 D1.7 카드 구조 변경
🔴 접대비 detail 신규 모달 확장
🟡 매출 현황, 매입 현황, 시공 현황, 근태 현황 신규 섹션
🟡 생산 현황 복잡한 공정 집계
🟢 미출고 내역, 일별 매출/매입 단순 조회