# SAM ERP API 개발 명세서 > 기준 문서: SAM_ERP_Storyboard_D0.8_251216 > 작성일: 2025-12-17 > 상태: 개발 준비 완료 --- ## 개발 범위 요약 | 구분 | 항목수 | 작업 | |------|--------|------| | 기존 API 활용 | 12개 | 프론트엔드 연동만 진행 | | 확장 개발 | 6개 | 기존 구조 활용, API 추가 | | 신규 개발 | 8개 | 테이블 + API 신규 생성 | --- # Part 1: 기존 API (프론트엔드 연동) > 아래 영역은 API 개발 완료. 프론트엔드 연동 시 참고. | 영역 | 기존 API | 스토리보드 참조 | |------|----------|-----------------| | 사원관리 | `/v1/employees/*` | 슬라이드 28-35 | | 부서관리 | `/v1/departments/*` | 슬라이드 36-38 | | 근태관리 | `/v1/attendances/*` | 슬라이드 23-27, 39-42 | | 게시판 | `/v1/boards/*` | - | | 권한관리 | `/v1/roles/*`, `/v1/permissions/*` | 슬라이드 96 | | 테넌트 | `/v1/tenants/*` | 슬라이드 14-22 | | 메뉴 | `/v1/menus/*` | 슬라이드 8-13 | | 거래처 | `/v1/clients/*` | 슬라이드 60-67 | | 공통코드 | `/v1/settings/common/*` | 슬라이드 93-95 | | 파일 | `/v1/files/*` | - | | 설정 | `/v1/settings/*` | - | | 프로필 | `/v1/users/me/*`, `/v1/profiles/*` | - | --- # Part 2: 확장 개발 (기존 구조 활용) ## 2.1 휴가 관리 ### 스펙 - 스토리보드: 슬라이드 43-46, 100 - 의존성: `attendances` 테이블 참조 ### 테이블: `leaves` ```sql CREATE TABLE leaves ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, leave_type VARCHAR(20) NOT NULL COMMENT '연차/반차/병가/경조사/출산/육아', start_date DATE NOT NULL, end_date DATE NOT NULL, days DECIMAL(3,1) NOT NULL COMMENT '사용일수', reason TEXT, status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/approved/rejected/cancelled', approved_by BIGINT NULL, approved_at TIMESTAMP NULL, reject_reason TEXT NULL, created_by BIGINT, updated_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant_user (tenant_id, user_id), INDEX idx_status (status), INDEX idx_dates (start_date, end_date) ); ``` ### 테이블: `leave_balances` ```sql CREATE TABLE leave_balances ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, year INT NOT NULL, total_days DECIMAL(4,1) NOT NULL DEFAULT 15 COMMENT '연간 부여일수', used_days DECIMAL(4,1) NOT NULL DEFAULT 0 COMMENT '사용일수', remaining_days DECIMAL(4,1) GENERATED ALWAYS AS (total_days - used_days) STORED, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_user_year (tenant_id, user_id, year) ); ``` ### API 엔드포인트 ``` GET /v1/leaves # 목록 (필터: status, user_id, date_range) POST /v1/leaves # 신청 GET /v1/leaves/{id} # 상세 PATCH /v1/leaves/{id} # 수정 (pending 상태만) DELETE /v1/leaves/{id} # 취소 (pending 상태만) POST /v1/leaves/{id}/approve # 승인 POST /v1/leaves/{id}/reject # 반려 (reject_reason 필수) GET /v1/leaves/balance # 내 잔여휴가 GET /v1/leaves/balance/{userId} # 특정 사용자 잔여휴가 GET /v1/settings/leave # 휴가 설정 PUT /v1/settings/leave # 휴가 설정 수정 ``` ### Request/Response 예시 ```json // POST /v1/leaves { "leave_type": "annual", "start_date": "2025-01-20", "end_date": "2025-01-21", "days": 2, "reason": "개인 사유" } // GET /v1/leaves/balance { "year": 2025, "total_days": 15, "used_days": 3, "remaining_days": 12 } ``` --- ## 2.2 근무/출퇴근 설정 ### 스펙 - 스토리보드: 슬라이드 97-99 - 의존성: `tenant_field_settings` 활용 가능 ### 테이블: `work_settings` ```sql CREATE TABLE work_settings ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL UNIQUE, work_type VARCHAR(20) DEFAULT 'fixed' COMMENT 'fixed/flexible/custom', standard_hours INT DEFAULT 40 COMMENT '주당 소정근로시간', overtime_hours INT DEFAULT 12 COMMENT '주당 연장근로시간', overtime_limit INT DEFAULT 52 COMMENT '연장근로한도', work_days JSON COMMENT '["mon","tue","wed","thu","fri"]', start_time TIME DEFAULT '09:00:00', end_time TIME DEFAULT '18:00:00', break_minutes INT DEFAULT 60, break_start TIME DEFAULT '12:00:00', break_end TIME DEFAULT '13:00:00', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); ``` ### 테이블: `attendance_settings` ```sql CREATE TABLE attendance_settings ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL UNIQUE, use_gps BOOLEAN DEFAULT FALSE, allowed_radius INT DEFAULT 100 COMMENT '허용반경(m)', hq_address VARCHAR(255), hq_latitude DECIMAL(10,8), hq_longitude DECIMAL(11,8), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); ``` ### 테이블: `sites` (현장) ```sql CREATE TABLE sites ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, name VARCHAR(100) NOT NULL, address VARCHAR(255), latitude DECIMAL(10,8), longitude DECIMAL(11,8), is_active BOOLEAN DEFAULT TRUE, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant (tenant_id) ); ``` ### API 엔드포인트 ``` GET /v1/settings/work # 근무 설정 조회 PUT /v1/settings/work # 근무 설정 수정 GET /v1/settings/attendance # 출퇴근 설정 조회 PUT /v1/settings/attendance # 출퇴근 설정 수정 GET /v1/sites # 현장 목록 POST /v1/sites # 현장 등록 GET /v1/sites/{id} # 현장 상세 PUT /v1/sites/{id} # 현장 수정 DELETE /v1/sites/{id} # 현장 삭제 ``` --- ## 2.3 카드/계좌 관리 ### 스펙 - 스토리보드: 슬라이드 101-104 - 보안: 카드번호/비밀번호 암호화 필수 ### 테이블: `cards` ```sql CREATE TABLE cards ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, card_company VARCHAR(50) NOT NULL COMMENT '카드사', card_number_encrypted TEXT NOT NULL COMMENT '암호화된 카드번호', card_number_last4 VARCHAR(4) NOT NULL COMMENT '끝 4자리', expiry_date VARCHAR(5) NOT NULL COMMENT 'MM/YY', card_password_encrypted TEXT COMMENT '암호화된 비밀번호 앞2자리', card_name VARCHAR(100) NOT NULL, status VARCHAR(20) DEFAULT 'active' COMMENT 'active/inactive', assigned_user_id BIGINT NULL, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant (tenant_id), INDEX idx_status (status) ); ``` ### 테이블: `bank_accounts` ```sql CREATE TABLE bank_accounts ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, bank_code VARCHAR(10) NOT NULL, bank_name VARCHAR(50) NOT NULL, account_number VARCHAR(30) NOT NULL, account_holder VARCHAR(50) NOT NULL, account_name VARCHAR(100) NOT NULL COMMENT '계좌별칭', status VARCHAR(20) DEFAULT 'active' COMMENT 'active/inactive', assigned_user_id BIGINT NULL, is_primary BOOLEAN DEFAULT FALSE COMMENT '대표계좌', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant (tenant_id), INDEX idx_status (status) ); ``` ### API 엔드포인트 ``` GET /v1/cards # 카드 목록 (필터: status) POST /v1/cards # 카드 등록 GET /v1/cards/{id} # 카드 상세 PUT /v1/cards/{id} # 카드 수정 DELETE /v1/cards/{id} # 카드 삭제 PATCH /v1/cards/{id}/toggle # 사용/정지 토글 GET /v1/bank-accounts # 계좌 목록 (필터: status) POST /v1/bank-accounts # 계좌 등록 GET /v1/bank-accounts/{id} # 계좌 상세 PUT /v1/bank-accounts/{id} # 계좌 수정 DELETE /v1/bank-accounts/{id} # 계좌 삭제 PATCH /v1/bank-accounts/{id}/toggle # 사용/정지 토글 PATCH /v1/bank-accounts/{id}/set-primary # 대표계좌 설정 ``` --- ## 2.4 입금/출금 관리 ### 스펙 - 스토리보드: 슬라이드 68-77 - 의존성: `clients`, `bank_accounts` 참조 ### 테이블: `deposits` (입금) ```sql CREATE TABLE deposits ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, deposit_date DATE NOT NULL, client_id BIGINT NULL, client_name VARCHAR(100) COMMENT '비회원 거래처명', bank_account_id BIGINT NULL, amount DECIMAL(15,2) NOT NULL, payment_method VARCHAR(20) NOT NULL COMMENT 'cash/transfer/card/check', account_code VARCHAR(20) COMMENT '계정과목', description TEXT, reference_type VARCHAR(50) NULL COMMENT 'sales/receivable/etc', reference_id BIGINT NULL, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant_date (tenant_id, deposit_date), INDEX idx_client (client_id) ); ``` ### 테이블: `withdrawals` (출금) ```sql CREATE TABLE withdrawals ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, withdrawal_date DATE NOT NULL, client_id BIGINT NULL, client_name VARCHAR(100), bank_account_id BIGINT NULL, amount DECIMAL(15,2) NOT NULL, payment_method VARCHAR(20) NOT NULL COMMENT 'cash/transfer/card/check', account_code VARCHAR(20) COMMENT '계정과목', description TEXT, reference_type VARCHAR(50) NULL COMMENT 'purchase/payable/payroll/etc', reference_id BIGINT NULL, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant_date (tenant_id, withdrawal_date), INDEX idx_client (client_id) ); ``` ### API 엔드포인트 ``` GET /v1/deposits # 입금 목록 (필터: date_range, client_id, payment_method) POST /v1/deposits # 입금 등록 GET /v1/deposits/{id} # 입금 상세 PUT /v1/deposits/{id} # 입금 수정 DELETE /v1/deposits/{id} # 입금 삭제 GET /v1/deposits/summary # 입금 요약 (기간별 합계) GET /v1/withdrawals # 출금 목록 POST /v1/withdrawals # 출금 등록 GET /v1/withdrawals/{id} # 출금 상세 PUT /v1/withdrawals/{id} # 출금 수정 DELETE /v1/withdrawals/{id} # 출금 삭제 GET /v1/withdrawals/summary # 출금 요약 ``` --- ## 2.5 매출/매입 관리 ### 스펙 - 스토리보드: 슬라이드 78-87 - 의존성: `clients`, `deposits`, `withdrawals` 참조 ### 테이블: `sales` (매출) ```sql CREATE TABLE sales ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, sale_number VARCHAR(30) NOT NULL COMMENT '매출번호', sale_date DATE NOT NULL, client_id BIGINT NOT NULL, supply_amount DECIMAL(15,2) NOT NULL COMMENT '공급가액', tax_amount DECIMAL(15,2) NOT NULL COMMENT '세액', total_amount DECIMAL(15,2) NOT NULL COMMENT '합계', description TEXT, status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed/invoiced', tax_invoice_id BIGINT NULL COMMENT '세금계산서 ID', deposit_id BIGINT NULL COMMENT '입금 연결', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_number (tenant_id, sale_number), INDEX idx_tenant_date (tenant_id, sale_date), INDEX idx_client (client_id) ); ``` ### 테이블: `purchases` (매입) ```sql CREATE TABLE purchases ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, purchase_number VARCHAR(30) NOT NULL, purchase_date DATE NOT NULL, client_id BIGINT NOT NULL, supply_amount DECIMAL(15,2) NOT NULL, tax_amount DECIMAL(15,2) NOT NULL, total_amount DECIMAL(15,2) NOT NULL, description TEXT, status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed', withdrawal_id BIGINT NULL COMMENT '출금 연결', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_number (tenant_id, purchase_number), INDEX idx_tenant_date (tenant_id, purchase_date), INDEX idx_client (client_id) ); ``` ### API 엔드포인트 ``` GET /v1/sales # 매출 목록 POST /v1/sales # 매출 등록 GET /v1/sales/{id} # 매출 상세 PUT /v1/sales/{id} # 매출 수정 DELETE /v1/sales/{id} # 매출 삭제 POST /v1/sales/{id}/confirm # 매출 확정 POST /v1/sales/{id}/tax-invoice # 세금계산서 발행 (바로빌 연동) GET /v1/purchases # 매입 목록 POST /v1/purchases # 매입 등록 GET /v1/purchases/{id} # 매입 상세 PUT /v1/purchases/{id} # 매입 수정 DELETE /v1/purchases/{id} # 매입 삭제 POST /v1/purchases/{id}/confirm # 매입 확정 ``` --- ## 2.6 보고서 ### 스펙 - 스토리보드: 슬라이드 106-109 - 의존성: `deposits`, `withdrawals`, `sales`, `purchases` 집계 ### API 엔드포인트 ``` GET /v1/reports/daily # 일일 일보 Query: date (기준일) Response: { previous_balance, daily_deposit, daily_withdrawal, current_balance, details: [{ type, client_name, account_code, deposit_amount, withdrawal_amount, description }] } GET /v1/reports/daily/export # 일일 일보 엑셀 다운로드 Query: date Response: Excel file GET /v1/reports/expense-estimate # 지출 예상 내역서 Query: year_month Response: { total_estimate, account_balance, expected_balance, items: [{ expected_date, item_name, amount, client_name, account_name }], monthly_summary: [{ month, total }] } GET /v1/reports/expense-estimate/export # 엑셀 다운로드 Query: year_month Response: Excel file ``` --- # Part 3: 신규 개발 ## 3.1 전자결재 모듈 ### 스펙 - 스토리보드: 슬라이드 47-59 - 핵심 기능: 기안/결재/반려/참조 ### 테이블: `approval_forms` (결재 양식) ```sql CREATE TABLE approval_forms ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, name VARCHAR(100) NOT NULL COMMENT '양식명', code VARCHAR(50) NOT NULL COMMENT '양식코드', category VARCHAR(50) COMMENT '분류', template JSON NOT NULL COMMENT '양식 템플릿 (필드 정의)', is_active BOOLEAN DEFAULT TRUE, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_code (tenant_id, code), INDEX idx_tenant (tenant_id) ); ``` ### 테이블: `approval_lines` (결재선 템플릿) ```sql CREATE TABLE approval_lines ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, name VARCHAR(100) NOT NULL, steps JSON NOT NULL COMMENT '[{order, type: approval/agreement/reference, user_id, position}]', is_default BOOLEAN DEFAULT FALSE, created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant (tenant_id) ); ``` ### 테이블: `approvals` (결재 문서) ```sql CREATE TABLE approvals ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, document_number VARCHAR(50) NOT NULL, form_id BIGINT NOT NULL, title VARCHAR(200) NOT NULL, content JSON NOT NULL COMMENT '양식 데이터', status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/pending/approved/rejected/cancelled', drafter_id BIGINT NOT NULL COMMENT '기안자', drafted_at TIMESTAMP NULL, completed_at TIMESTAMP NULL, current_step INT DEFAULT 0, attachments JSON COMMENT '첨부파일 IDs', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_number (tenant_id, document_number), INDEX idx_tenant_status (tenant_id, status), INDEX idx_drafter (drafter_id) ); ``` ### 테이블: `approval_steps` (결재 단계) ```sql CREATE TABLE approval_steps ( id BIGINT PRIMARY KEY AUTO_INCREMENT, approval_id BIGINT NOT NULL, step_order INT NOT NULL, step_type VARCHAR(20) NOT NULL COMMENT 'approval/agreement/reference', approver_id BIGINT NOT NULL, status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/approved/rejected/skipped', comment TEXT, acted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_approval (approval_id), INDEX idx_approver_status (approver_id, status) ); ``` ### API 엔드포인트 ``` # 결재 문서 GET /v1/approvals/drafts # 기안함 (내가 기안한 문서) GET /v1/approvals/inbox # 결재함 (내 결재 대기) GET /v1/approvals/completed # 결재 완료함 GET /v1/approvals/reference # 참조함 POST /v1/approvals # 문서 기안 GET /v1/approvals/{id} # 문서 상세 PUT /v1/approvals/{id} # 문서 수정 (draft만) DELETE /v1/approvals/{id} # 문서 삭제/회수 POST /v1/approvals/{id}/submit # 결재 상신 POST /v1/approvals/{id}/approve # 승인 (comment 선택) POST /v1/approvals/{id}/reject # 반려 (comment 필수) # 결재선 템플릿 GET /v1/approval-lines # 결재선 목록 POST /v1/approval-lines # 결재선 생성 PUT /v1/approval-lines/{id} # 결재선 수정 DELETE /v1/approval-lines/{id} # 결재선 삭제 # 결재 양식 GET /v1/approval-forms # 양식 목록 POST /v1/approval-forms # 양식 생성 GET /v1/approval-forms/{id} # 양식 상세 PUT /v1/approval-forms/{id} # 양식 수정 DELETE /v1/approval-forms/{id} # 양식 삭제 ``` ### 상태 전이 ``` draft → pending (상신) → approved (전체 승인) → rejected (반려) pending → cancelled (회수, 기안자만) rejected → draft (재기안 시 새 문서 생성) ``` --- ## 3.2 급여 관리 ### 스펙 - 스토리보드: 미상세 (회계관리 연계) - 의존성: `employees`, `attendances`, `leaves` ### 테이블: `payrolls` ```sql CREATE TABLE payrolls ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, pay_year INT NOT NULL, pay_month INT NOT NULL, base_salary DECIMAL(15,2) NOT NULL COMMENT '기본급', overtime_pay DECIMAL(15,2) DEFAULT 0 COMMENT '연장근로수당', bonus DECIMAL(15,2) DEFAULT 0 COMMENT '상여금', allowances JSON COMMENT '수당 상세 [{name, amount}]', gross_salary DECIMAL(15,2) NOT NULL COMMENT '총지급액', income_tax DECIMAL(15,2) DEFAULT 0 COMMENT '소득세', resident_tax DECIMAL(15,2) DEFAULT 0 COMMENT '주민세', health_insurance DECIMAL(15,2) DEFAULT 0 COMMENT '건강보험', pension DECIMAL(15,2) DEFAULT 0 COMMENT '국민연금', employment_insurance DECIMAL(15,2) DEFAULT 0 COMMENT '고용보험', deductions JSON COMMENT '공제 상세', total_deductions DECIMAL(15,2) NOT NULL COMMENT '총공제액', net_salary DECIMAL(15,2) NOT NULL COMMENT '실수령액', status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed/paid', paid_at TIMESTAMP NULL, withdrawal_id BIGINT NULL COMMENT '출금 연결', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_tenant_user_month (tenant_id, user_id, pay_year, pay_month), INDEX idx_tenant_month (tenant_id, pay_year, pay_month) ); ``` ### API 엔드포인트 ``` GET /v1/payrolls # 급여 목록 (필터: year, month, user_id, status) POST /v1/payrolls # 급여 등록 GET /v1/payrolls/{id} # 급여 상세 PUT /v1/payrolls/{id} # 급여 수정 (draft만) DELETE /v1/payrolls/{id} # 급여 삭제 (draft만) POST /v1/payrolls/{id}/confirm # 급여 확정 POST /v1/payrolls/{id}/pay # 지급 처리 (출금 연결) GET /v1/payrolls/{id}/payslip # 급여명세서 조회 GET /v1/payrolls/{id}/payslip/pdf # 급여명세서 PDF POST /v1/payrolls/calculate # 급여 일괄 계산 Body: { year, month, user_ids?: [] } // user_ids 없으면 전체 GET /v1/settings/payroll # 급여 설정 (세율, 보험료율 등) PUT /v1/settings/payroll # 급여 설정 수정 ``` --- ## 3.3 대시보드 ### 스펙 - 스토리보드: 미상세 (진입점 화면) - 의존성: 전 모듈 집계 ### API 엔드포인트 ``` GET /v1/dashboard/summary Response: { today: { date, attendances_count, leaves_count, approvals_pending }, finance: { monthly_deposit, monthly_withdrawal, balance }, sales: { monthly_sales, monthly_purchases }, tasks: { pending_approvals, pending_leaves } } GET /v1/dashboard/charts Query: period (week/month/quarter) Response: { deposit_trend: [{ date, amount }], withdrawal_trend: [{ date, amount }], sales_by_client: [{ client_name, amount }] } GET /v1/dashboard/notifications Query: limit (default 10) Response: { items: [{ id, type, message, is_read, created_at }] } GET /v1/dashboard/approvals Response: { items: [{ id, title, drafter_name, status, created_at }] } ``` --- ## 3.4 AI 리포트 ### 스펙 - 스토리보드: 슬라이드 113 - 의존성: 전 모듈 데이터 분석 ### 테이블: `ai_reports` ```sql CREATE TABLE ai_reports ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, report_date DATE NOT NULL, report_type VARCHAR(50) NOT NULL COMMENT 'daily/weekly/monthly', content JSON NOT NULL COMMENT '리포트 내용', summary TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_tenant_date (tenant_id, report_date) ); ``` ### API 엔드포인트 ``` GET /v1/reports/ai # AI 리포트 목록 POST /v1/reports/ai/generate # AI 리포트 생성 Body: { report_type: 'daily'|'weekly'|'monthly', target_date? } GET /v1/reports/ai/{id} # AI 리포트 상세 DELETE /v1/reports/ai/{id} # AI 리포트 삭제 ``` ### AI 리포트 출력 형식 ```json { "report": [ { "area": "지출분석", "status": "warning", "message": "...", "detail": "..." }, { "area": "미수금", "status": "caution", "message": "...", "detail": "..." } ], "summary": "전체 요약 메시지" } ``` - status: `warning`(빨강), `caution`(주황), `positive`(녹색), `normal`(파랑) --- ## 3.5 가지급금 관리 ### 스펙 - 스토리보드: 슬라이드 110-112 - 인정이자율: 4.6% (연도별 변동) ### 테이블: `loans` (가지급금) ```sql CREATE TABLE loans ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL COMMENT '가지급금 수령자', loan_date DATE NOT NULL COMMENT '지급일', amount DECIMAL(15,2) NOT NULL COMMENT '가지급금액', purpose TEXT COMMENT '사용목적', settlement_date DATE NULL COMMENT '정산일', settlement_amount DECIMAL(15,2) NULL COMMENT '정산금액', status VARCHAR(20) DEFAULT 'outstanding' COMMENT 'outstanding/settled/partial', withdrawal_id BIGINT NULL COMMENT '출금 연결', created_by BIGINT, deleted_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant_user (tenant_id, user_id), INDEX idx_status (status) ); ``` ### API 엔드포인트 ``` GET /v1/loans # 가지급금 목록 POST /v1/loans # 가지급금 등록 GET /v1/loans/{id} # 가지급금 상세 PUT /v1/loans/{id} # 가지급금 수정 DELETE /v1/loans/{id} # 가지급금 삭제 POST /v1/loans/{id}/settle # 정산 처리 Body: { settlement_date, settlement_amount } POST /v1/loans/calculate-interest # 인정이자 계산 Body: { year, user_id? } Response: { balance, interest_rate, recognized_interest, corporate_tax, income_tax, local_tax, total_tax } GET /v1/reports/loan-interest # 인정이자 리포트 Query: year ``` ### 계산 공식 ``` 경과일수 = 정산일 - 지급일 일이자율 = 연이자율 / 365 인정이자 = 가지급금 × 일이자율 × 경과일수 법인세추가 = 인정이자 × 0.19 소득세추가 = 인정이자 × 0.35 지방소득세 = 소득세추가 × 0.10 ``` --- ## 3.6 구독/결제 관리 ### 스펙 - 스토리보드: 미상세 (SaaS 과금) - 별도 결제 시스템 연동 필요 ### 테이블: `subscriptions` ```sql CREATE TABLE subscriptions ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL UNIQUE, plan_code VARCHAR(50) NOT NULL COMMENT 'basic/standard/premium', status VARCHAR(20) DEFAULT 'active' COMMENT 'trial/active/expired/cancelled', started_at DATE NOT NULL, expires_at DATE NOT NULL, user_limit INT DEFAULT 5, storage_limit_mb INT DEFAULT 1024, auto_renew BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); ``` ### 테이블: `payments` ```sql CREATE TABLE payments ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, subscription_id BIGINT NOT NULL, amount DECIMAL(10,2) NOT NULL, payment_method VARCHAR(20) COMMENT 'card/transfer', status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/completed/failed/refunded', paid_at TIMESTAMP NULL, pg_transaction_id VARCHAR(100), receipt_url VARCHAR(500), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_tenant (tenant_id), INDEX idx_status (status) ); ``` ### API 엔드포인트 ``` GET /v1/subscriptions # 구독 정보 POST /v1/subscriptions # 구독 신청/변경 PUT /v1/subscriptions/{id} # 구독 수정 DELETE /v1/subscriptions/{id} # 구독 해지 GET /v1/payments # 결제 내역 GET /v1/payments/{id} # 결제 상세 POST /v1/payments/retry/{id} # 결제 재시도 ``` --- ## 3.7 고객센터 ### 스펙 - 스토리보드: 미상세 (CS 기능) ### 테이블: `support_tickets` ```sql CREATE TABLE support_tickets ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NULL COMMENT 'NULL이면 비회원 문의', user_id BIGINT NULL, ticket_number VARCHAR(20) NOT NULL, category VARCHAR(50) NOT NULL COMMENT '문의유형', title VARCHAR(200) NOT NULL, content TEXT NOT NULL, status VARCHAR(20) DEFAULT 'open' COMMENT 'open/in_progress/resolved/closed', priority VARCHAR(20) DEFAULT 'normal' COMMENT 'low/normal/high/urgent', assigned_to BIGINT NULL COMMENT '담당자', resolved_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_ticket_number (ticket_number), INDEX idx_status (status) ); ``` ### 테이블: `support_ticket_replies` ```sql CREATE TABLE support_ticket_replies ( id BIGINT PRIMARY KEY AUTO_INCREMENT, ticket_id BIGINT NOT NULL, user_id BIGINT NULL COMMENT 'NULL이면 관리자 답변', is_staff BOOLEAN DEFAULT FALSE, content TEXT NOT NULL, attachments JSON, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_ticket (ticket_id) ); ``` ### 테이블: `faqs` ```sql CREATE TABLE faqs ( id BIGINT PRIMARY KEY AUTO_INCREMENT, category VARCHAR(50) NOT NULL, question VARCHAR(500) NOT NULL, answer TEXT NOT NULL, sort_order INT DEFAULT 0, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_category (category) ); ``` ### API 엔드포인트 ``` GET /v1/support/tickets # 문의 목록 POST /v1/support/tickets # 문의 등록 GET /v1/support/tickets/{id} # 문의 상세 PUT /v1/support/tickets/{id} # 문의 수정 POST /v1/support/tickets/{id}/reply # 답변/추가문의 GET /v1/support/faq # FAQ 목록 (필터: category) GET /v1/support/faq/{id} # FAQ 상세 ``` --- ## 3.8 바로빌 연동 ### 스펙 - 스토리보드: 슬라이드 63, 78 - 외부 API: 바로빌 (사업자조회, 세금계산서) ### 테이블: `tax_invoices` ```sql CREATE TABLE tax_invoices ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, invoice_type VARCHAR(20) NOT NULL COMMENT 'sales/purchase', invoice_number VARCHAR(50) NOT NULL COMMENT '승인번호', issue_date DATE NOT NULL, supplier_business_no VARCHAR(20) NOT NULL, supplier_name VARCHAR(100) NOT NULL, buyer_business_no VARCHAR(20) NOT NULL, buyer_name VARCHAR(100) NOT NULL, supply_amount DECIMAL(15,2) NOT NULL, tax_amount DECIMAL(15,2) NOT NULL, total_amount DECIMAL(15,2) NOT NULL, status VARCHAR(20) DEFAULT 'issued' COMMENT 'issued/cancelled', barobill_id VARCHAR(100) COMMENT '바로빌 문서 ID', reference_type VARCHAR(50) NULL COMMENT 'sales/purchases', reference_id BIGINT NULL, issued_at TIMESTAMP NULL, cancelled_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_tenant_date (tenant_id, issue_date), INDEX idx_invoice_number (invoice_number) ); ``` ### API 엔드포인트 ``` POST /v1/external/barobill/verify-business Body: { business_number } Response: { valid, company_name, ceo_name, business_type, ... } POST /v1/external/barobill/tax-invoice Body: { invoice_type, supplier, buyer, items, ... } Response: { id, invoice_number, barobill_id } GET /v1/external/barobill/tax-invoice/{id} Response: 세금계산서 상세 POST /v1/external/barobill/tax-invoice/{id}/cancel Response: 취소 결과 GET /v1/tax-invoices # 세금계산서 목록 (내부 조회용) GET /v1/tax-invoices/{id} # 세금계산서 상세 ``` --- # Part 4: 기획 확인 필요 > 아래 항목은 API 구현 전 비즈니스 로직 확정 필요 ## 4.1 상태 전이 조건 | 대상 | 확인 항목 | 기본값 (확정 전) | |------|----------|------------------| | 테넌트 | 신청→승인→만료→해지 전이 조건 | 수동 전환 | | 사원 | 휴직→복직/퇴사 전이 조건 | 수동 전환 | | 결재 | 반려 후 재기안 프로세스 | 새 문서 생성 | | 미수금 | 연체 판정 기준일 | 30일 | | 악성채권 | 악성채권 판정 조건 | 90일 + 수동 | ## 4.2 모듈 간 연동 | 연동 | 확인 항목 | 기본값 | |------|----------|--------| | 전자결재→회계 | 지출결의서 승인 시 출금 자동 생성 | 수동 연결 | | 휴가신청→결재 | 휴가가 결재 문서로 생성되는지 | 별도 관리 | | 휴가승인→근태 | 승인 휴가가 근태 자동 반영 | 자동 반영 | | GPS출퇴근→근태 | GPS 기록이 근태 자동 반영 | 자동 반영 | | 급여→출금 | 급여 확정 시 출금 자동 생성 | 수동 연결 | ## 4.3 외부 연동 | 항목 | 확인 필요 | |------|----------| | 바로빌 API 비용 | 호출당 비용, 월 한도 | | 연동 은행 범위 | 지원 은행 목록 | | 연동 실패 처리 | Retry 정책, fallback | ## 4.4 MES 메뉴 | 메뉴 | 확인 필요 | |------|----------| | 영업관리 | 기존 Quote API 활용 여부 | | 판매관리 | 상세 요구사항 | | 구매관리 | 상세 요구사항 | ## 4.5 어음관리 | 항목 | 확인 필요 | |------|----------| | 기능 필요성 | 사용 여부 | | 상세 기능 | 등록/만기일/추심/부도 | --- # 개발 순서 ``` Phase 1: 확장 개발 (1-2주) ├── 2.1 휴가 관리 ├── 2.2 근무/출퇴근 설정 ├── 2.3 카드/계좌 관리 ├── 2.4 입금/출금 관리 ├── 2.5 매출/매입 관리 └── 2.6 보고서 Phase 2: 핵심 신규 (2-4주) ├── 3.1 전자결재 모듈 ★ ├── 3.2 급여 관리 └── 3.3 대시보드 Phase 3: 추가 기능 (4-6주) ├── 3.4 AI 리포트 ├── 3.5 가지급금 관리 └── 3.8 바로빌 연동 Phase 4: SaaS 기능 (별도) ├── 3.6 구독/결제 관리 └── 3.7 고객센터 ``` --- # 참고 문서 | 문서 | 경로 | |------|------| | DB 스키마 | `docs/system/database/README.md` | | 시스템 아키텍처 | `docs/system/overview.md` | | HR API 분석 | `docs/features/hr/hr-api-analysis.md` | | 기존 API 라우트 | `api/routes/api.php` | | 스토리보드 상세 | `docs/system/erp-analysis/01-common.md` ~ `08-reports.md` |