Files
sam-docs/specs/erp-analysis/99-gap-analysis.md

1048 lines
34 KiB
Markdown
Raw Normal View History

# 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/specs/database-schema.md` |
| 시스템 아키텍처 | `docs/architecture/system-overview.md` |
| HR API 분석 | `docs/features/hr/hr-api-analysis.md` |
| 기존 API 라우트 | `api/routes/api.php` |
| 스토리보드 상세 | `docs/specs/erp-analysis/01-common.md` ~ `08-reports.md` |