docs: [finance] 경조사비 서비스 이관 기획서 추가
- MNG 경조사비 → API+React 이관 기획 - API 엔드포인트 7개, React 페이지 구성 설계 - INDEX.md에 문서 등록
This commit is contained in:
1
INDEX.md
1
INDEX.md
@@ -42,6 +42,7 @@
|
||||
| QMS 점검표 | `dev/dev_plans/qms-checklist-template-plan.md` | 점검표 템플릿 관리 기능 |
|
||||
| 부적합관리 | `dev/dev_plans/nonconforming-management-plan.md` | 자재관리 부적합관리 기획 (불량내역/처리방법/자재비용) |
|
||||
| 계정별원장·손익계산서 | `dev/dev_plans/account-ledger-income-statement-plan.md` | 계정별원장 + 손익계산서 신규 메뉴 기획 (더존 참고) |
|
||||
| 경조사비 서비스 이관 | `dev/dev_plans/condolence-expense-service-plan.md` | MNG 경조사비 → API+React 서비스 이관 기획 |
|
||||
| 서버 운영 | `dev/deploys/ops-manual/README.md` | 서버 운영 매뉴얼 |
|
||||
| 서버 접근/백업 | `system/server-access-management.md` | 계정, 권한, 백업, 리플리케이션 |
|
||||
| 이관 작업 | `system/migration-status.md` | MNG→API+React 이관 현황, 우선순위, 로드맵 |
|
||||
|
||||
548
dev/dev_plans/condolence-expense-service-plan.md
Normal file
548
dev/dev_plans/condolence-expense-service-plan.md
Normal file
@@ -0,0 +1,548 @@
|
||||
# 경조사비 서비스 이관 기획서
|
||||
|
||||
> **작성일**: 2026-03-19
|
||||
> **상태**: 기획 확정
|
||||
> **대상**: MNG → API + React (서비스 이관)
|
||||
> **위치**: 서비스 > 회계관리 > 경조사비
|
||||
|
||||
---
|
||||
|
||||
## 1. 개요
|
||||
|
||||
### 1.1 목적
|
||||
|
||||
MNG 백오피스의 경조사비관리 기능을 서비스(API + React)로 이관한다.
|
||||
기존 MNG의 HTMX + Alpine.js 기반 UI를 REST API + React 구조로 재구현하며,
|
||||
멀티테넌트 정책을 강화하고 사용자(테넌트) 직접 사용이 가능하도록 한다.
|
||||
|
||||
### 1.2 배경
|
||||
|
||||
- MNG `회계/세무관리 > 경조사비관리` 메뉴로 기존 구현 완료 (2026-03-06)
|
||||
- DB 테이블 `condolence_expenses`는 API 프로젝트에서 마이그레이션 관리 중
|
||||
- MNG는 `scopeForTenant()` 수동 스코프 사용 → API는 `BelongsToTenant` 글로벌 스코프로 전환
|
||||
- MNG Controller에 비즈니스 로직이 직접 작성됨 → API는 Service-First 패턴 적용
|
||||
|
||||
### 1.3 이관 범위
|
||||
|
||||
| 구분 | MNG (현재) | API + React (이관 후) |
|
||||
|------|-----------|---------------------|
|
||||
| **백엔드** | Controller 직접 로직 | Service + Controller + FormRequest |
|
||||
| **프론트** | Blade + Alpine.js | React (Next.js) |
|
||||
| **인증** | 세션 기반 | Bearer 토큰 + `BelongsToTenant` |
|
||||
| **데이터** | `scopeForTenant()` 수동 | 글로벌 스코프 자동 격리 |
|
||||
| **API 문서** | 없음 | Swagger |
|
||||
|
||||
---
|
||||
|
||||
## 2. 현재 MNG 기능 분석
|
||||
|
||||
### 2.1 DB 테이블 (`condolence_expenses`)
|
||||
|
||||
> **마이그레이션**: `api/database/migrations/2026_03_06_220000_create_condolence_expenses_table.php`
|
||||
|
||||
| 컬럼 | 타입 | 설명 |
|
||||
|------|------|------|
|
||||
| `id` | BIGINT PK | 고유 ID |
|
||||
| `tenant_id` | BIGINT (FK, INDEX) | 테넌트 ID |
|
||||
| `event_date` | DATE | 경조사 발생일 |
|
||||
| `expense_date` | DATE | 지출일 |
|
||||
| `partner_name` | VARCHAR(100) | 거래처명/대상자 |
|
||||
| `description` | VARCHAR(200) | 내역 |
|
||||
| `category` | VARCHAR(20) | `congratulation`(축의) / `condolence`(부조) |
|
||||
| `has_cash` | BOOLEAN | 부조금 여부 |
|
||||
| `cash_method` | VARCHAR(30) | `cash` / `transfer` / `card` |
|
||||
| `cash_amount` | INTEGER | 부조금액 |
|
||||
| `has_gift` | BOOLEAN | 선물 여부 |
|
||||
| `gift_type` | VARCHAR(50) | 선물 종류 |
|
||||
| `gift_amount` | INTEGER | 선물 금액 |
|
||||
| `total_amount` | INTEGER | 총금액 (부조금 + 선물) |
|
||||
| `options` | JSON | 확장 속성 |
|
||||
| `memo` | TEXT | 비고 |
|
||||
| `created_by` | BIGINT | 등록자 |
|
||||
| `created_at` / `updated_at` | TIMESTAMP | 타임스탬프 |
|
||||
| `deleted_at` | TIMESTAMP | 소프트 삭제 |
|
||||
|
||||
**인덱스**: `(tenant_id, event_date)`, `(tenant_id, category)`
|
||||
|
||||
### 2.2 MNG 기능 목록
|
||||
|
||||
| 기능 | MNG 메서드 | 설명 |
|
||||
|------|-----------|------|
|
||||
| 목록 조회 | `list()` | 연도/구분/검색 필터 + 통계 |
|
||||
| 등록 | `store()` | 경조사비 신규 등록 |
|
||||
| 수정 | `update()` | 기존 항목 수정 |
|
||||
| 삭제 | `destroy()` | 소프트 삭제 |
|
||||
| CSV 내보내기 | JS `exportCsv()` | 프론트엔드에서 직접 생성 |
|
||||
|
||||
### 2.3 통계 응답 (`stats`)
|
||||
|
||||
```json
|
||||
{
|
||||
"totalCount": 12,
|
||||
"totalAmount": 1250000,
|
||||
"cashTotal": 750000,
|
||||
"giftTotal": 500000,
|
||||
"congratulationCount": 7,
|
||||
"condolenceCount": 5
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. API 설계
|
||||
|
||||
### 3.1 엔드포인트
|
||||
|
||||
> **라우트 파일**: `api/routes/api/v1/finance.php`
|
||||
> **기본 경로**: `/api/v1/condolence-expenses`
|
||||
|
||||
| Method | Path | 설명 | 비고 |
|
||||
|--------|------|------|------|
|
||||
| GET | `/` | 목록 조회 (페이지네이션) | 필터: year, category, search |
|
||||
| POST | `/` | 신규 등록 | |
|
||||
| GET | `/summary` | 통계 조회 | 연도/구분별 집계 |
|
||||
| GET | `/{id}` | 상세 조회 | |
|
||||
| PUT | `/{id}` | 수정 | |
|
||||
| DELETE | `/{id}` | 삭제 (소프트) | |
|
||||
| GET | `/export` | CSV/Excel 내보내기 | 서버사이드 생성 |
|
||||
|
||||
### 3.2 목록 조회 요청/응답
|
||||
|
||||
**요청 파라미터**:
|
||||
|
||||
| 파라미터 | 타입 | 필수 | 설명 | 기본값 |
|
||||
|---------|------|:---:|------|--------|
|
||||
| `year` | integer | N | 연도 필터 | 당해연도 |
|
||||
| `category` | string | N | `congratulation` / `condolence` | 전체 |
|
||||
| `search` | string | N | 거래처명/내역/비고 통합 검색 | - |
|
||||
| `page` | integer | N | 페이지 번호 | 1 |
|
||||
| `per_page` | integer | N | 페이지 크기 | 50 |
|
||||
| `sort_by` | string | N | 정렬 기준 | `event_date` |
|
||||
| `sort_order` | string | N | `asc` / `desc` | `desc` |
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"event_date": "2026-03-15",
|
||||
"expense_date": "2026-03-16",
|
||||
"partner_name": "ABC 회사",
|
||||
"description": "김과장 결혼축의금",
|
||||
"category": "congratulation",
|
||||
"category_label": "축의",
|
||||
"has_cash": true,
|
||||
"cash_method": "transfer",
|
||||
"cash_method_label": "계좌이체",
|
||||
"cash_amount": 50000,
|
||||
"has_gift": true,
|
||||
"gift_type": "화환",
|
||||
"gift_amount": 30000,
|
||||
"total_amount": 80000,
|
||||
"memo": "사원 본인 결혼",
|
||||
"created_by_name": "홍길동",
|
||||
"created_at": "2026-03-16T10:30:00"
|
||||
}
|
||||
],
|
||||
"meta": { "current_page": 1, "last_page": 1, "per_page": 50, "total": 12 }
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 통계 조회 (`/summary`)
|
||||
|
||||
**요청**: `?year=2026&category=all`
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"total_count": 12,
|
||||
"total_amount": 1250000,
|
||||
"cash_total": 750000,
|
||||
"gift_total": 500000,
|
||||
"congratulation_count": 7,
|
||||
"condolence_count": 5,
|
||||
"congratulation_amount": 800000,
|
||||
"condolence_amount": 450000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 등록/수정 요청
|
||||
|
||||
```json
|
||||
{
|
||||
"event_date": "2026-03-15",
|
||||
"expense_date": "2026-03-16",
|
||||
"partner_name": "ABC 회사",
|
||||
"description": "김과장 결혼축의금",
|
||||
"category": "congratulation",
|
||||
"has_cash": true,
|
||||
"cash_method": "transfer",
|
||||
"cash_amount": 50000,
|
||||
"has_gift": true,
|
||||
"gift_type": "화환",
|
||||
"gift_amount": 30000,
|
||||
"memo": "사원 본인 결혼"
|
||||
}
|
||||
```
|
||||
|
||||
> `total_amount`는 서버에서 자동 계산 (클라이언트 전송 불필요)
|
||||
|
||||
### 3.5 검증 규칙 (FormRequest)
|
||||
|
||||
| 필드 | 규칙 |
|
||||
|------|------|
|
||||
| `partner_name` | 필수, string, max:100 |
|
||||
| `category` | 필수, in:congratulation,condolence |
|
||||
| `event_date` | 선택, date |
|
||||
| `expense_date` | 선택, date |
|
||||
| `description` | 선택, string, max:200 |
|
||||
| `has_cash` | 선택, boolean |
|
||||
| `cash_method` | `has_cash`=true일 때 필수, in:cash,transfer,card |
|
||||
| `cash_amount` | `has_cash`=true일 때 필수, integer, min:0 |
|
||||
| `has_gift` | 선택, boolean |
|
||||
| `gift_type` | `has_gift`=true일 때 선택, string, max:50 |
|
||||
| `gift_amount` | `has_gift`=true일 때 필수, integer, min:0 |
|
||||
| `memo` | 선택, string |
|
||||
|
||||
---
|
||||
|
||||
## 4. API 구현 상세
|
||||
|
||||
### 4.1 파일 구조
|
||||
|
||||
```
|
||||
api/
|
||||
├── app/
|
||||
│ ├── Http/
|
||||
│ │ ├── Controllers/Api/V1/CondolenceExpenseController.php
|
||||
│ │ └── Requests/V1/CondolenceExpense/
|
||||
│ │ ├── StoreCondolenceExpenseRequest.php
|
||||
│ │ └── UpdateCondolenceExpenseRequest.php
|
||||
│ ├── Models/Tenants/CondolenceExpense.php
|
||||
│ ├── Services/CondolenceExpenseService.php
|
||||
│ └── Swagger/v1/CondolenceExpenseApi.php
|
||||
└── routes/api/v1/finance.php (라우트 추가)
|
||||
```
|
||||
|
||||
### 4.2 Model
|
||||
|
||||
```php
|
||||
class CondolenceExpense extends Model
|
||||
{
|
||||
use Auditable, BelongsToTenant, ModelTrait, SoftDeletes;
|
||||
|
||||
// 카테고리 상수
|
||||
const CATEGORY_CONGRATULATION = 'congratulation';
|
||||
const CATEGORY_CONDOLENCE = 'condolence';
|
||||
|
||||
// 지출방법 상수
|
||||
const CASH_METHOD_CASH = 'cash';
|
||||
const CASH_METHOD_TRANSFER = 'transfer';
|
||||
const CASH_METHOD_CARD = 'card';
|
||||
|
||||
protected $casts = [
|
||||
'event_date' => 'date',
|
||||
'expense_date' => 'date',
|
||||
'has_cash' => 'boolean',
|
||||
'has_gift' => 'boolean',
|
||||
'cash_amount' => 'integer',
|
||||
'gift_amount' => 'integer',
|
||||
'total_amount' => 'integer',
|
||||
'options' => 'array',
|
||||
];
|
||||
|
||||
// Accessor: category_label
|
||||
// Accessor: cash_method_label
|
||||
// Scope: scopeByCategory(), scopeInYear()
|
||||
// Relation: creator() → User (created_by)
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Service 메서드
|
||||
|
||||
| 메서드 | 설명 |
|
||||
|--------|------|
|
||||
| `index(array $params)` | 페이지네이션 + 필터 (year, category, search, sort) |
|
||||
| `store(array $data)` | 등록 (total_amount 자동 계산, created_by 설정) |
|
||||
| `show(int $id)` | 상세 조회 |
|
||||
| `update(int $id, array $data)` | 수정 (total_amount 재계산) |
|
||||
| `destroy(int $id)` | 소프트 삭제 |
|
||||
| `summary(array $params)` | 통계 집계 (year, category 필터) |
|
||||
| `export(array $params)` | CSV/Excel 데이터 생성 |
|
||||
|
||||
### 4.4 total_amount 자동 계산
|
||||
|
||||
```php
|
||||
private function calculateTotal(array $data): int
|
||||
{
|
||||
$cash = ($data['has_cash'] ?? false) ? ($data['cash_amount'] ?? 0) : 0;
|
||||
$gift = ($data['has_gift'] ?? false) ? ($data['gift_amount'] ?? 0) : 0;
|
||||
return $cash + $gift;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 마이그레이션 추가 필요 여부
|
||||
|
||||
> **기존 테이블**: `condolence_expenses` (이미 존재)
|
||||
> **추가 마이그레이션**: `updated_by`, `deleted_by` 컬럼 추가 (Auditable 트레이트 호환)
|
||||
|
||||
```php
|
||||
// 추가 마이그레이션 필요
|
||||
Schema::table('condolence_expenses', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->after('created_by');
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->after('updated_by');
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. React 구현 상세
|
||||
|
||||
### 5.1 메뉴 위치
|
||||
|
||||
```
|
||||
회계관리 (accounting)
|
||||
├── 입금관리
|
||||
├── 출금관리
|
||||
├── 카드거래조회
|
||||
├── 은행거래조회
|
||||
├── ...
|
||||
├── 경조사비 ← 신규 (NEW)
|
||||
├── 상품권
|
||||
└── ...
|
||||
```
|
||||
|
||||
**React 라우트**: `/accounting/condolence-expenses`
|
||||
|
||||
### 5.2 파일 구조
|
||||
|
||||
```
|
||||
react/src/
|
||||
├── app/[locale]/(protected)/accounting/
|
||||
│ └── condolence-expenses/
|
||||
│ └── page.tsx (진입점: mode 분기)
|
||||
├── components/accounting/
|
||||
│ └── CondolenceExpenseManagement/
|
||||
│ ├── index.tsx (메인 컴포넌트)
|
||||
│ ├── CondolenceExpenseList.tsx (목록 + 필터 + 통계)
|
||||
│ ├── CondolenceExpenseForm.tsx (등록/수정 모달)
|
||||
│ ├── actions.ts (Server Actions)
|
||||
│ └── types.ts (타입 정의)
|
||||
```
|
||||
|
||||
### 5.3 페이지 구성
|
||||
|
||||
#### 통계 카드 (상단)
|
||||
|
||||
| 카드 | 값 | 스타일 |
|
||||
|------|------|--------|
|
||||
| 총 건수 | `total_count` | - |
|
||||
| 총 금액 | `total_amount` | 통화 포맷 |
|
||||
| 부조금 합계 | `cash_total` | 통화 포맷 |
|
||||
| 선물 합계 | `gift_total` | 통화 포맷 |
|
||||
| 축의/부조 | `congratulation_count` / `condolence_count` | 건수 |
|
||||
|
||||
#### 필터 (통계 카드 하단)
|
||||
|
||||
| 필터 | 타입 | 옵션 |
|
||||
|------|------|------|
|
||||
| 연도 | Select | 당해 ~ 5년 전 |
|
||||
| 구분 | Select | 전체 / 축의 / 부조 |
|
||||
| 검색 | Input | 거래처명, 내역, 비고 (debounce 300ms) |
|
||||
|
||||
#### 테이블
|
||||
|
||||
| No | 컬럼 | 정렬 |
|
||||
|----|------|------|
|
||||
| 1 | 경조사일자 | 좌 |
|
||||
| 2 | 지출일자 | 좌 |
|
||||
| 3 | 거래처명 | 좌 |
|
||||
| 4 | 내역 | 좌 |
|
||||
| 5 | 구분 | 중앙 (배지: 축의=빨강, 부조=회색) |
|
||||
| 6 | 부조금 여부 | 중앙 |
|
||||
| 7 | 지출방법 | 좌 |
|
||||
| 8 | 부조금액 | 우 (통화) |
|
||||
| 9 | 선물 여부 | 중앙 |
|
||||
| 10 | 선물종류 | 좌 |
|
||||
| 11 | 선물금액 | 우 (통화) |
|
||||
| 12 | 총금액 | 우 (통화, 굵게) |
|
||||
| 13 | 비고 | 좌 |
|
||||
|
||||
**하단 합계 행**: 부조금액 합계, 선물금액 합계, 총금액 합계
|
||||
|
||||
#### 등록/수정 모달
|
||||
|
||||
MNG 모달 구조를 React Dialog로 재현:
|
||||
|
||||
1. 날짜 (경조사일자, 지출일자)
|
||||
2. 거래처명 (필수), 내역, 구분 (축의/부조)
|
||||
3. 부조금 섹션 (체크박스 토글) — 지출방법, 금액
|
||||
4. 선물 섹션 (체크박스 토글) — 종류, 금액
|
||||
5. 총금액 (읽기 전용, 자동 계산)
|
||||
6. 비고
|
||||
|
||||
### 5.4 Server Actions (`actions.ts`)
|
||||
|
||||
```typescript
|
||||
// buildApiUrl 필수 사용
|
||||
import { buildApiUrl } from '@/lib/api/query-params';
|
||||
|
||||
export async function getCondolenceExpenses(params) {
|
||||
// GET /api/v1/condolence-expenses
|
||||
}
|
||||
|
||||
export async function getCondolenceExpenseSummary(params) {
|
||||
// GET /api/v1/condolence-expenses/summary
|
||||
}
|
||||
|
||||
export async function createCondolenceExpense(data) {
|
||||
// POST /api/v1/condolence-expenses
|
||||
}
|
||||
|
||||
export async function updateCondolenceExpense(id, data) {
|
||||
// PUT /api/v1/condolence-expenses/{id}
|
||||
}
|
||||
|
||||
export async function deleteCondolenceExpense(id) {
|
||||
// DELETE /api/v1/condolence-expenses/{id}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 인증 및 권한
|
||||
|
||||
### 6.1 API 인증
|
||||
|
||||
- 기본 미들웨어: `auth.apikey` (API Key + Bearer 토큰)
|
||||
- `BelongsToTenant` 글로벌 스코프로 자동 데이터 격리
|
||||
|
||||
### 6.2 MNG → API 호출 시
|
||||
|
||||
> 경조사비 API는 Bearer 토큰 **필수** (화이트리스트 등록 불필요)
|
||||
> MNG에서 경조사비를 계속 사용하려면 FormulaApiService 패턴으로 API 호출 필요
|
||||
|
||||
### 6.3 React 인증
|
||||
|
||||
- `authenticatedFetch` 사용 (HttpOnly 쿠키 기반)
|
||||
- 직접 `fetch` 금지
|
||||
|
||||
---
|
||||
|
||||
## 7. 구현 순서
|
||||
|
||||
### Phase 1: API 구현
|
||||
|
||||
| 순서 | 작업 | 파일 |
|
||||
|------|------|------|
|
||||
| 1 | 마이그레이션 (updated_by, deleted_by 추가) | `database/migrations/` |
|
||||
| 2 | Model 생성 | `app/Models/Tenants/CondolenceExpense.php` |
|
||||
| 3 | Service 생성 | `app/Services/CondolenceExpenseService.php` |
|
||||
| 4 | FormRequest 생성 | `app/Http/Requests/V1/CondolenceExpense/` |
|
||||
| 5 | Controller 생성 | `app/Http/Controllers/Api/V1/CondolenceExpenseController.php` |
|
||||
| 6 | Route 등록 | `routes/api/v1/finance.php` |
|
||||
| 7 | Swagger 작성 | `app/Swagger/v1/CondolenceExpenseApi.php` |
|
||||
|
||||
### Phase 2: React 구현
|
||||
|
||||
| 순서 | 작업 | 파일 |
|
||||
|------|------|------|
|
||||
| 1 | 타입 정의 | `types.ts` |
|
||||
| 2 | Server Actions | `actions.ts` |
|
||||
| 3 | 목록 컴포넌트 (통계 + 필터 + 테이블) | `CondolenceExpenseList.tsx` |
|
||||
| 4 | 등록/수정 모달 | `CondolenceExpenseForm.tsx` |
|
||||
| 5 | 페이지 진입점 | `page.tsx` |
|
||||
| 6 | 메뉴 등록 | DB (tinker) |
|
||||
|
||||
### Phase 3: 연동 테스트
|
||||
|
||||
| 순서 | 작업 |
|
||||
|------|------|
|
||||
| 1 | API Swagger UI 테스트 |
|
||||
| 2 | React ↔ API 연동 확인 |
|
||||
| 3 | 멀티테넌트 데이터 격리 검증 |
|
||||
| 4 | 기존 MNG 데이터 React에서 조회 확인 |
|
||||
|
||||
---
|
||||
|
||||
## 8. MNG 기존 코드 처리
|
||||
|
||||
> **MNG 경조사비 코드는 삭제하지 않는다.**
|
||||
|
||||
| 항목 | 처리 |
|
||||
|------|------|
|
||||
| MNG Controller | 유지 (관리자 전용 조회 가능) |
|
||||
| MNG Model | 유지 |
|
||||
| MNG Blade View | 유지 |
|
||||
| MNG Route | 유지 |
|
||||
|
||||
이관 완료 후 MNG 메뉴에서 경조사비를 숨기고, 서비스(React)로 안내한다.
|
||||
|
||||
---
|
||||
|
||||
## 9. 기존 패턴 참고
|
||||
|
||||
| 참고 기능 | 위치 | 참고 사항 |
|
||||
|----------|------|----------|
|
||||
| BankAccount | `api/app/Services/BankAccountService.php` | CRUD + toggle + setPrimary 패턴 |
|
||||
| ExpenseAccount | `api/app/Models/Tenants/ExpenseAccount.php` | 복리후생비 카테고리 구분 |
|
||||
| Deposit/Withdrawal | `api/app/Models/Tenants/Deposit.php` | 입출금 CRUD 패턴 |
|
||||
| 급여관리 | `docs/features/finance/payroll.md` | 상태 워크플로우, 전표 연동 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 체크리스트
|
||||
|
||||
### API 구현 체크리스트
|
||||
|
||||
- [ ] Model: `BelongsToTenant`, `Auditable`, `SoftDeletes` trait 적용
|
||||
- [ ] Model: `'options' => 'array'` cast + `getOption()`/`setOption()` 헬퍼
|
||||
- [ ] Model: 카테고리/지출방법 상수 정의
|
||||
- [ ] Service: `$this->tenantId()`, `$this->apiUserId()` 사용
|
||||
- [ ] Service: `total_amount` 자동 계산 로직
|
||||
- [ ] Controller: `ApiResponse::handle()` 사용
|
||||
- [ ] FormRequest: 검증 규칙 분리 (Store/Update)
|
||||
- [ ] Route: `finance.php`에 등록
|
||||
- [ ] Swagger: 엔드포인트 문서 작성
|
||||
- [ ] 마이그레이션: `updated_by`, `deleted_by` 컬럼 추가
|
||||
|
||||
### React 구현 체크리스트
|
||||
|
||||
- [ ] `'use client'` 선언
|
||||
- [ ] `buildApiUrl()` 사용 (직접 URL 조립 금지)
|
||||
- [ ] `authenticatedFetch` / Server Actions 사용
|
||||
- [ ] 통계 카드 + 필터 + 테이블 + 합계행
|
||||
- [ ] 등록/수정 모달 (Dialog)
|
||||
- [ ] 금액 포맷팅 (천 단위 구분)
|
||||
- [ ] debounce 검색 (300ms)
|
||||
- [ ] 메뉴 등록 (DB tinker)
|
||||
|
||||
### 인증 체크리스트
|
||||
|
||||
- [ ] API: Bearer 토큰 필수 (화이트리스트 불필요)
|
||||
- [ ] React: `authenticatedFetch` 사용
|
||||
- [ ] 멀티테넌트 데이터 격리 검증
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
|
||||
| 문서 | 경로 |
|
||||
|------|------|
|
||||
| API 개발 규칙 | `dev/standards/api-rules.md` |
|
||||
| options 컬럼 정책 | `standards/options-column-policy.md` |
|
||||
| 이관 현황 | `system/migration-status.md` |
|
||||
| 급여관리 | `features/finance/payroll.md` |
|
||||
| 보안 정책 | `system/security-policy.md` |
|
||||
| 계정별원장 기획 | `dev/dev_plans/account-ledger-income-statement-plan.md` |
|
||||
|
||||
---
|
||||
|
||||
**최종 업데이트**: 2026-03-19
|
||||
Reference in New Issue
Block a user