diff --git a/system/api-structure.md b/system/api-structure.md new file mode 100644 index 0000000..32de616 --- /dev/null +++ b/system/api-structure.md @@ -0,0 +1,208 @@ +# API 서버 구조 현황 + +> **최종 갱신**: 2026-02-27 +> **기술 스택**: Laravel 12 + PHP 8.4 + Sanctum + Spatie Permission + L5-Swagger + +--- + +## 1. 프로젝트 규모 + +| 항목 | 수량 | +|------|------| +| API 엔드포인트 | ~1,027 | +| 컨트롤러 | 131 | +| 모델 | 220 | +| 서비스 | 180 | +| FormRequest | 271 | +| 미들웨어 | 9 | +| Swagger 문서 | 110 | +| 마이그레이션 | 459 | +| 설정 파일 | 22 | + +--- + +## 2. 디렉토리 구조 + +``` +app/ +├── Http/ +│ ├── Controllers/Api/ +│ │ ├── Admin/ 글로벌 메뉴 관리 +│ │ └── V1/ 메인 API (131개) +│ │ ├── Admin/ FCM 관리 +│ │ ├── Audit/ 감사 로그 +│ │ ├── Construction/ 시공 (작업지시, 결과, 설정) +│ │ ├── Design/ 설계 (모델, 버전, BOM 템플릿) +│ │ ├── Documents/ 문서 (템플릿, 생성) +│ │ ├── ESign/ 전자서명 +│ │ ├── ItemMaster/ 품목 마스터 (9개) +│ │ └── [104 Root Controllers] +│ ├── Middleware/ 9개 +│ └── Requests/ 271개 (FormRequest) +├── Models/ 220개 (32개 도메인) +├── Services/ 180개 +├── Swagger/v1/ 110개 (OpenAPI 문서) +├── Helpers/ 4개 +├── Observers/ 5개 +├── Traits/ 모델/감사 트레이트 +└── Exceptions/ 2개 +``` + +--- + +## 3. 라우트 도메인별 엔드포인트 + +| 라우트 파일 | 엔드포인트 | 주요 기능 | +|------------|-----------|----------| +| finance.php | 180 | 재무 (결제, 청구서, 세금계산서, 급여) | +| hr.php | 141 | 인사 (급여, 근태, 휴가, 대출) | +| common.php | 128 | 공통 (코드, 분류, 카테고리, 필드) | +| sales.php | 122 | 영업 (수주, 견적, 거래처, 출하) | +| boards.php | 84 | 게시판 (동적 필드 지원) | +| inventory.php | 79 | 재고 (자재, 입고, 창고) | +| production.php | 67 | 생산 (작업지시, 작업실적, 공정) | +| design.php | 61 | 설계 (모델, 버전, BOM 템플릿) | +| users.php | 34 | 사용자 (프로필, 역할, 초대) | +| admin.php | 29 | 관리자 (테넌트, 메뉴, FCM) | +| tenants.php | 23 | 테넌트 (전환, 프로필) | +| files.php | 20 | 파일 (업로드, 저장, 조회) | +| esign.php | 18 | 전자서명 워크플로우 | +| documents.php | 17 | 문서 (템플릿, 생성) | +| auth.php | 9 | 인증 (로그인, 로그아웃, 등록) | +| audit.php | 7 | 감사 (로그, 이력) | +| stats.php | 5 | 통계/리포트 | +| app.php | 3 | 앱 버전, 상태 체크 | +| **합계** | **~1,027** | | + +``` +routes/ +├── api.php 메인 API 진입점 +└── api/v1/ + ├── admin.php + ├── app.php + ├── audit.php + ├── auth.php + ├── boards.php + ├── common.php + ├── design.php + ├── documents.php + ├── esign.php + ├── files.php + ├── finance.php + ├── hr.php + ├── inventory.php + ├── production.php + ├── sales.php + ├── stats.php + ├── tenants.php + └── users.php +``` + +--- + +## 4. 미들웨어 + +| 미들웨어 | 역할 | +|---------|------| +| ApiKeyMiddleware | API 키 인증 + Sanctum 토큰 검증 | +| ApiRateLimiter | API 속도 제한 | +| ApiVersionMiddleware | API 버전 라우팅 | +| CheckPermission | 권한 기반 접근 제어 | +| CheckSwaggerAuth | Swagger UI 인증 | +| CorsMiddleware | CORS 정책 | +| LogApiRequest | API 요청/응답 로깅 | +| PermMapper | 권한 매핑 변환 | +| SetAuditSessionVariables | 감사 세션 컨텍스트 | + +--- + +## 5. 아키텍처 패턴 + +### 인증 체계 +- **글로벌**: API Key (모든 요청) +- **사용자**: Sanctum Bearer Token (Access 120분, Refresh 7일) +- **내부**: HMAC (`INTERNAL_EXCHANGE_SECRET`, mng ↔ api) + +### 응답 포맷 +```json +{ + "success": true, + "message": "message.key.from.lang", + "data": { ... } +} +``` +- `ApiResponse::handle()` 헬퍼로 통일 + +### 핵심 패턴 +- **Service-First**: 비즈니스 로직 → Service 클래스 +- **FormRequest 필수**: Controller에서 직접 검증 금지 +- **BelongsToTenant**: 모든 비즈니스 모델에 tenant_id 격리 +- **Auditable**: created_by, updated_by, deleted_by 자동 기록 +- **SoftDeletes**: 대부분의 엔티티 논리 삭제 + +### 헬퍼 + +| 헬퍼 | 역할 | +|------|------| +| ApiResponse | JSON 응답 포맷 통일 | +| ItemTypeHelper | 품목 분류 로직 | +| Legacy5130Calculator | 레거시 5130 연동 계산 | +| TenantCodeGenerator | 테넌트별 코드 생성 | + +--- + +## 6. 주요 의존성 + +| 패키지 | 버전 | 용도 | +|--------|------|------| +| laravel/framework | ^12.0 | 코어 프레임워크 | +| laravel/sanctum | ^4.0 | API 토큰 인증 | +| spatie/laravel-permission | ^6.21 | RBAC 권한 관리 | +| darkaonline/l5-swagger | ^9.0 | Swagger/OpenAPI 문서 | +| maatwebsite/excel | ^3.1 | Excel 가져오기/내보내기 | +| google/auth | ^1.49 | Google 인증 | +| doctrine/dbal | ^4.3 | DB 추상화 | + +--- + +## 7. 설정 + +``` +config/ +├── app.php 앱 메타데이터 +├── audit.php 감사 로깅 (13개월 보존) +├── auth.php 인증 (Sanctum, API 키) +├── authz.php 인가 + 권한 +├── cors.php CORS 정책 +├── custom.php 커스텀 앱 설정 +├── database.php DB 연결 (samdb, sam_stat) +├── fcm.php Firebase Cloud Messaging +├── l5-swagger.php Swagger 설정 +├── pagination.php 페이지네이션 기본값 +├── permission.php Spatie Permission +├── products.php 제품별 설정 +├── sanctum.php Sanctum 토큰 설정 +└── [기타 8개] +``` + +--- + +## 8. api ↔ mng ↔ react 관계 + +``` +react (dev.sam.kr) ──Server Actions──→ api (api.sam.kr) ←──DB 공유──→ mng (mng.sam.kr) + │ + MySQL (samdb) +``` + +- **api**: DB 마이그레이션 유일 관리자 (459개). 모든 테이블 정의 +- **mng**: 자체 모델 (185개), 마이그레이션 없음. 동일 DB 직접 접근 +- **react**: Server Actions로 api 호출. DB 직접 접근 없음 +- **내부 통신**: HMAC 기반 `INTERNAL_EXCHANGE_SECRET` (mng → api) +- **파일 공유**: mng가 api의 `storage/app/tenants` 마운트 + +### Swagger 문서 +- 110개 OpenAPI 문서 파일 +- 도메인별 태그 구성 +- 보안 스키마: ApiKeyAuth + BearerAuth (Sanctum) +- URL: `api.sam.kr/api/documentation` \ No newline at end of file diff --git a/system/board-system-spec.md b/system/board-system-spec.md new file mode 100644 index 0000000..1f0cdea --- /dev/null +++ b/system/board-system-spec.md @@ -0,0 +1,523 @@ +# 게시판 시스템 스펙 + +**작성일**: 2025-11-27 +**상태**: 설계 완료, 구현 대기 +**관련 프로젝트**: mng, api + +--- + +## 1. 개요 + +### 1.1 목적 +- mng에서 **시스템 게시판**을 생성하여 모든 테넌트에게 제공 +- sam(api)에서 테넌트별 **자체 게시판** 생성 가능 +- 공지사항, 1:1 문의, FAQ 등 다양한 게시판 유형 지원 + +### 1.2 핵심 개념 + +| 구분 | 설명 | +|------|------| +| **시스템 게시판** | mng에서 생성, `is_system=true`, 모든 테넌트에서 접근 가능 | +| **테넌트 게시판** | sam에서 생성, `is_system=false`, 해당 테넌트만 접근 | +| **board_type** | 자유 입력 (notice, qna, faq, free 등 제한 없음) | + +### 1.3 역할 분리 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ mng (상위 관리자) │ +├─────────────────────────────────────────────────────────────┤ +│ • 시스템 게시판 CRUD (is_system = true) │ +│ • 게시판 필드 정의 (board_settings) │ +│ • 게시판 유형 자유 설정 (board_type) │ +│ • tenant_id = NULL │ +└─────────────────────────────────────────────────────────────┘ + ↓ 전체 테넌트 공개 +┌─────────────────────────────────────────────────────────────┐ +│ sam (api - 테넌트용) │ +├─────────────────────────────────────────────────────────────┤ +│ • 테넌트 게시판 CRUD (is_system = false) │ +│ • 시스템 게시판 사용 (읽기 전용 구조) │ +│ • 게시글 CRUD (posts) │ +│ • tenant_id = 현재 테넌트 │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. 데이터베이스 스키마 + +### 2.1 기존 테이블 현황 + +현재 구현된 테이블 (6개): +- `boards` - 게시판 정의 +- `board_settings` - EAV 커스텀 필드 정의 +- `posts` - 게시글 +- `post_custom_field_values` - EAV 커스텀 필드 값 +- `board_comments` - 댓글 +- `board_files` - 파일 첨부 + +### 2.2 boards 테이블 확장 + +**추가 컬럼:** + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| `is_system` | TINYINT(1) DEFAULT 0 | 시스템 게시판 여부 (1=전체 공개) | +| `board_type` | VARCHAR(50) NULL | 게시판 유형 (자유 입력) | + +**변경 컬럼:** + +| 컬럼 | 변경 내용 | +|------|----------| +| `tenant_id` | NOT NULL → **NULL 허용** (시스템 게시판용) | + +**최종 boards 테이블 구조:** + +```sql +CREATE TABLE boards ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NULL COMMENT '테넌트 ID (NULL=시스템 게시판)', + is_system TINYINT(1) DEFAULT 0 COMMENT '시스템 게시판 여부 (1=전체 테넌트 공개)', + board_type VARCHAR(50) NULL COMMENT '게시판 유형 (notice, qna, faq, free 등)', + board_code VARCHAR(50) NOT NULL COMMENT '게시판 코드 (URL용)', + name VARCHAR(100) NOT NULL COMMENT '게시판명', + description TEXT NULL COMMENT '게시판 설명', + editor_type VARCHAR(20) DEFAULT 'wysiwyg' COMMENT '에디터 타입', + allow_files TINYINT(1) DEFAULT 1 COMMENT '파일 첨부 허용', + max_file_count INT DEFAULT 5 COMMENT '최대 파일 수', + max_file_size INT DEFAULT 20480 COMMENT '최대 파일 크기 (KB)', + extra_settings JSON NULL COMMENT '추가 설정 (권한, 옵션 등)', + is_active TINYINT(1) DEFAULT 1 COMMENT '활성 여부', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + deleted_at TIMESTAMP NULL, + deleted_by BIGINT UNSIGNED NULL, + + INDEX idx_boards_tenant (tenant_id), + INDEX idx_boards_is_system (is_system), + INDEX idx_boards_board_type (board_type), + UNIQUE INDEX uk_boards_code (tenant_id, board_code) +); +``` + +### 2.3 board_settings 테이블 (EAV 필드 정의) + +현재 구조 유지: + +```sql +CREATE TABLE board_settings ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + board_id BIGINT UNSIGNED NOT NULL COMMENT '게시판 ID', + name VARCHAR(100) NOT NULL COMMENT '필드명', + field_key VARCHAR(50) NOT NULL COMMENT '필드 키', + field_type VARCHAR(30) NOT NULL COMMENT '필드 타입 (text, number, select, date 등)', + field_meta JSON NULL COMMENT '필드 메타 (옵션, 유효성 등)', + is_required TINYINT(1) DEFAULT 0 COMMENT '필수 여부', + sort_order INT DEFAULT 0 COMMENT '정렬 순서', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + + INDEX idx_board_settings_board (board_id), + FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE +); +``` + +### 2.4 posts 테이블 + +현재 구조 유지 (SoftDeletes 적용): + +```sql +CREATE TABLE posts ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID', + board_id BIGINT UNSIGNED NOT NULL COMMENT '게시판 ID', + user_id BIGINT UNSIGNED NOT NULL COMMENT '작성자 ID', + title VARCHAR(255) NOT NULL COMMENT '제목', + content LONGTEXT NULL COMMENT '내용', + editor_type VARCHAR(20) DEFAULT 'wysiwyg' COMMENT '에디터 타입', + ip_address VARCHAR(45) NULL COMMENT 'IP 주소', + is_notice TINYINT(1) DEFAULT 0 COMMENT '공지 여부', + is_secret TINYINT(1) DEFAULT 0 COMMENT '비밀글 여부', + views INT DEFAULT 0 COMMENT '조회수', + status VARCHAR(20) DEFAULT 'active' COMMENT '상태', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + deleted_at TIMESTAMP NULL, + deleted_by BIGINT UNSIGNED NULL, + + INDEX idx_posts_tenant_board (tenant_id, board_id), + INDEX idx_posts_status (status), + FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE +); +``` + +### 2.5 post_custom_field_values 테이블 (EAV 값) + +현재 구조 유지: + +```sql +CREATE TABLE post_custom_field_values ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + post_id BIGINT UNSIGNED NOT NULL COMMENT '게시글 ID', + field_id BIGINT UNSIGNED NOT NULL COMMENT '필드 ID (board_settings.id)', + value TEXT NULL COMMENT '필드 값', + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + + INDEX idx_pcfv_post (post_id), + INDEX idx_pcfv_field (field_id), + FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, + FOREIGN KEY (field_id) REFERENCES board_settings(id) ON DELETE CASCADE +); +``` + +--- + +## 3. 게시판 유형 (board_type) + +### 3.1 권장 유형 + +| board_type | 설명 | 특징 | +|------------|------|------| +| `notice` | 공지사항 | 관리자만 작성, 전체 공개 | +| `qna` | 1:1 문의 | 작성자+관리자만 열람, 비밀글 기본 | +| `faq` | FAQ | 관리자 작성, 카테고리 분류 | +| `free` | 자유게시판 | 댓글 허용, 전체 공개 | +| `gallery` | 갤러리 | 이미지 중심 | +| `download` | 자료실 | 파일 첨부 중심 | + +### 3.2 유형별 extra_settings 예시 + +```json +// notice (공지사항) +{ + "write_roles": ["admin", "manager"], + "allow_comment": false, + "allow_secret": false +} + +// qna (1:1 문의) +{ + "write_roles": ["*"], + "allow_comment": true, + "default_secret": true, + "only_author_view": true +} + +// faq +{ + "write_roles": ["admin"], + "use_category": true, + "allow_comment": false +} + +// free (자유게시판) +{ + "write_roles": ["*"], + "allow_comment": true, + "allow_secret": true +} +``` + +--- + +## 4. API 설계 + +### 4.1 mng API (시스템 게시판 관리) + +``` +# 시스템 게시판 CRUD +GET /mng/boards # 시스템 게시판 목록 +POST /mng/boards # 시스템 게시판 생성 +GET /mng/boards/{id} # 시스템 게시판 상세 +PUT /mng/boards/{id} # 시스템 게시판 수정 +DELETE /mng/boards/{id} # 시스템 게시판 삭제 + +# 게시판 필드 관리 +GET /mng/boards/{id}/fields # 필드 목록 +POST /mng/boards/{id}/fields # 필드 추가 +PUT /mng/boards/{id}/fields/{fid} # 필드 수정 +DELETE /mng/boards/{id}/fields/{fid} # 필드 삭제 +POST /mng/boards/{id}/fields/reorder # 필드 순서 변경 +``` + +### 4.2 sam API (테넌트용) + +``` +# 게시판 조회 (시스템 + 테넌트) +GET /v1/boards # 접근 가능한 게시판 목록 +GET /v1/boards/{code} # 게시판 상세 + +# 테넌트 게시판 관리 +POST /v1/boards # 테넌트 게시판 생성 +PUT /v1/boards/{code} # 테넌트 게시판 수정 +DELETE /v1/boards/{code} # 테넌트 게시판 삭제 + +# 게시글 CRUD +GET /v1/boards/{code}/posts # 게시글 목록 +POST /v1/boards/{code}/posts # 게시글 작성 +GET /v1/boards/{code}/posts/{id} # 게시글 상세 +PUT /v1/boards/{code}/posts/{id} # 게시글 수정 +DELETE /v1/boards/{code}/posts/{id} # 게시글 삭제 + +# 댓글 +GET /v1/posts/{id}/comments # 댓글 목록 +POST /v1/posts/{id}/comments # 댓글 작성 +PUT /v1/comments/{id} # 댓글 수정 +DELETE /v1/comments/{id} # 댓글 삭제 +``` + +--- + +## 5. 모델 설계 + +### 5.1 Board 모델 + +```php +// api/app/Models/Boards/Board.php + +namespace App\Models\Boards; + +use App\Traits\BelongsToTenant; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; + +class Board extends Model +{ + use SoftDeletes; + + protected $fillable = [ + 'tenant_id', 'is_system', 'board_type', 'board_code', 'name', + 'description', 'editor_type', 'allow_files', 'max_file_count', + 'max_file_size', 'extra_settings', 'is_active', + 'created_by', 'updated_by', 'deleted_by', + ]; + + protected $casts = [ + 'is_system' => 'boolean', + 'is_active' => 'boolean', + 'allow_files' => 'boolean', + 'extra_settings' => 'array', + ]; + + /** + * 현재 테넌트에서 접근 가능한 게시판 + * - 시스템 게시판 (is_system = true) + * - 해당 테넌트 게시판 (tenant_id = 현재 테넌트) + */ + public function scopeAccessible($query, int $tenantId) + { + return $query->where(function ($q) use ($tenantId) { + $q->where('is_system', true) + ->orWhere('tenant_id', $tenantId); + })->where('is_active', true); + } + + /** + * 시스템 게시판만 (mng용) + */ + public function scopeSystemOnly($query) + { + return $query->where('is_system', true); + } + + /** + * 테넌트 게시판만 + */ + public function scopeTenantOnly($query, int $tenantId) + { + return $query->where('is_system', false) + ->where('tenant_id', $tenantId); + } + + // 관계 + public function fields() + { + return $this->hasMany(BoardSetting::class, 'board_id') + ->orderBy('sort_order'); + } + + public function posts() + { + return $this->hasMany(Post::class, 'board_id'); + } + + // Helper + public function getSetting(string $key, $default = null) + { + return data_get($this->extra_settings, $key, $default); + } +} +``` + +### 5.2 BoardService + +```php +// api/app/Services/Boards/BoardService.php + +namespace App\Services\Boards; + +use App\Models\Boards\Board; +use App\Services\Service; + +class BoardService extends Service +{ + /** + * 접근 가능한 게시판 목록 (시스템 + 테넌트) + */ + public function getAccessibleBoards(array $filters = []) + { + return Board::accessible($this->tenantId()) + ->when(isset($filters['board_type']), fn($q) => + $q->where('board_type', $filters['board_type'])) + ->orderBy('is_system', 'desc') + ->orderBy('name') + ->get(); + } + + /** + * 시스템 게시판 목록 (mng용) + */ + public function getSystemBoards() + { + return Board::systemOnly() + ->orderBy('name') + ->get(); + } + + /** + * 시스템 게시판 생성 (mng용) + */ + public function createSystemBoard(array $data): Board + { + $data['is_system'] = true; + $data['tenant_id'] = null; + $data['created_by'] = $this->apiUserId(); + + return Board::create($data); + } + + /** + * 테넌트 게시판 생성 (sam용) + */ + public function createTenantBoard(array $data): Board + { + $data['is_system'] = false; + $data['tenant_id'] = $this->tenantId(); + $data['created_by'] = $this->apiUserId(); + + return Board::create($data); + } + + /** + * 게시판 코드로 조회 + */ + public function getBoardByCode(string $code): ?Board + { + return Board::accessible($this->tenantId()) + ->where('board_code', $code) + ->first(); + } +} +``` + +--- + +## 6. 권한 모델 + +### 6.1 extra_settings 기반 권한 + +게시판별 권한은 `extra_settings` JSON 필드로 관리: + +```json +{ + "permissions": { + "read": ["*"], // 모든 역할 읽기 가능 + "write": ["admin", "user"], // admin, user 역할만 작성 + "manage": ["admin"] // admin만 관리 + } +} +``` + +### 6.2 권한 검증 + +```php +// Board 모델에 추가 +public function canRead(User $user): bool +{ + $roles = $this->getSetting('permissions.read', ['*']); + return in_array('*', $roles) || + $user->hasAnyRole($roles); +} + +public function canWrite(User $user): bool +{ + $roles = $this->getSetting('permissions.write', ['*']); + return in_array('*', $roles) || + $user->hasAnyRole($roles); +} + +public function canManage(User $user): bool +{ + $roles = $this->getSetting('permissions.manage', ['admin']); + return $user->hasAnyRole($roles); +} +``` + +--- + +## 7. 구현 계획 + +### 7.1 Phase 1: DB 마이그레이션 (api/) + +1. `boards` 테이블 확장 + - `tenant_id` nullable 변경 + - `is_system` 컬럼 추가 + - `board_type` 컬럼 추가 + - `deleted_at`, `deleted_by` 추가 (없으면) + - 인덱스 추가 + +### 7.2 Phase 2: 모델/서비스 수정 (api/) + +1. `Board` 모델 업데이트 + - 스코프 추가 (accessible, systemOnly, tenantOnly) + - SoftDeletes 적용 + - 권한 헬퍼 메서드 + +2. `BoardService` 구현 + - 시스템/테넌트 게시판 분리 로직 + +### 7.3 Phase 3: mng 화면 개발 + +1. 게시판 목록 (`/mng/boards`) +2. 게시판 생성/수정 폼 +3. 게시판 필드 관리 + +### 7.4 Phase 4: sam API 개발 + +1. 게시판 API (`/v1/boards`) +2. 게시글 API (`/v1/boards/{code}/posts`) +3. Swagger 문서 + +--- + +## 8. 관련 문서 + +- [데이터베이스 스키마](./database/README.md) +- [API 개발 규칙](../standards/api-rules.md) +- [MNG Critical Rules](../../mng/docs/MNG_CRITICAL_RULES.md) + +--- + +**최종 업데이트**: 2025-11-27 +**버전**: 1.0 +**상태**: 설계 완료 diff --git a/system/database/README.md b/system/database/README.md new file mode 100644 index 0000000..b641e65 --- /dev/null +++ b/system/database/README.md @@ -0,0 +1,193 @@ +# 데이터베이스 스키마 현황 + +> **최종 갱신**: 2026-02-27 +> **DB**: MySQL 8.0 (samdb + sam_stat) +> **마이그레이션**: 459개 (api/에서만 관리) + +--- + +## 1. 규모 요약 + +| 항목 | 수량 | +|------|------| +| Eloquent 모델 | 220 | +| 도메인 그룹 | 32 | +| 마이그레이션 | 459 (메인 437 + 통계 22) | +| DB 연결 | 2 (samdb, sam_stat) | + +--- + +## 2. 도메인별 모델 분포 + +| 도메인 | 모델 수 | 주요 엔티티 | 상세 | +|--------|---------|------------|------| +| Tenants | 56 | Tenant, Department, Approval, Payment, Stock 등 | [tenants.md](tenants.md) | +| Stats | 21 | StatFinanceDaily, DimClient, DimDate 등 | [stats.md](stats.md) | +| Documents | 15 | Document, DocumentTemplate, DocumentApproval 등 | [documents.md](documents.md) | +| Commons | 10 | Category, File, Menu, Tag, Classification | [commons.md](commons.md) | +| Quote | 8 | Quote, QuoteItem, QuoteFormula, QuoteRevision | [sales.md](sales.md) | +| Production | 8 | WorkOrder, WorkOrderItem, WorkResult 등 | [production.md](production.md) | +| Orders | 8 | Order, OrderItem, OrderNode, Client 등 | [sales.md](sales.md) | +| ItemMaster | 8 | ItemField, ItemPage, ItemBomItem, CustomTab 등 | [products.md](products.md) | +| Products | 6 | Product, ProductComponent, Part, Price | [products.md](products.md) | +| Interview | 5 | InterviewTemplate, InterviewSession 등 | [hr.md](hr.md) | +| Construction | 5 | Contract, HandoverReport, StructureReview | [production.md](production.md) | +| Boards | 5 | Board, Post, BoardSetting, PostCustomFieldValue | [commons.md](commons.md) | +| Members | 4 | User, UserTenant, UserRole, UserMenuPermission | [tenants.md](tenants.md) | +| Materials | 4 | Material, MaterialReceipt, MaterialInspection | [production.md](production.md) | +| ESign | 4 | EsignContract, EsignSigner, EsignSignField | [documents.md](documents.md) | +| Design | 4 | DesignModel, ModelVersion, BomTemplate | [products.md](products.md) | +| Qualitys | 3 | Inspection, Lot, LotSale | [production.md](production.md) | +| Permissions | 3 | Permission, Role, PermissionOverride | [tenants.md](tenants.md) | +| Items | 3 | Item, ItemDetail, ItemReceipt | [products.md](products.md) | +| BadDebts | 3 | BadDebt, BadDebtDocument, BadDebtMemo | [finance.md](finance.md) | +| Estimate | 2 | Estimate, EstimateItem | [sales.md](sales.md) | +| Audit | 2 | AuditLog, TriggerAuditLog | [commons.md](commons.md) | +| Root Level | 27 | ApiKey, Process, NumberingSequence 등 | 각 도메인 문서 참조 | + +--- + +## 3. 핵심 엔티티 관계도 + +### 인증 + 멀티테넌시 + +``` +User + ├─ hasMany UserTenant (pivot: is_active, is_default) + │ └─ belongsTo Tenant + ├─ hasMany UserRole + └─ hasMany UserMenuPermission + +Tenant + ├─ hasMany Department (계층 구조, parent_id) + │ └─ belongsToMany User (department_user pivot) + ├─ hasMany TenantUserProfile (테넌트별 직원 프로필) + └─ hasMany [모든 tenant-scoped 모델] +``` + +### 제품 + 설계 + +``` +Product + ├─ belongsTo Category (계층 분류) + ├─ hasMany ProductComponent (BOM) + ├─ hasMany Part, Price + └─ morphMany File + +DesignModel + └─ hasMany ModelVersion + └─ hasMany BomTemplate + └─ hasMany BomTemplateItem +``` + +### 견적 → 수주 → 생산 흐름 + +``` +Quote (견적) + ├─ belongsTo Client + ├─ hasMany QuoteItem + └─ → Order 변환 + +Order (수주) + ├─ belongsTo Quote, Client + ├─ hasMany OrderItem (options JSON) + ├─ hasMany OrderNode (설계 분해) + └─ hasMany WorkOrder + +WorkOrder (작업지시) + ├─ belongsTo Order, Process + ├─ hasMany WorkOrderItem (options JSON) + ├─ hasMany WorkOrderStepProgress + └─ hasMany WorkResult (작업실적) +``` + +### 문서 + 전자결재 + +``` +Document + ├─ belongsTo DocumentTemplate + ├─ morphTo linkable (다형 - Order, Quote 등) + ├─ hasMany DocumentApproval (결재 단계) + └─ hasMany DocumentData (동적 폼) + +DocumentTemplate + ├─ hasMany Section → Field → Item + └─ hasMany ApprovalLine (결재선) +``` + +--- + +## 4. 공통 패턴 + +### 트레이트 사용 현황 + +| 트레이트 | 적용 모델 수 | 역할 | +|---------|-------------|------| +| BelongsToTenant | ~160 (73%) | tenant_id 자동 스코핑 | +| Auditable | ~150 (68%) | created_by, updated_by, deleted_by | +| SoftDeletes | ~150 (68%) | 논리 삭제 (deleted_at) | +| ModelTrait | ~80 (36%) | 날짜 처리, is_active 스코프 | +| HasRoles (Spatie) | 3 | RBAC 권한 관리 | +| HasApiTokens (Sanctum) | 1 (User) | API 토큰 관리 | + +### 표준 컬럼 구조 + +모든 비즈니스 테이블의 공통 컬럼: +``` +id PK +tenant_id FK (멀티테넌시) +created_by FK → users (감사) +updated_by FK → users (감사) +deleted_by FK → users (감사) +created_at timestamp +updated_at timestamp +deleted_at timestamp (논리삭제) +is_active boolean +sort_order integer +options JSON (유연한 속성 저장) +``` + +### DB 설계 패턴 + +| 패턴 | 사용 예시 | +|------|----------| +| 계층 구조 (Self-Reference) | Category, Department (parent_id) | +| 다형 관계 (Polymorphic) | File, PermissionOverride (morphable_type/id) | +| EAV (Entity-Attribute-Value) | PostCustomFieldValue, CategoryField | +| JSON 컬럼 | Product.bom, OrderItem.options, WorkOrderItem.options | +| Pivot 테이블 | user_tenants, department_user | +| BOM/Tree | ProductComponent, BomTemplateItem | +| 버전 관리 | ModelVersion, QuoteRevision, OrderVersion | +| 상태 코드 | Order.status (DRAFT/CONFIRMED/IN_PRODUCTION) | + +### JSON options 컬럼 정책 + +> **FK/조인키만** 테이블 컬럼으로 추가. +> **나머지 속성은** `options` 또는 `attributes` JSON에 저장. +> 이유: 멀티테넌시 환경에서 테넌트별 스키마 변경 없이 유연한 관리. + +--- + +## 5. DB 연결 + +| 연결명 | DB | 용도 | +|--------|-----|------| +| mysql (기본) | samdb | 모든 비즈니스 데이터 | +| sam_stat | sam_stat | 통계/집계 전용 (21 모델) | +| chandj | chandj | 레거시 5130 (마이그레이션 대상) | + +--- + +## 6. 도메인별 상세 문서 + +| 문서 | 포함 도메인 | +|------|-----------| +| [tenants.md](tenants.md) | Tenants, Members, Permissions | +| [products.md](products.md) | Products, ItemMaster, Items, Design | +| [sales.md](sales.md) | Orders, Quote, Estimate | +| [production.md](production.md) | Production, Construction, Materials, Qualitys | +| [finance.md](finance.md) | Finance (Tenants 하위), BadDebts | +| [hr.md](hr.md) | HR (Tenants 하위), Interview | +| [documents.md](documents.md) | Documents, ESign | +| [commons.md](commons.md) | Commons, Boards, Audit | +| [stats.md](stats.md) | Stats (sam_stat DB) | \ No newline at end of file diff --git a/system/database/commons.md b/system/database/commons.md new file mode 100644 index 0000000..2b84c6b --- /dev/null +++ b/system/database/commons.md @@ -0,0 +1,85 @@ +# 공통 / 게시판 / 감사 도메인 + +> **모델 수**: Commons 10 + Boards 5 + Audit 2 = 17 +> **핵심**: 범용 분류, 파일 관리, 게시판 시스템, 감사 로그 + +--- + +## 주요 테이블 + +### 공통 (Commons) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| categories | Category | 범용 계층 분류 (parent_id, self-reference) | +| category_fields | CategoryField | 카테고리 동적 필드 (EAV) | +| category_templates | CategoryTemplate | 카테고리 필드 스냅샷 (버전) | +| category_logs | CategoryLog | 카테고리 변경 로그 | +| classifications | Classification | 분류 체계 | +| files | File | 파일 첨부 (다형: morphMany) | +| menus | Menu | 메뉴 체계 | +| tags | Tag | 태그 시스템 | +| holidays | Holiday | 공휴일 | +| common_codes | CommonCode | 공통 코드 | + +### 게시판 (Boards) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| boards | Board | 게시판 정의 | +| posts | Post | 게시글 | +| board_settings | BoardSetting | 게시판 동적 필드 정의 | +| post_custom_field_values | PostCustomFieldValue | 게시글 커스텀 필드 값 (EAV) | +| board_comments | BoardComment | 댓글 | + +### 감사 (Audit) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| audit_logs | AuditLog | 변경 감사 로그 (불변) | +| trigger_audit_logs | TriggerAuditLog | DB 트리거 감사 로그 | + +--- + +## 관계 구조 + +``` +Category (계층 분류) + ├─ belongsTo Category (parent_id → self) + ├─ hasMany Category (children) + ├─ hasMany CategoryField (EAV 동적 필드) + ├─ hasMany CategoryTemplate (필드 버전 스냅샷) + ├─ hasMany Product + └─ belongsToMany File via tags + +Board (게시판) + ├─ hasMany Post + │ ├─ hasMany PostCustomFieldValue (EAV) + │ └─ hasMany BoardComment + └─ hasMany BoardSetting (동적 필드 정의) + +File (범용 첨부) + └─ morphTo fileable (어떤 모델에든 첨부 가능) +``` + +--- + +## EAV 패턴 + +게시판과 카테고리 모두 **EAV(Entity-Attribute-Value)** 패턴 사용: + +``` +Board → BoardSetting (필드 정의: field_name, field_type) +Post → PostCustomFieldValue (필드 값: board_setting_id, value) + +Category → CategoryField (필드 정의: field_name, field_type) +``` + +--- + +## 특이사항 + +- `File`은 다형(morphMany) 관계 — 모든 모델에서 파일 첨부 가능 +- `AuditLog`는 불변 (timestamps 없음, SoftDeletes 없음) +- 감사 로그 보존 정책: 13개월 +- 게시판 시스템: EAV 패턴으로 동적 필드 지원 (노션 스타일 전환 계획 중) \ No newline at end of file diff --git a/system/database/documents.md b/system/database/documents.md new file mode 100644 index 0000000..3bc037e --- /dev/null +++ b/system/database/documents.md @@ -0,0 +1,68 @@ +# 문서 / 전자서명 도메인 + +> **모델 수**: Documents 15 + ESign 4 = 19 +> **핵심**: 문서 템플릿 기반 생성, 전자결재, 전자서명 + +--- + +## 주요 테이블 + +### 문서 (Documents) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| documents | Document | 문서 마스터 (다형 linkable) | +| document_templates | DocumentTemplate | 문서 템플릿 정의 | +| document_template_sections | DocumentTemplateSection | 템플릿 섹션 | +| document_template_section_fields | DocumentTemplateSectionField | 섹션 필드 | +| document_template_section_items | DocumentTemplateSectionItem | 체크리스트 항목 | +| document_template_field_presets | DocumentTemplateFieldPreset | 필드 프리셋 | +| document_template_approval_lines | DocumentTemplateApprovalLine | 결재선 정의 | +| document_approvals | DocumentApproval | 문서 결재 기록 | +| document_attachments | DocumentAttachment | 문서 첨부 | +| document_data | DocumentData | 문서 동적 데이터 | +| document_links | DocumentLink | 문서 링크 | + +### 전자서명 (ESign) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| esign_contracts | EsignContract | 전자서명 계약 | +| esign_signers | EsignSigner | 서명자 | +| esign_sign_fields | EsignSignField | 서명 필드 | +| esign_audit_logs | EsignAuditLog | 전자서명 감사 로그 | + +--- + +## 관계 구조 + +``` +DocumentTemplate + ├─ hasMany DocumentTemplateSection + │ └─ hasMany DocumentTemplateSectionField + │ ├─ hasMany DocumentTemplateSectionItem (체크리스트) + │ └─ hasMany DocumentTemplateFieldPreset (프리셋) + └─ hasMany DocumentTemplateApprovalLine (결재선) + +Document + ├─ belongsTo DocumentTemplate + ├─ morphTo linkable (Order, Quote 등에 연결) + ├─ hasMany DocumentApproval + ├─ hasMany DocumentAttachment + ├─ hasMany DocumentData + └─ hasMany DocumentLink + +EsignContract + ├─ hasMany EsignSigner + ├─ hasMany EsignSignField + └─ hasMany EsignAuditLog +``` + +--- + +## 특이사항 + +- 문서 시스템은 템플릿 기반 (Section → Field → Item 3단계) +- `Document.linkable`은 다형 관계 (Order, Quote 등에 첨부 가능) +- 전자서명은 별도 감사 로그 보유 (EsignAuditLog) +- 문서 15개 모델 중 7개가 템플릿 구조 관련 \ No newline at end of file diff --git a/system/database/finance.md b/system/database/finance.md new file mode 100644 index 0000000..8496518 --- /dev/null +++ b/system/database/finance.md @@ -0,0 +1,57 @@ +ㅇ# 재무 / 회계 도메인 + +> **모델 수**: Finance 관련 (Tenants 하위) + BadDebts 3 +> **핵심**: 매입/매출, 결제, 세금계산서, 대출, 경비 +> **API 엔드포인트**: 180개 (finance.php — 최대 규모) + +--- + +## 주요 테이블 + +### 결제 / 청구 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| payments | Payment | 결제 마스터 | +| bills | Bill | 청구서 | +| deposits | Deposit | 입금 | +| withdrawals | Withdrawal | 출금 | +| receivables | Receivables | 매출채권 | +| vendor_ledgers | VendorLedger | 거래처 원장 | + +### 세금 / 카드 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| tax_invoices | TaxInvoice | 세금계산서 | +| vat_* | Vat 관련 | 부가세 관리 | +| cards | Card | 법인카드 | +| card_transactions | CardTransaction | 카드 거래 | +| bank_accounts | BankAccount | 은행 계좌 | +| bank_transactions | BankTransaction | 은행 거래 | + +### 대손 (BadDebts) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| bad_debts | BadDebt | 대손 마스터 | +| bad_debt_documents | BadDebtDocument | 대손 관련 문서 | +| bad_debt_memos | BadDebtMemo | 대손 메모 | + +### 기타 재무 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| expected_expenses | ExpectedExpense | 예상 경비 | +| entertainments | Entertainment | 접대비 | +| purchases | Purchase | 매입 | +| subscriptions | Subscription | 구독/정기결제 | + +--- + +## 특이사항 + +- 재무 모델은 대부분 `Tenants/` 디렉토리 하위에 위치 +- finance.php 라우트가 180개로 전체 API 중 최대 규모 +- 바로빌 연동은 mng에서 관리 (api에는 해당 모델 없음) +- 모든 재무 모델은 BelongsToTenant + Auditable + SoftDeletes \ No newline at end of file diff --git a/system/database/hr.md b/system/database/hr.md new file mode 100644 index 0000000..26851c0 --- /dev/null +++ b/system/database/hr.md @@ -0,0 +1,68 @@ +# 인사 / HR 도메인 + +> **모델 수**: HR 관련 (Tenants 하위) + Interview 5 +> **핵심**: 급여, 근태, 휴가, 대출, 면접 +> **API 엔드포인트**: 141개 (hr.php) + +--- + +## 주요 테이블 + +### 급여 / 근무 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| payrolls | Payroll | 급여 마스터 | +| salaries | Salary | 급여 항목 | +| attendances | Attendance | 근태 기록 | +| attendance_requests | AttendanceRequest | 근태 요청 | +| leaves | Leave | 휴가 사용 기록 | +| leave_policies | LeavePolicy | 휴가 정책 | +| labors | Labor | 노무비 | + +### 대출 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| loans | Loan | 직원 대출 | + +### 면접 (Interview) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| interview_templates | InterviewTemplate | 면접 양식 | +| interview_sessions | InterviewSession | 면접 세션 | +| interview_questions | InterviewQuestion | 면접 질문 | +| interview_categories | InterviewCategory | 면접 카테고리 | +| interview_responses | InterviewResponse | 면접 답변 | + +--- + +## 관계 구조 + +``` +TenantUserProfile (직원) + ├─ hasMany Payroll + ├─ hasMany Attendance + ├─ hasMany Leave + ├─ hasMany Loan + └─ hasMany AttendanceRequest + +LeavePolicy + └─ belongsTo Tenant (테넌트별 휴가 정책) + +InterviewTemplate + ├─ hasMany InterviewCategory + │ └─ hasMany InterviewQuestion + └─ hasMany InterviewSession + └─ hasMany InterviewResponse +``` + +--- + +## 특이사항 + +- HR 모델은 대부분 `Tenants/` 디렉토리 하위 +- 직원 정보는 `TenantUserProfile` (테넌트별 프로필) +- 면접 모델은 별도 `Interview/` 도메인으로 분리 +- 급여 관련 최근 추가: long_term_care 컬럼 (2026-02-27) \ No newline at end of file diff --git a/system/database/production.md b/system/database/production.md new file mode 100644 index 0000000..7c3a676 --- /dev/null +++ b/system/database/production.md @@ -0,0 +1,112 @@ +# 생산 / 시공 / 자재 / 품질 도메인 + +> **모델 수**: Production 8 + Construction 5 + Materials 4 + Qualitys 3 = 20 +> **핵심**: 작업지시, 공정 관리, 자재/LOT 추적, 품질 검사 + +--- + +## 주요 테이블 + +### 생산 (Production) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| work_orders | WorkOrder | 작업지시 마스터 | +| work_order_items | WorkOrderItem | 작업지시 항목 (options JSON) | +| work_order_step_progress | WorkOrderStepProgress | 단계별 진행 추적 | +| work_order_bending_details | WorkOrderBendingDetail | 절곡 상세 사양 | +| work_order_assignees | WorkOrderAssignee | 작업자 배정 | +| work_order_issues | WorkOrderIssue | 작업 이슈 기록 | +| work_results | WorkResult | 작업실적 | +| work_order_material_inputs | WorkOrderMaterialInput | 자재 투입 기록 | + +### 시공 (Construction) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| contracts | Contract | 시공 계약 | +| handover_reports | HandoverReport | 인수인계 보고서 | +| handover_report_managers | HandoverReportManager | 인수인계 담당자 | +| structure_reviews | StructureReview | 구조 검토 | + +### 자재 (Materials) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| materials | Material | 자재 마스터 | +| material_receipts | MaterialReceipt | 자재 입고 | +| material_inspections | MaterialInspection | 수입검사 마스터 | +| material_inspection_items | MaterialInspectionItem | 수입검사 항목 | + +### 품질 (Qualitys) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| inspections | Inspection | 검사 마스터 | +| lots | Lot | LOT 관리 | +| lot_sales | LotSale | LOT 출고 | + +--- + +## 관계 구조 + +``` +WorkOrder (작업지시) + ├─ belongsTo Order + ├─ belongsTo Process (공정) + ├─ belongsTo Department (담당 팀) + ├─ hasMany WorkOrderItem + │ ├─ options: JSON { floor, code, width, height, slat_info, bending_info } + │ └─ hasMany WorkOrderMaterialInput + ├─ hasMany WorkOrderStepProgress + ├─ hasMany WorkOrderBendingDetail + ├─ hasMany WorkOrderAssignee + ├─ hasMany WorkOrderIssue + └─ hasMany WorkResult + +Material + ├─ belongsTo Category + ├─ hasMany MaterialReceipt + ├─ hasMany Lot + └─ morphMany File + +Inspection + ├─ belongsTo WorkOrder (또는 MaterialReceipt) + └─ hasMany InspectionItem +``` + +--- + +## WorkOrderItem options JSON 구조 + +```json +{ + "floor": "1F", + "code": "SL-001", + "width": 1200, + "height": 800, + "cutting_info": { ... }, + "slat_info": { "joint_bar": 2, "glass_qty": 10 }, + "bending_info": { ... }, + "wip_info": { ... } +} +``` + +- OrderItem.options에서 복사됨 (width 직접 접근 가능) +- 조인트바 자동계산: `createWorkOrders()` 에서 처리 + +--- + +## LOT 관리 흐름 + +``` +Material → MaterialReceipt (입고) + │ + MaterialInspection (수입검사) + │ + Lot (LOT 생성) + │ + WorkOrderMaterialInput (투입) + │ + LotSale (출고) +``` \ No newline at end of file diff --git a/system/database/products.md b/system/database/products.md new file mode 100644 index 0000000..304a9e1 --- /dev/null +++ b/system/database/products.md @@ -0,0 +1,88 @@ +# 제품 / 품목 / 설계 도메인 + +> **모델 수**: Products 6 + ItemMaster 8 + Items 3 + Design 4 = 21 +> **핵심**: 제품 정의, BOM 구조, 품목 마스터, 설계 모델 + +--- + +## 주요 테이블 + +### 제품 (Products) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| products | Product | 제품 마스터 (code, name, product_type) | +| product_components | ProductComponent | BOM 구성 (parent-child 관계) | +| parts | Part | 부품 정의 | +| prices | Price | 가격 정보 | +| common_codes | CommonCode | 공통 코드 | + +### 품목 마스터 (ItemMaster) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| item_fields | ItemField | 품목 필드 정의 | +| item_pages | ItemPage | 품목 페이지 구성 | +| item_bom_items | ItemBomItem | 품목 BOM 항목 | +| custom_tabs | CustomTab | 커스텀 탭 | +| unit_options | UnitOption | 단위 옵션 | + +### 품목 (Items) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| items | Item | 품목 마스터 | +| item_details | ItemDetail | 품목 상세 | +| item_receipts | ItemReceipt | 품목 입고 | + +### 설계 (Design) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| design_models | DesignModel | 설계 모델 마스터 | +| model_versions | ModelVersion | 모델 버전 | +| bom_templates | BomTemplate | BOM 템플릿 | +| bom_template_items | BomTemplateItem | BOM 템플릿 항목 (수량, 로스율) | + +--- + +## 관계 구조 + +``` +Product + ├─ belongsTo Category (계층 분류) + ├─ hasMany ProductComponent (BOM) + │ └─ child_product_id → Product (자기 참조) + ├─ hasMany Part + ├─ hasMany Price + └─ morphMany File + +Item + ├─ hasMany ItemDetail + ├─ hasMany ItemReceipt + └─ options JSON: { lot_managed, consumption_method, production_source, input_tracking } + +DesignModel → ModelVersion → BomTemplate → BomTemplateItem +``` + +--- + +## 품목 options 체계 + +items.options JSON으로 품목별 관리 방식 정의: + +| 속성 | 타입 | 설명 | +|------|------|------| +| lot_managed | bool | LOT 추적 여부 | +| consumption_method | auto/manual/none | 소진 방식 | +| production_source | purchased/self_produced/both | 조달 구분 | +| input_tracking | bool | 원자재 투입 추적 여부 | + +### 유형별 조합 + +| 유형 | 예시 | lot | consumption | source | +|------|------|-----|------------|--------| +| 구매 소모품 (LOT) | 내화실 | true | manual | purchased | +| 구매 소모품 (비LOT) | 장갑, 테이프 | false | manual | purchased | +| 일반 자체생산 | 슬랫, 절곡물 | true | auto | self_produced | +| 잔재 활용 생산 | 조인트바 | true | auto | self_produced | \ No newline at end of file diff --git a/system/database/sales.md b/system/database/sales.md new file mode 100644 index 0000000..2403106 --- /dev/null +++ b/system/database/sales.md @@ -0,0 +1,98 @@ +# 영업 / 수주 / 견적 도메인 + +> **모델 수**: Orders 8 + Quote 8 + Estimate 2 = 18 +> **핵심**: 견적 → 수주 → 생산 변환 흐름 + +--- + +## 주요 테이블 + +### 수주 (Orders) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| orders | Order | 수주 마스터 (status: DRAFT→CONFIRMED→IN_PRODUCTION) | +| order_items | OrderItem | 수주 항목 (options JSON 포함) | +| order_nodes | OrderNode | 설계 분해 구조 | +| order_item_components | OrderItemComponent | 수주 항목 구성요소 | +| order_histories | OrderHistory | 수주 변경 이력 | +| clients | Client | 거래처 마스터 | +| client_groups | ClientGroup | 거래처 그룹 | +| site_briefings | SiteBriefing | 현장 브리핑 | + +### 견적 (Quote) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| quotes | Quote | 견적 마스터 | +| quote_items | QuoteItem | 견적 항목 | +| quote_formulas | QuoteFormula | 견적 공식 | +| quote_formula_categories | QuoteFormulaCategory | 공식 카테고리 | +| quote_revisions | QuoteRevision | 견적 버전 이력 | + +### 견적서 (Estimate) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| estimates | Estimate | 견적서 마스터 | +| estimate_items | EstimateItem | 견적서 항목 | + +--- + +## 관계 구조 + +``` +Quote (견적) + ├─ belongsTo Client + ├─ belongsTo SiteBriefing + ├─ belongsTo Item + ├─ hasMany QuoteItem + ├─ hasMany QuoteRevision + └─ → Order 변환 (OrderService) + +Order (수주) + ├─ belongsTo Quote + ├─ belongsTo Client + ├─ hasMany OrderItem + │ ├─ belongsTo Item + │ ├─ hasMany OrderItemComponent + │ └─ options: JSON { floor, code, width, height, cutting_info, slat_info, bending_info } + ├─ hasMany OrderNode + ├─ hasMany OrderHistory + └─ hasMany WorkOrder (생산으로 변환) +``` + +--- + +## 비즈니스 흐름 + +``` +견적(Quote) → 수주(Order) → 작업지시(WorkOrder) → 작업실적(WorkResult) + │ │ │ + QuoteItem OrderItem WorkOrderItem +``` + +### 상태 흐름 (Order) +``` +DRAFT → CONFIRMED → IN_PRODUCTION → COMPLETED → SHIPPED +``` + +--- + +## OrderItem options JSON 구조 + +```json +{ + "floor": "1F", + "code": "SL-001", + "width": 1200, + "height": 800, + "cutting_info": { ... }, + "slat_info": { "joint_bar": 2, "glass_qty": 10 }, + "bending_info": { ... }, + "wip_info": { ... } +} +``` + +- 견적 → 수주 변환 시 `extractSlatInfoFromBom()`으로 slat_info 자동 계산 +- 조인트바 수량 공식: `(2 + floor((제작가로 - 500) / 1000)) × 셔터수량` \ No newline at end of file diff --git a/system/database/stats.md b/system/database/stats.md new file mode 100644 index 0000000..5fb3c72 --- /dev/null +++ b/system/database/stats.md @@ -0,0 +1,68 @@ +# 통계 도메인 + +> **모델 수**: 21 +> **DB 연결**: sam_stat (별도 데이터베이스) +> **핵심**: 일별/월별 집계, 차원 테이블, 통계 서비스 15개 + +--- + +## 주요 테이블 + +### 일별 집계 (Daily) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| stat_finance_daily | StatFinanceDaily | 일별 재무 통계 | +| stat_production_daily | StatProductionDaily | 일별 생산 통계 | +| stat_sales_daily | StatSalesDaily | 일별 영업 통계 | +| stat_hr_daily | StatHrDaily | 일별 인사 통계 | +| stat_inventory_daily | StatInventoryDaily | 일별 재고 통계 | + +### 월별 집계 (Monthly) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| stat_finance_monthly | StatFinanceMonthly | 월별 재무 통계 | +| stat_production_monthly | StatProductionMonthly | 월별 생산 통계 | +| stat_sales_monthly | StatSalesMonthly | 월별 영업 통계 | + +### 차원 테이블 (Dimensions) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| dim_clients | DimClient | 거래처 차원 | +| dim_dates | DimDate | 날짜 차원 | +| dim_products | DimProduct | 제품 차원 | +| dim_departments | DimDepartment | 부서 차원 | + +### 기타 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| base_stat_model | BaseStatModel | 통계 모델 베이스 | +| stat_* | 기타 통계 모델 | 도메인별 집계 | + +--- + +## 아키텍처 + +``` +[samdb] ──Observer 이벤트──→ [통계 서비스 15개] ──집계──→ [sam_stat DB] + +StatEventObserver + ├─ 주문 이벤트 → StatSalesDaily 업데이트 + ├─ 생산 이벤트 → StatProductionDaily 업데이트 + ├─ 재무 이벤트 → StatFinanceDaily 업데이트 + └─ ... (도메인별) +``` + +--- + +## 특이사항 + +- **별도 DB 연결**: `sam_stat` (samdb와 분리) +- **마이그레이션**: 22개 (별도 관리) +- **서비스**: 15개 전용 서비스 (Stats/ 디렉토리) +- **차원 테이블**: 스타 스키마 기반 (DimClient, DimDate 등) +- **이벤트 기반**: Observer 패턴으로 실시간 집계 +- API 엔드포인트: 5개 (stats.php) — 대부분 조회용 \ No newline at end of file diff --git a/system/database/tenants.md b/system/database/tenants.md new file mode 100644 index 0000000..63d61b4 --- /dev/null +++ b/system/database/tenants.md @@ -0,0 +1,90 @@ +# 테넌트 / 사용자 / 권한 도메인 + +> **모델 수**: Tenants 56 + Members 4 + Permissions 3 = 63 +> **핵심**: 멀티테넌시 기반, 모든 비즈니스 데이터의 기준점 + +--- + +## 주요 테이블 + +### 인증 / 사용자 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| users | User | 시스템 계정 (Sanctum, HasRoles) | +| user_tenants | UserTenant | 사용자-테넌트 매핑 (is_active, is_default) | +| user_roles | UserRole | 사용자-역할 매핑 | +| user_menu_permissions | UserMenuPermission | 사용자별 메뉴 권한 | + +### 테넌트 핵심 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| tenants | Tenant | 조직/회사 마스터 | +| departments | Department | 부서 (계층 구조, parent_id) | +| department_user | (pivot) | 부서-사용자 다대다 | +| tenant_user_profiles | TenantUserProfile | 테넌트별 직원 프로필 | +| positions | Position | 직급/직위 | + +### 테넌트 설정 + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| tenant_settings | TenantSetting | 테넌트별 설정값 | +| tenant_field_settings | TenantFieldSetting | 필드별 설정 | +| tenant_option_groups | TenantOptionGroup | 옵션 그룹 정의 | +| tenant_option_values | TenantOptionValue | 옵션 값 | +| tenant_stat_fields | TenantStatField | 통계 필드 설정 | + +### 권한 (Spatie Permission) + +| 테이블 | 모델 | 역할 | +|--------|------|------| +| permissions | Permission | 권한 정의 | +| roles | Role | 역할 정의 | +| permission_overrides | PermissionOverride | 권한 오버라이드 (다형) | + +--- + +## 관계 구조 + +``` +User (1) + ├─ (N) UserTenant ─→ (1) Tenant + ├─ (N) UserRole ─→ (1) Role ─→ (N) Permission + └─ (N) UserMenuPermission + +Tenant (1) + ├─ (N) Department (parent_id → self) + │ └─ (N:M) User via department_user + ├─ (N) TenantUserProfile + │ ├─ → User + │ └─ → Department + ├─ (N) TenantSetting + └─ (N) [모든 BelongsToTenant 모델] +``` + +--- + +## Tenants 하위 비즈니스 모델 (56개) + +Tenants 도메인은 조직 내 다양한 비즈니스 기능을 포함: + +- **재무**: Payment, Bill, TaxInvoice, JournalEntry, Deposit, Withdrawal 등 +- **인사**: Payroll, Attendance, Leave, LeavePolicy, Salary, Loan 등 +- **영업**: Sale, Client, ClientGroup, Shipment, Receivables 등 +- **재고**: Stock, StockLot, MaterialInput 등 +- **결재**: Approval, ApprovalForm, ApprovalLine 등 +- **기타**: Calendar, CalendarSchedule, Notification 등 + +> 이 모델들의 상세 내용은 각 도메인 문서(finance.md, hr.md, sales.md 등)에서 다룸. + +--- + +## 특이사항 + +- `User`는 BelongsToTenant가 아님 (시스템 전역) +- `UserTenant`으로 다중 테넌트 소속 지원 +- `TenantUserProfile`은 테넌트별 직원 정보 (직급, 입사일 등) +- `Department`는 self-reference 계층 구조 (parent_id) +- 권한은 메뉴 기반 RBAC (Spatie Permission + UserMenuPermission) \ No newline at end of file diff --git a/system/docker-setup.md b/system/docker-setup.md new file mode 100644 index 0000000..e0b3d7a --- /dev/null +++ b/system/docker-setup.md @@ -0,0 +1,232 @@ +# Docker 환경 설정 + +> **최종 갱신**: 2026-02-27 +> **Docker Compose**: 7 서비스, `samnet` 브리지 네트워크 + +--- + +## 1. 서비스 구성 + +| 서비스 | 이미지 | 포트 | 역할 | +|--------|--------|------|------| +| nginx | nginx:latest | 80, 443 | 리버스 프록시, SSL 종료 | +| api | php:8.4-fpm (custom) | 9000 | Laravel REST API | +| mng | php:8.4-fpm (custom) | 9000 | Laravel 관리자 패널 | +| react | node:20-alpine | 3000 | Next.js 프론트엔드 | +| design | node:20-alpine | 3002 | Vite 디자인 시스템 | +| php73 | php:7.3-fpm (custom) | 9000 | 레거시 5130 | +| mysql | mysql:8.0 | 3306 | 데이터베이스 | + +--- + +## 2. 도메인 매핑 + +| 도메인 | 대상 | SSL | 비고 | +|--------|------|-----|------| +| api.sam.kr | api:9000 (FastCGI) | O | 대형 JSON 버퍼링 | +| mng.sam.kr | mng:9000 (FastCGI) | O | 관리자 패널 | +| admin.sam.kr | mng:9000 (FastCGI) | O | mng 별칭 | +| dev.sam.kr | react:3000 (Proxy) | O | HMR WebSocket 지원 | +| design.sam.kr | design:3002 (Proxy) | O | HMR WebSocket 지원 | +| 5130.sam.kr | php73:9000 (FastCGI) | O | 레거시 | +| dev.haisa.kr | host.docker.internal:8888 | X | 외부 프록시 | + +--- + +## 3. 네트워크 구조 + +``` +[호스트] + 127.0.0.1:80 ─→ nginx:80 + 127.0.0.1:443 ─→ nginx:443 + 127.0.0.1:3306 ─→ mysql:3306 + +[samnet 내부] + nginx ──FastCGI──→ api:9000 + nginx ──FastCGI──→ mng:9000 + nginx ──FastCGI──→ php73:9000 + nginx ──Proxy────→ react:3000 + nginx ──Proxy────→ design:3002 + api/mng ─────────→ mysql:3306 +``` + +- 모든 포트는 `127.0.0.1` 바인딩 (외부 접근 차단) +- `samnet` 브리지 네트워크로 컨테이너간 통신 + +--- + +## 4. Dockerfile 요약 + +### api / mng (PHP 8.4-FPM) +``` +Base: php:8.4-fpm +Extensions: zip, mysqli, pdo, pdo_mysql, intl +Packages: git, unzip, nginx, supervisor +Composer: 2 (멀티스테이지 빌드) +실행: Supervisor (nginx + php-fpm 동시) +Entrypoint: storage:link, 권한 설정 +``` + +### react (Node 20) +``` +Base: node:20-alpine +추가: chromium, font-noto-cjk (Puppeteer 지원) +환경: PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser +실행: npm run dev (포트 3000) +``` + +### design (Node 20) +``` +Base: node:20-alpine +실행: npm run dev (포트 3002) +``` + +### php73 (PHP 7.3-FPM) +``` +Base: php:7.3-fpm +Extensions: gd, mbstring +설정: short_open_tag=On, display_errors=On +``` + +--- + +## 5. 볼륨 마운팅 + +### 주요 볼륨 +- **db_data** (Named Volume): MySQL 데이터 영속성 +- **앱 소스코드**: 호스트 → 컨테이너 직접 마운트 +- **API 스토리지**: mng가 api의 storage/app/tenants 공유 마운트 + +### Nginx 설정 +- `docker/nginx/nginx.conf` → `/etc/nginx/nginx.conf` (RO) +- `docker/nginx/ssl/` → `/etc/nginx/ssl/` (RO) + +### PHP 설정 +- `uploads.ini`: file_uploads=On, memory_limit=256M, upload_max=20M, post_max=100M +- `supervisord.conf`: php-fpm + nginx 동시 실행 (nodaemon) + +--- + +## 6. MySQL 설정 + +### my.cnf +```ini +innodb_buffer_pool_size = 256M +innodb_log_buffer_size = 16M +sort_buffer_size = 4M +tmp_table_size = 64M +character-set-server = utf8mb4 +collation-server = utf8mb4_unicode_ci +log_bin_trust_function_creators = 1 +``` + +### 초기화 (init.sql) +```sql +CREATE DATABASE samdb; -- API/MNG용 +CREATE DATABASE chandj; -- 레거시 5130용 +CREATE USER samuser@'%'; +GRANT ALL ON samdb.*, chandj.*; +``` + +--- + +## 7. Nginx 보안 필터 (API) + +``` +차단 패턴: +- 경로 트래버설: \.\.\/|\.\.\\|etc\/passwd +- 민감 파일: \.env|\.git|\.htaccess|\.sql|@fs\/ +- 악성 User-Agent: sqlmap, nikto, nmap, masscan, metasploit, nessus +응답: 403 Forbidden +``` + +### 업로드 제한 +| 대상 | 최대 크기 | +|------|----------| +| Nginx (기본) | 100M | +| API | 100M | +| MNG | 210M | + +### 정적 자산 캐싱 +- 대상: js, css, png, jpg, gif, svg, ico, woff2, ttf +- 만료: 30일, Cache-Control: public + +--- + +## 8. CI/CD (Jenkins) + +### 파이프라인 요약 + +| 저장소 | 트리거 브랜치 | 배포 서버 | 특징 | +|--------|-------------|----------|------| +| api | main, develop | 211.117.60.189 | Release 디렉토리, 자동 마이그레이션, 자동 롤백 | +| react | main, develop | 114.203.209.83 (dev), 211.117.60.189 (stage/prod) | PM2 프로세스 관리 | +| mng | main | 211.117.60.189 | npm build + PHP-FPM 재로드 | +| sales | main | 211.117.60.189 | 정적 사이트 rsync만 | + +### 배포 전략 (api/mng) +``` +1. releases/{RELEASE_ID} 디렉토리 생성 (타임스탬프) +2. rsync 코드 복사 (.git, .env, storage 제외) +3. composer install + npm install +4. php artisan migrate --force +5. config/route/view 캐시 생성 +6. /current symlink → 최신 릴리스 +7. PHP-FPM 재로드 +8. 이전 릴리스 정리 (최근 6개만 유지) +``` + +### 롤백: 실패 시 이전 릴리스로 symlink 자동 변경 +### 알림: Slack (빌드 시작/성공/실패) + +--- + +## 9. 배포 환경 요약 + +| 환경 | 도메인 | IP | 배포 방식 | +|------|--------|----|----------| +| 로컬 | *.sam.kr | localhost | Docker Compose | +| 개발 | codebridge-x.com | 114.203.209.83 | Jenkins (react only) | +| 스테이지 | TBD | 211.117.60.189 | Jenkins (api, mng, react) | +| 운영 | TBD | 211.117.60.189 | Jenkins (승인 필요, 비활성) | + +--- + +## 10. 디렉토리 구조 + +``` +docker/ +├── docker-compose.yml 전체 서비스 정의 +├── .env 프로젝트명 설정 +├── nginx/ +│ ├── nginx.conf 메인 설정 (7개 virtual host) +│ └── ssl/ SSL 인증서 +├── api/ +│ ├── Dockerfile +│ ├── nginx.conf +│ ├── supervisord.conf +│ ├── entrypoint.sh +│ └── uploads.ini +├── mng/ +│ ├── Dockerfile +│ ├── nginx.conf +│ ├── supervisord.conf +│ ├── entrypoint.sh +│ └── uploads.ini +├── react/ +│ ├── Dockerfile +│ └── entrypoint.sh +├── design/ +│ ├── Dockerfile +│ └── entrypoint.sh +├── 5130/ +│ ├── Dockerfile +│ ├── nginx.conf +│ ├── supervisord.conf +│ ├── entrypoint.sh +│ └── uploads.ini +└── mysql/ + ├── init.sql + ├── my.cnf + └── database.sql +``` \ No newline at end of file diff --git a/system/erp-analysis/00-overview.md b/system/erp-analysis/00-overview.md new file mode 100644 index 0000000..14c35ce --- /dev/null +++ b/system/erp-analysis/00-overview.md @@ -0,0 +1,155 @@ +# SAM ERP 스토리보드 분석 개요 + +> 분석 대상: SAM_ERP_Storyboard_D0.8_251216 (113 슬라이드) +> 분석일: 2025-12-17 +> 버전: D0.8 + +## 1. 문서 개요 + +### 1.1 버전 히스토리 +| 날짜 | 버전 | 내용 | +|------|------|------| +| 2025.12.01 | D0.6 | 프론트 초안 - 인사관리 & 전자결재 작성 | +| 2025.12.01 | D0.7 | 프론트 작성 - 인사관리 & 전자결재 피드백 반영 | +| 2025.12.16 | D0.8 | 회계 & 보고서 작성, GPS 출퇴근, 카드/계좌관리, 보고서 추가 | + +### 1.2 슬라이드 구성 +- **총 113 슬라이드** +- 공통 UI 가이드 + 8개 주요 기능 모듈 + +## 2. 메뉴 구조 (GNB/LNB) + +``` +SAM ERP +├── 대시보드 +├── MES 메뉴 (영업관리, 판매관리, 구매관리 등) +├── 인사관리 +│ ├── 부서관리 +│ ├── 사원관리 +│ ├── 근태관리 +│ └── 휴가관리 +├── 전자결재 +│ ├── 기안함 +│ ├── 결재함 +│ └── 참조함 +├── 게시판 +├── 회계관리 +│ ├── 거래처관리 +│ ├── 매출관리 +│ ├── 매입관리 +│ ├── 입금관리 +│ ├── 출금관리 +│ ├── 어음관리 +│ ├── 거래처원장 +│ ├── 일일 일보 +│ ├── 지출 예상 내역서 +│ ├── 미수금 현황 +│ ├── 악성채권 추심관리 +│ ├── 입출금 계좌 조회 +│ └── 카드 내역 조회 +├── 기준정보 +│ ├── 직급관리 +│ ├── 직책관리 +│ ├── 권한관리 +│ ├── 근무관리 +│ ├── 출퇴근관리 +│ ├── 휴가관리 +│ ├── 카드관리 +│ ├── 계좌관리 +│ ├── 팝업관리 +│ ├── 게시판관리 +│ ├── 일반설정 +│ └── 알림설정 +├── 보고서 및 분석 +├── 계정정보 +├── 회사정보 +├── 구독관리 +├── 결제내역 +└── 고객센터 +``` + +## 3. 기능 그룹별 슬라이드 매핑 + +| 그룹 | 슬라이드 범위 | 주요 내용 | 분석 문서 | +|------|---------------|----------|----------| +| 공통 | 3-13 | UI 컴포넌트, 인터랙션, 알림 | [01-common.md](./01-common.md) | +| 인증/영업 | 14-22 | 가입, 로그인, 약관동의 | [02-auth.md](./02-auth.md) | +| GPS 출퇴근 | 23-27 | 모바일 출퇴근 | [03-gps-attendance.md](./03-gps-attendance.md) | +| 인사관리 | 28-46 | 부서/사원/근태/휴가 | [04-hr-management.md](./04-hr-management.md) | +| 전자결재 | 47-59 | 기안/결재/참조함 | [05-approval.md](./05-approval.md) | +| 회계관리 | 60-91 | 거래처/매출/매입/입출금 | [06-accounting.md](./06-accounting.md) | +| 기준정보 | 92-104 | 직급/직책/휴가/카드/계좌 | [07-master-data.md](./07-master-data.md) | +| 보고서 | 105-113 | 분석/AI 리포트 | [08-reports.md](./08-reports.md) | + +## 4. 사용자 역할 + +### 4.1 영업사원 (Sales) +- 운영 로그인 +- 회사 등록 신청 +- 테넌트 추가 알림 + +### 4.2 관리자 (Admin) +- 자료 확인 +- 가입 승인/거절 +- 이메일로 URL 발송 + +### 4.3 고객사 (Customer/Tenant) +- 약관 동의 +- 비밀번호 설정 +- SAM 로그인 +- 테넌트 추가 + +## 5. 핵심 비즈니스 플로우 + +### 5.1 가입 및 로그인 플로우 (슬라이드 15) +``` +영업사원: 운영 로그인 → 사업자등록번호 입력 → 회사정보 등록 → 가입신청 완료 + ↓ (거절) +관리자: 자료 확인 → 승인? → 이메일로 URL 발송 거절 알림 + ↓ +고객사: 약관 동의 → 비밀번호 설정 → SAM 로그인 → 테넌트 추가? + ↓ +매니저: 테넌트 추가 알림 → 사업자등록번호 입력 +``` + +### 5.2 회계관리 플로우 (슬라이드 61) +``` +매출: 거래처 선택 → 매출 등록 → 세금계산서 발행 +입금: 입금 등록 → 전액 입금? → 어음 수취? +매입: 거래처 선택 → 매입 등록 → 세금계산서 수취 +출금: 출금 등록 → 전액 출금? → 어음 발행? +추심: 미수금 현황 → 연체? → 악성주심? → 악성 추심 +조회: 입출금 계좌 조회, 카드 내역 조회 +장부/보고서: 거래처원장, 지출 예상 내역서, 일일 일보 +``` + +## 6. 기술 스펙 + +### 6.1 반응형 웹 브레이크포인트 +- 모바일: < 640px (기본) +- 태블릿: 768px ~ 1023px (md) +- 데스크탑: 1024px+ (lg) +- 대형 모니터: 1280px+ (xl) + +### 6.2 인터랙션 +| 타입 | 적용 | +|------|------| +| Tap | Yes | +| Touch & Hold | No | +| Double Tap | No | +| Drag & Drop | Yes | +| Scroll Up/Down | Yes | +| Swipe Left/Right | Yes | +| Pinch Zoom In/Out | Yes | + +### 6.3 알림 타입 +- Alert (알림): 사용자에게 상황 알림 +- Confirm Alert (확인): 확인/취소 선택 +- Toast Message: 2-3초 후 Fade out + +## 7. 다음 단계 + +1. 각 기능 그룹별 상세 분석 문서 작성 +2. API 엔드포인트 도출 +3. 데이터 모델 설계 +4. 개발 우선순위 결정 \ No newline at end of file diff --git a/system/erp-analysis/01-common.md b/system/erp-analysis/01-common.md new file mode 100644 index 0000000..f78e1f9 --- /dev/null +++ b/system/erp-analysis/01-common.md @@ -0,0 +1,143 @@ +# 공통 UI 컴포넌트 (슬라이드 3-13) + +## 1. 화면 템플릿 (슬라이드 6) + +### 1.1 모바일 화면 구조 +``` +┌─────────────────────────────┐ +│ A. Status bar (OS 관리) │ +├─────────────────────────────┤ +│ B. Browser 영역 │ +├──────┬──────────────────────┤ +│Button│ Title │Button│ C. Title 영역 +├──────┴──────────────────────┤ +│ │ +│ D. Content 영역 │ +│ │ +├─────────────────────────────┤ +│ E. Browser bar 영역 │ +├─────────────────────────────┤ +│ F. Keypad 영역 (입력 시) │ +└─────────────────────────────┘ +``` + +### 1.2 영역 설명 +- **A. Status bar**: 안테나, 통화, 배터리 등 시스템 OS 관리 영역 +- **B. Browser 영역**: 브라우저 기능 영역 +- **C. Title 영역**: 텍스트 또는 기능 버튼으로 구현, 텍스트 기본 가운데 정렬 +- **D. Content 영역**: 컨텐츠 내용 표시, 컨텐츠 길이가 길어질 경우 스크롤 제공 +- **E. Browser bar 영역**: 브라우저 유틸 바 영역 +- **F. Keypad 영역**: 키보드 입력할 때 활성화, 모든 페이지 위에 덮어쓰기 구현 + +## 2. GNB/LNB/푸터 (슬라이드 8) + +### 2.1 알림 버튼 +- 클릭: 알림 팝업 표시 + +### 2.2 개인 정보 버튼 +- 등록: 디폴트 이미지, 이름, 직급 +- 클릭: 마이페이지 팝업 표시 + +### 2.3 회사 로고 +- 회사정보 화면에서 등록한 로고 표시 +- 회사 변경 선택 시 해당 로고 변경 + +### 2.4 메뉴 영역 +- 메뉴 클릭: + - 하위 메뉴가 있을 경우: 하위 메뉴 하단에 표시 + - 하위 메뉴 없을 경우: 해당 메뉴 화면으로 이동 + - 목록 길 경우 해당 영역 내 스크롤 처리 + +### 2.5 MES 메뉴 영역 +- 영업관리, 판매관리, 구매관리 등 해당하는 MES 메뉴 영역 표시 + +### 2.6 푸터 영역 +- 모든 화면 하단 공통 표시 + +## 3. 알림 팝업 (슬라이드 9) + +### 3.1 알림 목록 +- 항목: 디폴트 원형일, 종류(공지사항), 안내/제목/내용, 전송일시 표시 +- 클릭: 해당 상세 화면으로 이동 +- 최신순 10개까지 표시 + +### 3.2 New 아이콘 +- 새 알림일 경우 New 아이콘 표시 +- 해당 알림 클릭 시 사라짐 + +### 3.3 빨간 점 아이콘 +- 새 알림이 있을 경우 표시 +- 해당 알림 모두 클릭 시 사라짐 + +## 4. 마이페이지 팝업 (슬라이드 10) + +### 4.1 계정 아이디 (이메일) 표시 + +### 4.2 회사 셀렉트 박스 +- 종류: 회사명, 회사명... (해당 계정이 생성한 회사(테넌트) 목록 표시) +- 정렬: 등록순 +- 한 회사만 소유중일 경우에는 해당 영역 숨김 + +### 4.3 로그아웃 버튼 +- 클릭: "정말 로그아웃하시겠습니까?" 로그아웃 확인 Alert 표시 +- 확인 버튼 클릭 시 로그아웃 처리 + +## 5. 셀렉트 박스 (슬라이드 11) + +### 5.1 기본 셀렉트 박스 +- 클릭: 하단에 종류 목록 표시 + +### 5.2 종류 목록 +- 목록 중 하나만 선택 가능 + +### 5.3 다중 선택 셀렉트 박스 +- 선택된 첫번째 항목명 + 추가 수 표시 +- 텍스트 영역 부족할 경우 '항목..+3' 형태로 표시 + +### 5.4 다중 선택 종류 목록 +- 목록 중 복수 선택 가능 +- 전체 선택 시 전체 선택/해제 토글 + +### 5.5 검색 영역 +- 검색어 입력 후 엔터 또는 검색 아이콘 클릭 시 (5-1) 형태로 표시되며 (5-2) 영역에 검색 결과 표시 + +### 5.6 삭제 버튼 +- 클릭: 검색어 삭제 처리, 전체 종류 목록 표시 + +## 6. 입력 필드 가이드 메시지 (슬라이드 12) + +### 6.1 가이드 메시지 표시 위치 +- 상황에 따라 입력 필드 하단 또는 Alert에 표시 + +### 6.2 가이드 메시지 색상 +- 긍정일 경우: 녹색 +- (1-1) 부정일 경우: 붉은색 + +## 7. 공지 팝업 (슬라이드 13) + +### 7.1 대상 +- 전체, 설정 부서 +- 내용: 설정 기간동안 대상에게 팝업 표시 + +### 7.2 팝업 내용 영역 +- 이미지, 텍스트 + +### 7.3 "1일간 이 창을 열지 않음" 체크박스 +- 클릭: 체크 설정/해제 토글 +- 디폴트: 체크 해제 상태 +- 체크 설정 시 1일 동안 팝업 미표시 (차정 기준) + +--- + +## API 도출 + +### 공통 API +``` +GET /api/notifications # 알림 목록 조회 +POST /api/notifications/{id}/read # 알림 읽음 처리 +GET /api/user/profile # 마이페이지 정보 +GET /api/user/companies # 사용자 소속 회사 목록 +POST /api/auth/logout # 로그아웃 +GET /api/announcements # 공지 팝업 조회 +POST /api/announcements/{id}/dismiss # 공지 팝업 닫기 (1일간 안보기) +``` \ No newline at end of file diff --git a/system/erp-analysis/02-auth.md b/system/erp-analysis/02-auth.md new file mode 100644 index 0000000..1d9728d --- /dev/null +++ b/system/erp-analysis/02-auth.md @@ -0,0 +1,205 @@ +# 인증/영업 (슬라이드 14-22) + +## 1. 가입 및 로그인 플로우차트 (슬라이드 15) + +### 1.1 영업사원 플로우 +``` +운영 로그인 → 사업자등록번호 입력 → 사업자번호 조회? + ↓ Yes + 회사정보 등록 → 가입신청 완료 + ↓ (거절) + 거절 알림 +``` + +### 1.2 관리자 플로우 +``` +자료 확인 → 승인? → (Yes) → 이메일로 URL 발송 + ↓ (No) + 계약금50% 결제 확인 +``` + +### 1.3 고객사 플로우 +``` +약관 동의 → 비밀번호 설정 → SAM 로그인 → 테넌트 추가? + ↓ (Yes) + 매니저: 테넌트 추가 알림 + ↓ + 사업자등록번호 입력 +``` + +## 2. 운영 로그인 (슬라이드 16) + +### 2.1 아이디 인풋박스 +- 테넌트 생성자일 경우 이메일 +- 사용자일 경우 이메일 또는 아이디 +- (1-1) 상황별 가이드 메시지 + +### 2.2 비밀번호 인풋박스 +- 입력 시 마지막 글자 제외 후 마스킹 처리 +- (2-1) 상황별 가이드 메시지 + +### 2.3 열람 버튼 +- 클릭: 열람/숨김 토글 +- 디폴트: 숨김 상태 +- 열람 상태일 시 (2) 영역 마스킹 해제 처리 + +### 2.4 자동 로그인 체크박스 +- 클릭: 체크 설정/해제 토글 +- 체크 시 로그아웃 전까지 세션 유지 + +### 2.5 로그인 버튼 +- 클릭: 유효할 경우 대시보드 화면으로 이동 + +### 2.6 가이드 메시지 +| 상황 | 가이드 메시지 | +|------|---------------| +| 필수 정보 미 입력 시 | 필수 정보입니다. | +| 4글자 미만 입력 시 | 이메일은 4자 이상 가능합니다 | +| 이메일 형식에 유효 하지 않을 경우 | 이메일 주소를 다시 확인해주세요. | +| 8자 미만 입력 시 | 8자 이상으로 만들어주세요. | +| 영문+숫자+특수문자 조합이 아닐 경우 | 영문, 숫자, 특수문자를 포함해주세요. 다음의 특수기호는 보안 사항을 가능합니다., ; - @ ! | + +## 3. 사업자등록번호 조회 (슬라이드 17) + +### 3.1 제조 데모 +- 클릭: 제조 데모 화면으로 이동 + +### 3.2 시공 데모 +- 클릭: 시공 데모 화면으로 이동 + +### 3.3 사업자등록번호 인풋박스 +- 숫자만 가능, 10자리 + +### 3.4 다음 버튼 +- 클릭: + 1. 바로 빌 사업자등록번호 조회 후 사용 불가 경우: "중복된 사업자등록번호입니다." 알림 Alert 표시 + 2. 바로 빌 사업자등록번호 조회 후 사용 가능한 경우: + - [1] 테넌트 등록된 사업자등록번호일 경우: 테넌트 등록 전이어도 다른 영업사원이 등록중을 경우에는 사업자등록번호 사용 불가 (어드민에서는 해제 가능) + - "등록된 사업자등록번호 입니다." 알림 Alert 표시 + - [2] 등록되지 않은 사업자등록번호일 경우: 회사정보 등록 화면으로 이동 + +## 4. 회사정보 등록 (슬라이드 18) + +### 4.1 회사(테넌트) 상태 +- 신청: 신청 완료 입력 +- 승인: 자동 입금 외 계약금 50% 입금, 이메일로 URL 발송 선택 +- 최초 로그인 시 ERP만 표시 +- 거절: 프로젝트 설정 완료, 잔금 50% 입금 및 인도, 당월 말일까지는 무료, 익월부터 익월말까지 사용하고 구독료 청구 +- 만료: 기간 종료, 안료외 연체 상태 구분?? 영업사원에게 알림, 서비스에는 접근 불가, 배너 +- 해지: 오퍼 대기기간 단계 필요?? +- 해지: 서비스 이용 불가 +- 탈퇴: 로그인 불가, 복구 불가?? +- 미사: 서비스 이용 불가 + +### 4.2 회사 로고 이미지 영역 +- 디폴드 이미지 표시 +- 클릭: 파일탐색기 팝업 표시, 10MB 이하의 PNG, JPEG, GIF 중 하나 선택 가능 + +### 4.3 우편번호 찾기 버튼 +- 클릭: 선정한 주소 팝업 표시 + +### 4.4 찾기 버튼 +- 클릭: 파일탐색기 팝업 표시, 이미지 또는 파일 하나 선택 가능 + +### 4.5 가입 신청 버튼 +- 클릭: 사업자등록번호 조회 화면으로 이동 +- 회사 로고만 선택, 나머지는 필수 정보 +- 클릭: 가입 신청 완료 화면으로 이동 + +### 4.6 입력 필드 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 회사 로고 | N | 750x250px, 10MB 이하 PNG, JPEG, GIF | +| 회사명 | Y | | +| 대표자명 | Y | | +| 업태 | Y | | +| 업종 | Y | | +| 주소 | Y | 우편번호 찾기 + 상세주소 | +| 이메일 (아이디) | Y | | +| 세금계산서 이메일 | Y | | +| 담당자명 | Y | | +| 담당자 연락처 | Y | | +| 사업자등록증 | Y | 파일 첨부 | + +## 5. 가입 신청 완료 (슬라이드 19) + +### 5.1 가입 신청 완료 안내 문구 표시 +- SAM은 폐쇄형 네트워크이므로 플랫폼의 무결성을 보장하기 위해 모든 계정을 검토해야 합니다. +- (회사명)의 계정 세부 정보를 추가로 확인하기 위해 추가 정보를 요청할 수 있습니다. +- 영업일 기준 3일 이내에 계정에 대한 업데이트를 받게 됩니다. + +### 5.2 가입 신청 취소 버튼 +- 클릭: "가입 신청 취소 시 등록한 모든 정보가 삭제됩니다. 정말 가입 신청을 취소하시겠습니까?" 확인 Alert 표시 + +## 6. 가입 신청 승인 성공 이메일 (슬라이드 20) + +### 6.1 계정 활성화 버튼 +- 클릭: 약관 동의 화면으로 이동 + +### 6.2 지원, 블로그 버튼 +- 클릭: 해당 운영 노션 링크로 이동 + +## 7. 약관 동의 (슬라이드 21) + +### 7.1 약관 영역 +- 클릭: (1-1) 약관 내용 영역 열림/닫힘 토글 +- 디폴트: 닫힘 + +### 7.2 체크박스 +- 클릭: 체크 설정/해제 토글 +- 디폴트: 체크 설정 해제 + +### 7.3 약관에 동의합니다 버튼 +- 모든 필수 약관 동의 시 버튼 활성화 +- 클릭: 비밀번호 설정 화면으로 이동 + +### 7.4 약관에 동의합니다 버튼 +- 클릭: 모든 필수, 선택 약관에 동의 처리, 비밀번호 설정 화면으로 이동 + +### 7.5 약관 목록 +| 약관명 | 필수 | +|--------|------| +| [필수] 서비스 이용약관 | Y | +| [필수] 개인정보 취급방침 | Y | +| [필수] 약관명 | Y | +| 마케팅 정보 수신 동의 (선택) | N | +| - 이메일 수신 동의 | N | +| - SMS 수신 동의 | N | + +## 8. 비밀번호 설정 (슬라이드 22) + +### 8.1 계정 활성화 버튼 +- 클릭: 로그인 화면으로 이동 + +### 8.2 비밀번호 요구사항 +- 최소 8자 이상 영문+숫자+특수문자 조합 + +--- + +## API 도출 + +### 인증 API +``` +POST /api/auth/login # 로그인 +POST /api/auth/logout # 로그아웃 +POST /api/auth/password/reset # 비밀번호 재설정 +POST /api/auth/password/change # 비밀번호 변경 +``` + +### 회원가입/영업 API +``` +GET /api/business-registration/verify # 사업자등록번호 조회 +POST /api/registration/company # 회사정보 등록 +POST /api/registration/cancel # 가입신청 취소 +GET /api/terms # 약관 목록 조회 +POST /api/terms/agree # 약관 동의 +POST /api/account/activate # 계정 활성화 +``` + +### 테넌트 API +``` +GET /api/tenants # 테넌트 목록 +POST /api/tenants # 테넌트 추가 +PUT /api/tenants/{id} # 테넌트 수정 +GET /api/tenants/{id}/switch # 테넌트 전환 +``` diff --git a/system/erp-analysis/03-gps-attendance.md b/system/erp-analysis/03-gps-attendance.md new file mode 100644 index 0000000..4903e27 --- /dev/null +++ b/system/erp-analysis/03-gps-attendance.md @@ -0,0 +1,144 @@ +# GPS 출퇴근 (슬라이드 23-27) + +## 1. 개요 + +GPS 기반 모바일 출퇴근 관리 시스템으로, 위치 정보를 활용하여 출근/퇴근을 기록합니다. + +## 2. 마이페이지 팝업 > 출퇴근하기 (슬라이드 24) + +### 2.1 출퇴근 버튼 +- GPS 출퇴근 사용 시에만 표시 +- 모바일일 경우에만 버튼 활성화 +- 클릭: 출퇴근하기 화면으로 이동 + +### 2.2 출퇴근 허용 반경 +- 기준 화표로부터의 출퇴근 허용 반경을 m 형으로 표시 (기준정보 > 출퇴근관리에서 설정) + +### 2.3 현재 위치 버튼 +- 클릭: (3-1) 해당 현재 위치를 지도 중심으로 표시 + +### 2.4 [+] 버튼 +- 클릭: 지도 영역 확대 + +### 2.5 확대/축소 슬라이드바 +- 드래그&드랍 또는 클릭: 지도 영역 확대/축소 + +### 2.6 [-] 버튼 +- 클릭: 지도 영역 축소 + +### 2.7 개인 정보 영역 +- 항목: 프로필 이미지, 이름, 부서명, 직급명 + +### 2.8 현재 시:분:초 표시 +- HH:MM:SS + +### 2.9 출근하기 버튼 +- 클릭: + 1) 출근 위치 미설정 상태일 경우: "출근 위치를 설정해주세요." 알림 Alert 표시 + 2) 출근 위치 설정 상태일 경우: + - (1) 출근 위치가 기준 설정 반경 초과일 경우: "출근 가능 위치가 아닙니다. 출근 위치를 확인해주세요." 알림 Alert 표시 + - [2] GPS 출근 위치 기준 설정 반경 이내: 출근하기 화면으로 이동 (출근 기록 저장) + +## 3. 출근하기 (슬라이드 25) + +### 3.1 퇴근하기 버튼 +- 클릭: + 1) 퇴근 위치 미설정 상태일 경우: "퇴근 위치를 설정해주세요." 알림 Alert 표시 + 2) 퇴근 위치 설정 상태일 경우: + - (1) 퇴근 위치가 기준 설정 반경 초과일 경우: "퇴근 가능 위치가 아닙니다. 퇴근 위치를 확인해주세요." 알림 Alert 표시 + - [2] GPS 퇴근 위치 기준 설정 반경 이내: 퇴근하기 화면으로 이동 (퇴근 기록 저장) + +### 3.2 출근 완료 아이콘 이미지 표시 + +### 3.3 출근 완료 정보 +- 항목: 출근 완료 문구, 시:분:초, 일자(요일) + +### 3.4 출근 화표의 본사/현장명 표시 + +### 3.5 확인 버튼 +- 클릭: 대시보드로 이동 + +## 4. 퇴근하기 (슬라이드 26) + +### 4.1 퇴근 완료 아이콘 이미지 표시 + +### 4.2 퇴근 완료 정보 +- 항목: 퇴근 완료 문구, 시:분:초, 일자(요일) + +### 4.3 퇴근 화표의 본사/현장명 표시 + +### 4.4 확인 버튼 +- 클릭: 대시보드로 이동 + +## 5. 현장 등록 (슬라이드 27) + +### 5.1 위치 정보 설정 +- 각 현장의 GPS 중심값으로 설정 + +### 5.2 입력 필드 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 주소 | Y | 우편번호 찾기 + 상세주소 | +| 경도 | Y | | +| 위도 | Y | | +| 첨부파일 | N | | + +--- + +## 데이터 모델 + +### Attendance (출퇴근 기록) +``` +- id: bigint +- user_id: bigint (FK) +- tenant_id: bigint (FK) +- type: enum('check_in', 'check_out') +- check_time: datetime +- latitude: decimal(10,8) +- longitude: decimal(11,8) +- location_id: bigint (FK, nullable) # 본사/현장 +- location_name: string +- is_valid: boolean # 유효 위치 여부 +- created_at: timestamp +``` + +### Location (본사/현장) +``` +- id: bigint +- tenant_id: bigint (FK) +- name: string +- address: string +- detail_address: string +- latitude: decimal(10,8) +- longitude: decimal(11,8) +- allowed_radius: int # 허용 반경 (m) +- is_active: boolean +- created_at: timestamp +``` + +--- + +## API 도출 + +### GPS 출퇴근 API +``` +POST /api/attendance/check-in # 출근 기록 +POST /api/attendance/check-out # 퇴근 기록 +GET /api/attendance/today # 오늘 출퇴근 현황 +GET /api/attendance/status # 현재 출퇴근 상태 +GET /api/attendance/location/validate # 위치 유효성 검증 +``` + +### 현장 관리 API +``` +GET /api/locations # 현장 목록 +POST /api/locations # 현장 등록 +PUT /api/locations/{id} # 현장 수정 +DELETE /api/locations/{id} # 현장 삭제 +``` + +### 출퇴근 설정 API +``` +GET /api/settings/attendance # 출퇴근 설정 조회 +PUT /api/settings/attendance # 출퇴근 설정 수정 +``` diff --git a/system/erp-analysis/04-hr-management.md b/system/erp-analysis/04-hr-management.md new file mode 100644 index 0000000..f70a093 --- /dev/null +++ b/system/erp-analysis/04-hr-management.md @@ -0,0 +1,381 @@ +# 인사관리 (슬라이드 28-46) + +## 1. 개요 + +인사관리 모듈은 부서, 사원, 근태, 휴가를 관리합니다. + +## 2. 부서관리 (슬라이드 30-31) + +### 2.1 전체 선택 체크박스 +- 클릭: 전체 선택 설정/해제 토글 +- 디폴트: 설정 해제 상태 + +### 2.2 개별 선택 체크박스 +- 클릭: 개별 선택 설정/해제 토글 +- 디폴트: 설정 해제 상태 + +### 2.3 추가 버튼 +- 클릭: 선택된 부서의 하위 부서 일괄 생성 +- 관리 권한이 없을 경우 숨김 + +### 2.4 삭제 버튼 +- 클릭: "선택한 부서 N개를 삭제하시겠습니까?" 확인 Alert 표시 +- 확인 선택 시 삭제된 부서 사원의 인원은 회사(기본) 인원으로 변경 + +### 2.5 확대 버튼 +- 클릭: (6) 확대 버튼으로 변경, 하위 부서 숨김 처리 + +### 2.6 축소 버튼 +- 클릭: (5) 축소 버튼으로 변경, 하위 부서 표시 처리 + +### 2.7 추가 버튼 +- 클릭: 부서 추가 팝업 표시 + +### 2.8 수정 버튼 +- 클릭: 부서 수정 팝업 표시 + +### 2.9 부서 추가/수정 팝업 +- 부서명 인풋박스: 기존 부서명 표시, 수정 가능 + +## 3. 사원관리 (슬라이드 32-40) + +### 3.1 기간 설정 영역 +- 입사일 기준 + +### 3.2 기간 설정 버튼 영역 +- 종류: 당해년도, 전전월, 전월, 당월, 어제, 오늘 +- 클릭: 해당 기간이 (1) 영역에 설정되며 화면 전체에 적용 처리 + +### 3.3 CSV 일괄 등록 버튼 +- 클릭: CSV 일괄 등록 화면으로 이동 + +### 3.4 사원 등록 버튼 +- 클릭: 사원 상세 화면으로 이동 + +### 3.5 사용자 초대 버튼 +- 클릭: 사용자 초대 팝업 표시 + +### 3.6 필터 셀렉트 박스 +- 종류: 전체, 사용자 아이디 보유, 사용자 아이디 미보유, 재직, 휴직, 퇴직 +- 디폴트: 전체 + +### 3.7 정렬 셀렉트 박스 +- 종류: 직급순, 부서 오름차순, 부서 내림차순, 이름 오름차순, 이름 내림차순 +- 디폴트: 직급순 + +### 3.8 현황 카드 +| 항목 | 설명 | +|------|------| +| 현직 | 전체 현직 사원 수 | +| 휴직 | 전체 휴직 사원 수 | +| 퇴직 | (1) 해당 기간의 퇴직 사원 수 | +| 평균근속년수 | 전체 현직 사원 기준 | + +## 4. 사원 상세 (슬라이드 33-36) + +### 4.1 사원 정보 영역 (필수) +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 이름 | Y | | +| 주민등록번호 | Y | | +| 휴대폰 | Y | | +| 이메일 | Y | | +| 연봉 | N | | +| 급여계좌 은행 | N | 은행 선택 | +| 계좌 | N | | +| 예금주 | N | | + +### 4.2 사용자 정보 영역 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 아이디 | N | 이메일 또는 아이디 | +| 비밀번호 | N | 최소 8자 이상 영문+숫자+특수문자 조합 | +| 권한 | N | 권한관리의 목록 표시 | +| 상태 | N | 종류: 정상, 재직, 중지. 재직 상태인 경우 로그아웃 처리, 로그인 시 '재정중인 아이디입니다.' 팝업 | + +### 4.3 사원 상세 영역 (선택) +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 프로필 사진 | N | 1250x250px, 10MB 이하 PNG, JPEG, GIF | +| 사원코드 | N | | +| 성별 | N | 남성/여성 | +| 주소 | N | 우편번호 찾기 + 상세주소 | + +### 4.4 인사 정보 영역 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 입사일 | N | | +| 고용 형태 | N | 종류: 정규직, 계약직, 파견직, 용역직, 시간제 근로자 | +| 직급 | N | 직급관리 화면에서 설정 | +| 상태 | N | 종류: 재직, 병가휴직, 육아휴직, 개인사정휴직, 무급휴직, 퇴사, 해고, 권고사직, 계약만료, 정년퇴직 | +| 부서 | N | 부서관리 화면에서 설정 | +| 직책 | N | 직책관리 화면에서 설정 | +| 출근 위치 | N | 본사, 현장 목록 | +| 퇴근 위치 | N | 본사, 현장 목록 | +| 퇴사일 | N | | +| 퇴사 사유 | N | | + +### 4.5 항목 설정 버튼 +- 클릭: 항목 설정 팝업 표시 + +### 4.6 항목 설정 팝업 (슬라이드 34) +- 전체 설정 ON/OFF 버튼 +- 개별 설정 ON/OFF 버튼 +- 디폴트: 설정 OFF 상태 + +## 5. CSV 일괄 등록 (슬라이드 39-40) + +### 5.1 양식 다운로드 버튼 +- 클릭: 등록된 양식 CSV 다운로드 + +### 5.2 파일 선택 버튼 +- 클릭: 파일 탐색기 팝업, CSV 1개만 등록 + +### 5.3 파일 변환 버튼 +- 클릭: CSV 데이터를 (3-1) 정보 등록 영역에 변환값 표시 +- 범위: 사원 상세 화면의 전체 항목 + +### 5.4 등록 버튼 +- 파일변환 완료 & (2) 체크 설정 항목 있을 경우에만 버튼 활성화 +- 클릭: "(등록)의 정보를 정말 등록하시겠습니까?" 확인 Alert 표시 +- 확인 클릭 시 (2) 체크 된 정보만 등록, "정보 등록이 완료되었습니다." 알림 Alert 표시 + +## 6. 사용자 초대 (슬라이드 37-38) + +### 6.1 사용자 초대 프로세스 +- 초대 이메일로 발송 → 약관 동의 (아이디를 이메일로 사용) → 비밀번호 설정 → 로그인 + +### 6.2 초대할 이메일 주소 인풋박스 +- ','로 구분하여 여러 주소 입력 가능 + +### 6.3 권한 셀렉트 박스, 검색 +- 종류: 권한관리의 목록 표시 + +### 6.4 초대 메시지 인풋박스 + +### 6.5 초대 버튼 +- 클릭: 사용자 초대 이메일 발송 +- 이메일 주소 기준 사원 정보가 있을 경우에는 대량하여 사용자 등록 처리 +- 없을 경우에는 사용자에만 등록하고 나머지 사원 정보는 직접 입력 필요 +- 사용자 아이디 중복 불가 + +## 7. 근태관리 (슬라이드 41-42) + +### 7.1 근태관리 현황 카드 +| 항목 | 설명 | +|------|------| +| 정시 출근 | 전체 정시 출근 수 | +| 지각 | 전체 지각 수 | +| 결근 | 전체 결근 수 | +| 휴가 | 전체 휴가 수 | + +### 7.2 기간 설정 버튼 영역 +- 종류: 당해년도, 전전월, 전월, 당월, 어제, 오늘 +- 클릭: 해당 기간이 설정되며 화면 전체에 적용 처리 +- 근태관리 자동 설정 시: 모든 사원이 정시 출퇴근한 것으로 기록, 예외사항만 경우 작성 + +### 7.3 근태 등록 버튼 +- 클릭: 근태 정보 팝업 표시 + +### 7.4 사유 등록 버튼 +- 클릭: 사유 정보 팝업 표시 + +### 7.5 필터 셀렉트 박스 +- 종류: 전체, 정시 출근, 지각, 결근, 휴가, 출장, 외근, 연장근무 +- 디폴트: 전체 + +### 7.6 정렬 셀렉트 박스 +- 종류: 직급순, 부서 오름차순, 부서 내림차순, 이름 오름차순, 이름 내림차순 +- 디폴트: 직급순 + +### 7.7 근태 정보 팝업 +| 필드명 | 설명 | +|--------|------| +| 대상 | 사원 셀렉트 박스, 검색&다중 선택 | +| 기준일 | 달력 팝업 표시, 일자 다중 선택 가능, 디폴트: 당일 | +| 출근 시간 | 시/분 선택 | +| 퇴근 시간 | 시/분 선택 | +| 야간 연장 시간 | 주당 연장 근로 시간에서 주말 연장 시간을 차감한 이내에만 설정 가능 | +| 주말 연장 시간 | 주당 연장 근로 시간에서 야간 연장 시간을 차감한 이내에만 설정 가능 | + +### 7.8 사유 정보 팝업 +| 필드명 | 설명 | +|--------|------| +| 대상 | 사원 셀렉트 박스 | +| 기준일 | 달력 팝업 | +| 내용 | 내용 입력 | + +## 8. 휴가관리 (슬라이드 43-46) + +### 8.1 휴가관리 탭 +- 휴가 사용 현황 +- 휴가 부여 현황 +- 휴가 신청 현황 + +### 8.2 휴가관리 현황 카드 +| 항목 | 설명 | +|------|------| +| 휴가 승인 대기 | | +| 연차 | 전체 연차 사원 수 | +| 결조사 | | +| 연간 연차 사용률 | | + +### 8.3 필터 셀렉트 박스 +- 종류: 전체, 모든 사원 목록 +- 항목: 부서명, 직급명, 사원명 표시 +- 디폴트: 전체 + +### 8.4 정렬 셀렉트 박스 +- 종류: 직급순, 부서 오름차순, 부서 내림차순, 이름 오름차순, 이름 내림차순 +- 디폴트: 직급순 + +### 8.5 휴가 부여 팝업 +| 필드명 | 설명 | +|--------|------| +| 유형 | 종류: 연차, 보상, 경조, 보건, 병가, 반차, 반수 선택 | +| 사유 | | +| 일수 | 개월/일/시간 선택 | + +### 8.6 휴가 신청 팝업 +| 필드명 | 설명 | +|--------|------| +| 잔여 | 잔여 일수 표시 | +| 유형 | 종류: 연차, 보상, 경조, 보건, 병가, 반차 | +| 기간 | 날짜 선택, (5) 반차 선택 시에는 시간으로 변경 | + +### 8.7 휴가 신청 현황 필터 +- 종류: 승인, 거절 +- 1/3 완료: 결재선 승인 진행도에 따라 표시 + +--- + +## 데이터 모델 + +### Department (부서) +``` +- id: bigint +- tenant_id: bigint (FK) +- parent_id: bigint (FK, nullable) +- name: string +- order: int +- is_active: boolean +- created_at: timestamp +``` + +### Employee (사원) +``` +- id: bigint +- tenant_id: bigint (FK) +- user_id: bigint (FK, nullable) +- department_id: bigint (FK, nullable) +- employee_code: string +- name: string +- resident_number: string (encrypted) +- phone: string +- email: string +- salary: decimal +- bank_code: string +- account_number: string +- account_holder: string +- profile_image: string +- gender: enum('male', 'female') +- address: string +- hire_date: date +- employment_type: enum('regular', 'contract', 'dispatch', 'service', 'part_time') +- position_id: bigint (FK) +- job_title_id: bigint (FK) +- status: enum('active', 'leave', 'sick_leave', 'parental_leave', 'personal_leave', 'unpaid_leave', 'resigned', 'dismissed', 'recommended_resignation', 'contract_expired', 'retired') +- check_in_location_id: bigint (FK, nullable) +- check_out_location_id: bigint (FK, nullable) +- resignation_date: date +- resignation_reason: text +- created_at: timestamp +``` + +### AttendanceRecord (근태 기록) +``` +- id: bigint +- tenant_id: bigint (FK) +- employee_id: bigint (FK) +- date: date +- check_in_time: time +- check_out_time: time +- status: enum('on_time', 'late', 'absent', 'leave', 'business_trip', 'outside_work', 'overtime') +- night_overtime_hours: decimal +- weekend_overtime_hours: decimal +- reason: text +- created_at: timestamp +``` + +### Leave (휴가) +``` +- id: bigint +- tenant_id: bigint (FK) +- employee_id: bigint (FK) +- type: enum('annual', 'reward', 'congratulation', 'health', 'sick', 'half_day', 'half_day_am', 'half_day_pm') +- start_date: date +- end_date: date +- days: decimal +- reason: text +- status: enum('pending', 'approved', 'rejected') +- created_at: timestamp +``` + +### LeaveBalance (휴가 잔여) +``` +- id: bigint +- tenant_id: bigint (FK) +- employee_id: bigint (FK) +- year: int +- type: enum('annual', 'reward', ...) +- granted: decimal +- used: decimal +- remaining: decimal +``` + +--- + +## API 도출 + +### 부서관리 API +``` +GET /api/departments # 부서 목록 (트리 구조) +POST /api/departments # 부서 추가 +PUT /api/departments/{id} # 부서 수정 +DELETE /api/departments/{id} # 부서 삭제 +DELETE /api/departments/bulk # 부서 일괄 삭제 +``` + +### 사원관리 API +``` +GET /api/employees # 사원 목록 +POST /api/employees # 사원 등록 +GET /api/employees/{id} # 사원 상세 +PUT /api/employees/{id} # 사원 수정 +DELETE /api/employees/{id} # 사원 삭제 +POST /api/employees/import # CSV 일괄 등록 +GET /api/employees/template # CSV 템플릿 다운로드 +POST /api/employees/invite # 사용자 초대 +``` + +### 근태관리 API +``` +GET /api/attendance # 근태 목록 +POST /api/attendance # 근태 등록 +PUT /api/attendance/{id} # 근태 수정 +GET /api/attendance/summary # 근태 현황 요약 +POST /api/attendance/reason # 사유 등록 +``` + +### 휴가관리 API +``` +GET /api/leaves # 휴가 목록 +POST /api/leaves # 휴가 신청 +PUT /api/leaves/{id} # 휴가 수정 +DELETE /api/leaves/{id} # 휴가 취소 +POST /api/leaves/{id}/approve # 휴가 승인 +POST /api/leaves/{id}/reject # 휴가 거절 +GET /api/leaves/balance/{employee_id} # 휴가 잔여 조회 +POST /api/leaves/grant # 휴가 부여 +GET /api/leaves/summary # 휴가 현황 요약 +``` \ No newline at end of file diff --git a/system/erp-analysis/05-approval.md b/system/erp-analysis/05-approval.md new file mode 100644 index 0000000..5f31d96 --- /dev/null +++ b/system/erp-analysis/05-approval.md @@ -0,0 +1,296 @@ +# 전자결재 (슬라이드 47-59) + +## 1. 개요 + +전자결재 모듈은 기안함, 결재함, 참조함으로 구성되며, 품의서, 지출결의서, 지출 예상 내역서 등의 문서를 처리합니다. + +## 2. 기안함 (슬라이드 48-54) + +### 2.1 문서 상태 +| 상태 | 설명 | +|------|------| +| 임시저장 | 문서 작성 중, 임시저장된 상태 | +| 진행 | 모든 결재자 중 일부 승인된 상태, 결재 요청을 받은 상태 | +| 결재요청 | 결재 요청을 받은 상태 | +| 반려 | 결재자 중 반려한 사람이 있는 상태 | + +### 2.2 기안함 현황 카드 +| 항목 | 설명 | +|------|------| +| 진행 | 진행 중인 문서 수 | +| 전체 | 전체 문서 수 | +| 반려 | 반려된 문서 수 | +| 임시 저장 | 임시저장 문서 수 | + +### 2.3 문서 작성 버튼 +- 클릭: 문서 작성 화면으로 이동 + +### 2.4 상세 버튼 +- 클릭: 문서 상세 팝업 표시 + +### 2.5 삭제 버튼 +- 클릭: + 1) 임시저장 상태일 경우: "정말 이(1)건을 삭제 처리하시겠습니까?" 확인 Alert 표시, 확인 시 해당 문서 삭제 처리 + 2) 임시저장 상태가 아닐 경우: "임시저장 상태만 삭제가 가능합니다." 알림 Alert 표시 + +### 2.6 수정 버튼 +- 클릭: + 1) 임시저장 상태일 경우: 문서 작성 화면으로 이동 + 2) 임시저장 상태가 아닐 경우: 문서 상세 팝업 표시 + +### 2.7 필터 셀렉트 박스 +- 종류: 전체, 임시저장, 진행, 완료, 반려 +- 디폴트: 전체 + +### 2.8 정렬 셀렉트 박스 +- 종류: 최신순, 등록순 +- 디폴트: 최신순 + +## 3. 문서 작성 (슬라이드 49-54) + +### 3.1 상세 버튼 +- 클릭: 문서 상세 팝업 표시 + +### 3.2 문서 유형 셀렉트 박스, 검색 +- 종류: 품의서, 지출결의서, 지출 예상 내역서 +- 선택한 문서 유형의 화면으로 변경 표시 + +### 3.3 결재자 셀렉트 박스, 검색&다중 선택 +- 항목: 부서명, 직책명, 사원명 표시 +- 종류: 전체, 모든 사원 목록 +- 디폴트: 전체 + +### 3.4 참조자 셀렉트 박스, 검색&다중 선택 +- 항목: 부서명, 직책명, 사원명 표시 +- 종류: 전체, 모든 사원 목록 +- 디폴트: 전체 + +### 3.5 버튼 영역 +| 버튼 | 설명 | +|------|------| +| 상세 | 문서 상세 팝업 표시 | +| 삭제 | 임시저장 상태만 삭제 가능 | +| 삼신 | 결재선 마감 경우 숨김 | +| 임시저장 | 임시저장 처리 | + +## 4. 품의서 (슬라이드 50) + +### 4.1 구매처 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 구매처 | Y | | +| 구매처 결제일 | Y | | + +### 4.2 품의서 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 제목 | Y | | +| 품의 내역 | Y | 녹음 버튼: 마이크 사용 가능할 경우에만 버튼 활성화, 녹음 중지 버튼으로 변경, 음성 내용을 텍스트로 변경하여 (1-1) 인풋박스 영역에 표시 | +| 품의 사유 | Y | | +| 예상 비용 | Y | | + +### 4.3 참고 이미지 정보 +- 첨부파일 찾기 + +## 5. 지출결의서 (슬라이드 51-52) + +### 5.1 지출 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 지출 요청일 | Y | | +| 결제일 | Y | | + +### 5.2 지출결의서 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 적요 | Y | | +| 금액 | Y | | +| 비고 | N | | + +### 5.3 결제 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 카드 | Y | 종류: 등록된 카드 목록, 디폴트: 첫번째 카드 | +| 총 비용 | - | 지출결의서 정보의 금액 합계 표시 | + +### 5.4 참고 이미지 정보 +- 첨부파일 찾기 + +## 6. 지출 예상 내역서 (슬라이드 53-54) + +### 6.1 지출 예상 내역서 목록 +- 체크 설정/해제 토글 +- 1) 지출 예상 내역서 화면에서 찾을 경우: 설정된 체크 상태 유지 +- 2) 문서 작성 화면에서 설정했을 경우: 모든 체크 항목 설정된 상태 + +### 6.2 항목 +| 필드명 | 설명 | +|--------|------| +| 예상 지급일 | | +| 품목 | | +| 지출금액 | | +| 거래처 | | +| 계좌 | | + +### 6.3 합계 +| 항목 | 설명 | +|------|------| +| 지출 합계 | | +| 계좌 잔액 | | +| 최종 차액 | | + +## 7. 결재함 (슬라이드 55-58) + +### 7.1 상태 +| 상태 | 설명 | +|------|------| +| 진행 | 결재 하위 상태 | +| 예정 | 결재 순번에 의한 대기 | +| 결재요청 | 결재 요청을 받은 상태 | + +### 7.2 결재함 현황 카드 +| 항목 | 설명 | +|------|------| +| 결재 요청 | 결재 요청 문서 수 | +| 완료 | 완료 문서 수 | +| 반려 | 반려 문서 수 | +| 예정 | 예정 문서 수 | + +### 7.3 승인 버튼 +- 클릭: "정말 (1)건을 승인하시겠습니까?" 확인 Alert 표시 +- 확인 버튼 클릭 시 "승인이 완료되었습니다." 알림 Alert 표시 + +### 7.4 반려 버튼 +- 클릭: "정말 (1)건을 반려하시겠습니까?" 확인 Alert 표시 +- 확인 버튼 클릭 시 "반려가 완료되었습니다." 알림 Alert 표시 + +### 7.5 필터 셀렉트 박스 +- 종류: 전체, 결재 요청, 예정, 완료, 반려 +- 1/3 완료: 결재선 승인 진행도에 따라 표시 +- 디폴트: 전체 + +### 7.6 수정 버튼 +- 클릭: 문서 상세 팝업 표시 + +## 8. 참조함 (슬라이드 59) + +### 8.1 열람 버튼 +- 클릭: "정말 (1)건을 열람 처리하시겠습니까?" 확인 Alert 표시 +- 확인 버튼 클릭 시 "열람 처리가 완료되었습니다." 알림 Alert 표시 + +### 8.2 미열람 버튼 +- 클릭: "정말 (1)건을 미열람 처리하시겠습니까?" 확인 Alert 표시 +- 확인 버튼 클릭 시 "미열람 처리가 완료되었습니다." 알림 Alert 표시 + +### 8.3 필터 셀렉트 박스 +- 종류: 전체, 열람, 미열람 +- 디폴트: 전체 + +## 9. 문서 상세 팝업 (슬라이드 56-58) + +### 9.1 버튼 영역 +| 버튼 | 설명 | +|------|------| +| 복제 | 문서 작성 화면으로 이동 (새글) | +| 수정 | 결재선 중에서는 누구나 수정 가능, 해당 문서 작성 화면으로 이동 | +| 반려 | 결재선 마감 경우 숨김 | +| 승인 | 결재선 마감 경우 숨김 | +| 인쇄 | | +| 공유 | (5-1) 팝업 표시 | +| 닫기 | | + +### 9.2 결재선 영역 +- 승인/반려 시 해당 아이콘 표시 + +### 9.3 공유 버튼 +| 공유 방식 | 설명 | +|-----------|------| +| PDF | | +| 이메일 | | +| 카카오톡 | | + +--- + +## 데이터 모델 + +### ApprovalDocument (결재 문서) +``` +- id: bigint +- tenant_id: bigint (FK) +- document_number: string +- document_type: enum('request', 'expense', 'expense_estimate') +- title: string +- status: enum('draft', 'pending', 'in_progress', 'approved', 'rejected') +- drafter_id: bigint (FK) # 기안자 +- content: json # 문서 내용 +- attachments: json +- created_at: timestamp +- submitted_at: timestamp +``` + +### ApprovalLine (결재선) +``` +- id: bigint +- document_id: bigint (FK) +- approver_id: bigint (FK) +- order: int +- status: enum('pending', 'approved', 'rejected') +- comment: text +- approved_at: timestamp +``` + +### ApprovalReference (참조자) +``` +- id: bigint +- document_id: bigint (FK) +- referee_id: bigint (FK) +- is_read: boolean +- read_at: timestamp +``` + +### ExpenseItem (지출 항목) +``` +- id: bigint +- document_id: bigint (FK) +- description: string +- amount: decimal +- note: text +``` + +--- + +## API 도출 + +### 기안함 API +``` +GET /api/approvals/drafts # 기안 목록 +POST /api/approvals # 문서 작성 +PUT /api/approvals/{id} # 문서 수정 +DELETE /api/approvals/{id} # 문서 삭제 +POST /api/approvals/{id}/submit # 문서 제출 (결재 요청) +POST /api/approvals/{id}/save-draft # 임시저장 +GET /api/approvals/{id} # 문서 상세 +GET /api/approvals/drafts/summary # 기안함 현황 +``` + +### 결재함 API +``` +GET /api/approvals/inbox # 결재함 목록 +POST /api/approvals/{id}/approve # 승인 +POST /api/approvals/{id}/reject # 반려 +GET /api/approvals/inbox/summary # 결재함 현황 +``` + +### 참조함 API +``` +GET /api/approvals/references # 참조함 목록 +POST /api/approvals/{id}/mark-read # 열람 처리 +POST /api/approvals/{id}/mark-unread # 미열람 처리 +``` + +### 문서 공유 API +``` +GET /api/approvals/{id}/pdf # PDF 다운로드 +POST /api/approvals/{id}/share/email # 이메일 공유 +POST /api/approvals/{id}/share/kakao # 카카오톡 공유 +``` \ No newline at end of file diff --git a/system/erp-analysis/06-accounting.md b/system/erp-analysis/06-accounting.md new file mode 100644 index 0000000..abe4c9d --- /dev/null +++ b/system/erp-analysis/06-accounting.md @@ -0,0 +1,427 @@ +# 회계관리 (슬라이드 60-91) + +## 1. 개요 + +회계관리 모듈은 거래처, 매출, 매입, 입금, 출금, 어음, 거래처원장, 미수금 현황, 입출금 계좌 조회 등을 관리합니다. + +## 2. 회계관리 플로우차트 (슬라이드 61) + +### 2.1 매출 플로우 +``` +거래처 선택 → 매출 등록 → 세금계산서 발행 +``` + +### 2.2 입금 플로우 +``` +입금 등록 → 전액 입금? → 어음 수취? + ↓ ↓ + 입출금 계좌 조회 어음관리 +``` + +### 2.3 매입 플로우 +``` +거래처 선택 → 매입 등록 → 세금계산서 수취 +``` + +### 2.4 출금 플로우 +``` +출금 등록 → 전액 출금? → 어음 발행? + ↓ ↓ + 입출금 계좌 조회 어음관리 +``` + +### 2.5 추심 플로우 +``` +미수금 현황 → 연체? → 악성주심? → 악성 추심 + ↓ + 미지급 알림 +``` + +### 2.6 조회 +- 입출금 계좌 조회 +- 카드 내역 조회 + +### 2.7 장부/보고서 +- 거래처원장 +- 지출 예상 내역서 +- 일일 일보 + +## 3. 거래처관리 (슬라이드 62-65) + +### 3.1 현황 카드 +| 항목 | 설명 | +|------|------| +| 전체 거래처 | | +| 매출 거래처 | | +| 매입 거래처 | | + +### 3.2 삭제 버튼 +- 관리 권한이 없을 경우 숨김 +- 클릭: "선택한 거래처 N개를 삭제하시겠습니까?" 확인 Alert 표시 +- 확인 선택 시 삭제 + +### 3.3 구분 필터 셀렉트 박스 +- 종류: 전체, 매출, 매입, 매입매출 +- 디폴트: 전체 + +### 3.4 신용등급 필터 셀렉트 박스 +- 종류: 전체, AAA, AA, A, BBB, BB, B, CCC, CC, C, D +- 디폴트: 전체 + +### 3.5 거래등급 필터 셀렉트 박스 +- 종류: 전체, A(우수), B(양호), C(보통), D(주의), E(위험) +- 디폴트: 전체 + +### 3.6 약정체결 필터 셀렉트 박스 +- 종류: 전체, 약정체결, 정상 +- 디폴트: 전체 + +### 3.7 정렬 셀렉트 박스 +- 종류: 최신순, 등록순, 거래처명 오름차순, 거래처명 내림차순, 미수금 높은순, 미수금 낮은순 +- 디폴트: 최신순 + +## 4. 거래처 상세 (슬라이드 63-65) + +### 4.1 기본 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 사업자등록번호 | Y | | +| 거래처 코드 | N | | +| 거래처명 | Y | | +| 대표자명 | Y | | +| 거래처 유형 | Y | 매출매입 선택 | +| 업태 | N | | +| 업종 | N | | + +### 4.2 연락처 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 주소 | N | 우편번호 찾기 + 상세주소 | +| 전화번호 | N | | +| 모바일 | N | | +| 팩스 | N | | +| 이메일 | N | | + +### 4.3 담당자 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 담당자명 | N | | +| 담당자 전화 | N | | + +### 4.4 시스템 관리자 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 관리자명 | N | | + +### 4.5 회사 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 회사 로고 | N | 750x250px, 10MB 이하 PNG, JPEG, GIF | + +### 4.6 결제 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 매입 결제일 | N | 종류: 1일~31일, 말일. 디폴트: 10일. 거래처 유형이 '매입' 또는 '매입매출'일 경우 해당 | +| 매출 결제일 | N | 종류: 1일~31일, 말일. 디폴트: 15일. 거래처 유형이 '매출' 또는 '매입매출'일 경우 표시 | + +### 4.7 신용 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 신용등급 | N | 외부 신용평가 등급 표시. 예: AAA, AA, A, BBB, BB, B, CCC, CC, C, D | +| 거래등급 | N | 종류: A(우수), B(양호), C(보통), D(주의), E(위험). 디폴트: A(우수). 자사 기준 거래처 평가 등급 | + +### 4.8 계좌 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 세금계산서 이메일 | N | | +| 입금계좌 은행 | N | 은행 선택 | +| 계좌 | N | | +| 예금주 | N | | + +### 4.9 추가 정보 +| 필드명 | 설명 | +|--------|------| +| 미수금 | 해당 거래처의 현재 미수금 잠게 표시. 읽기 전용 | +| 연체 | - ON: 연체 상태로 표시, 연체일수 표시 | +| | - OFF: 정상 상태 | +| | - 거래처 상세에서 연체 설정과 연동 | +| | - (4-1) 연체 등록 이후부터 경과일 표시 | +| 미지급 | 해당 거래처에 대한 미지급금 잠게 표시. 읽기 전용 | +| 악성채권 | - ON: 악성채권으로 등록, 악성채권 추심관리 목록에 표시 | +| | - OFF: 정상 상태 | +| | - 디폴트: OFF | +| 메모 | 추가 버튼 클릭 시 목록 최상단에 추가 | + +## 5. 매출관리 (슬라이드 66-71) + +### 5.1 매출 유형 +- 필드 매출 시 매출 직접 등록 (삭제 가능) +- 필드 매출: 용역 매출, 공사 매출, 임대 수익, 기타 매출 + +### 5.2 매출 상세 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 매출번호 | - | 자동 채번 | +| 매출일 | Y | | +| 거래처명 | Y | 거래처 선택 | +| 매출 유형 | Y | 선택 | + +### 5.3 품목 정보 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 품목명 | Y | | +| 수량 | Y | | +| 단가 | Y | | +| 공급가액 | - | 자동 계산 | +| 부가세 | - | 자동 계산 | +| 적요 | N | | + +### 5.4 세금계산서 +| 필드명 | 설명 | +|--------|------| +| 세금계산서 발행 | 토글 | + +### 5.5 거래명세서 +| 필드명 | 설명 | +|--------|------| +| 거래명세서 | 토글 | + +## 6. 입금관리 (슬라이드 74-76) + +### 6.1 입금 유형 +- 종류: 매출대금, 선수금, 가수금, 입대수익, 미자수익, 보증금 반환, 차입금, 자본금, 부가세 환급, 기타, 미상정 + +### 6.2 입금 상세 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 입금일 | Y | | +| 입금계좌 | Y | 국민은행 1234 (계좌명) | +| 입금자명 | Y | | +| 입금금액 | Y | | +| 적요 | N | | +| 거래처 | N | 선택 | +| 입금 유형 | Y | | + +## 7. 출금관리 (슬라이드 77-79) + +### 7.1 출금 유형 +- 종류: 매입대금, 선급금, 가지급금, 임대비용, 보증금 지급, 차입금 상환, 배당금 지급, 세금, 공과금, 경비, 4대보험, 급여 + +### 7.2 출금 상세 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 출금일 | Y | | +| 출금계좌 | Y | | +| 받는 분 | Y | | +| 출금금액 | Y | | +| 적요 | N | | +| 거래처 | N | | +| 출금 유형 | Y | | + +## 8. 거래처원장 (슬라이드 80) + +### 8.1 현황 카드 +| 항목 | 설명 | +|------|------| +| 전기 이월 | | +| 매출 | | +| 수금 | | +| 잔액 | | + +### 8.2 거래처원장 목록 +- 거래처별 기간별 합계 금액 표시 +- 클릭: 거래처원장 상세 화면으로 이동 + +### 8.3 엑셀 다운로드 버튼 +- 클릭: 엑셀 파일 다운로드 + +## 9. 미수금 현황 (슬라이드 85) + +### 9.1 미수금 현황 목록 +- 거래처별 월별 미수금 현황 (매출, 입금, 어음, 미수금, 메모) + +### 9.2 수취 어음 등록 시 표시 +- 회계에는 미반영 + +### 9.3 연체 표시 +- ON: 연체 상태로 표시, 연체일수 표시 +- OFF: 정상 상태 +- 거래처 상세에서 연체 설정과 연동 + +### 9.4 엑셀 다운로드 버튼 + +### 9.5 저장 버튼 + +## 10. 입출금 계좌 조회 (슬라이드 90) + +### 10.1 설명 +- 기준 정보 > 계좌 관리에 등록된 계좌의 자동 입출금 내역 수집 + +### 10.2 새로고침 버튼 +- 클릭: 은행 계좌 입출금 내역 최신 데이터 조회 +- 바로빌 API 연동 시 실시간 조회 + +### 10.3 구분 필터 셀렉트 박스 +- 종류: 전체, 출금, 입금 +- 디폴트: 전체 + +### 10.4 계정과목 필터 셀렉트 박스, 검색&다중 선택 +- (2) 선택에 따른 계정과목 목록 표시 +- 입금 종류: 전체, 매출대금, 선수금, 가수금, 임대수익, 이자수익, 보증금 반환, 차입금, 자본금, 부가세 환급, 기타, 미상정 +- 출금 종류: 전체, 매입대금, 선급금, 가지급금, 임대비용, 이자비용, 보증금 지급, 차입금 상환, 배당금 지급, 세금, 공과금, 경비, 4대보험, 급여 +- 디폴트: 전체 + +### 10.5 정렬 셀렉트 박스 +- 종류: 최신순, 등록순, 금액순 +- 디폴트: 최신순 + +### 10.6 수정 버튼 +- 클릭: 해당 입금/출금 상세 화면으로 이동 + +--- + +## 데이터 모델 + +### Vendor (거래처) +``` +- id: bigint +- tenant_id: bigint (FK) +- business_number: string +- vendor_code: string +- name: string +- representative: string +- type: enum('sales', 'purchase', 'both') +- business_type: string +- business_category: string +- address: string +- phone: string +- mobile: string +- fax: string +- email: string +- manager_name: string +- manager_phone: string +- logo: string +- purchase_payment_day: int +- sales_payment_day: int +- credit_rating: enum('AAA', 'AA', 'A', 'BBB', 'BB', 'B', 'CCC', 'CC', 'C', 'D') +- trade_rating: enum('A', 'B', 'C', 'D', 'E') +- tax_invoice_email: string +- bank_code: string +- account_number: string +- account_holder: string +- is_overdue: boolean +- overdue_start_date: date +- is_bad_debt: boolean +- notes: json +- created_at: timestamp +``` + +### Sales (매출) +``` +- id: bigint +- tenant_id: bigint (FK) +- vendor_id: bigint (FK) +- sales_number: string +- sales_date: date +- sales_type: enum('product', 'service', 'construction', 'rental', 'other') +- total_amount: decimal +- tax_amount: decimal +- is_tax_invoice_issued: boolean +- is_statement_issued: boolean +- created_at: timestamp +``` + +### SalesItem (매출 품목) +``` +- id: bigint +- sales_id: bigint (FK) +- item_name: string +- quantity: int +- unit_price: decimal +- supply_amount: decimal +- tax_amount: decimal +- description: string +``` + +### Deposit (입금) +``` +- id: bigint +- tenant_id: bigint (FK) +- vendor_id: bigint (FK, nullable) +- account_id: bigint (FK) +- deposit_date: date +- depositor_name: string +- amount: decimal +- description: string +- deposit_type: enum('sales', 'advance', 'suspense', 'rental', 'interest', 'deposit_return', 'loan', 'capital', 'vat_refund', 'other', 'unidentified') +- created_at: timestamp +``` + +### Withdrawal (출금) +``` +- id: bigint +- tenant_id: bigint (FK) +- vendor_id: bigint (FK, nullable) +- account_id: bigint (FK) +- withdrawal_date: date +- recipient_name: string +- amount: decimal +- description: string +- withdrawal_type: enum('purchase', 'advance', 'suspense', 'rental', 'interest', 'deposit', 'loan_repayment', 'dividend', 'tax', 'utility', 'expense', 'insurance', 'salary') +- created_at: timestamp +``` + +--- + +## API 도출 + +### 거래처 API +``` +GET /api/vendors # 거래처 목록 +POST /api/vendors # 거래처 등록 +GET /api/vendors/{id} # 거래처 상세 +PUT /api/vendors/{id} # 거래처 수정 +DELETE /api/vendors/{id} # 거래처 삭제 +DELETE /api/vendors/bulk # 거래처 일괄 삭제 +GET /api/vendors/summary # 거래처 현황 +``` + +### 매출 API +``` +GET /api/sales # 매출 목록 +POST /api/sales # 매출 등록 +GET /api/sales/{id} # 매출 상세 +PUT /api/sales/{id} # 매출 수정 +DELETE /api/sales/{id} # 매출 삭제 +POST /api/sales/{id}/tax-invoice # 세금계산서 발행 +GET /api/sales/summary # 매출 현황 +``` + +### 입금 API +``` +GET /api/deposits # 입금 목록 +POST /api/deposits # 입금 등록 +GET /api/deposits/{id} # 입금 상세 +PUT /api/deposits/{id} # 입금 수정 +DELETE /api/deposits/{id} # 입금 삭제 +``` + +### 출금 API +``` +GET /api/withdrawals # 출금 목록 +POST /api/withdrawals # 출금 등록 +GET /api/withdrawals/{id} # 출금 상세 +PUT /api/withdrawals/{id} # 출금 수정 +DELETE /api/withdrawals/{id} # 출금 삭제 +``` + +### 장부/보고서 API +``` +GET /api/ledger/vendor # 거래처원장 +GET /api/ledger/vendor/{vendor_id} # 거래처원장 상세 +GET /api/ledger/vendor/export # 거래처원장 엑셀 다운로드 +GET /api/receivables # 미수금 현황 +GET /api/receivables/export # 미수금 현황 엑셀 다운로드 +GET /api/bank-transactions # 입출금 계좌 조회 +POST /api/bank-transactions/sync # 입출금 내역 동기화 +``` \ No newline at end of file diff --git a/system/erp-analysis/07-master-data.md b/system/erp-analysis/07-master-data.md new file mode 100644 index 0000000..daa9182 --- /dev/null +++ b/system/erp-analysis/07-master-data.md @@ -0,0 +1,332 @@ +# 기준정보 (슬라이드 92-104) + +## 1. 개요 + +기준정보 모듈은 직급, 직책, 권한, 근무, 출퇴근, 휴가, 카드, 계좌, 팝업, 게시판, 일반설정, 알림설정을 관리합니다. + +## 2. 직급관리 (슬라이드 93, 95) + +### 2.1 직급 인풋박스 +- 직급 입력 후 추가 버튼 클릭 + +### 2.2 추가 버튼 +- 클릭: (2-1) 직급 목록 최하단에 표시 + +### 2.3 직급 목록 +- 디폴트: 사원, 대리, 과장, 차장, 부장, 이사, 상무, 전무, 부사장, 사장 + +### 2.4 순서 변경 버튼 +- 드래그&드랍: 해당 위치로 순서 변경 + +### 2.5 수정 버튼 +- 클릭: 직급 수정 팝업 표시 + +### 2.6 삭제 버튼 +- 클릭: + 1) 해당 직급으로 사원 설정된 경우: "'직급명'을 사용하고 있는 사원이 있습니다. 다 변경 후 삭제가 가능합니다." 알림 Alert 표시 + 2) 해당 직급으로 사원 미설정된 경우: "정말 삭제하시겠습니까?" 확인 Alert 표시, 확인 클릭 시 "삭제가 완료되었습니다." 알림 Alert 표시 + +### 2.7 직급 수정 팝업 +- 직급명 인풋박스: 기존 직급명 표시, 수정 가능 + +## 3. 직책관리 (슬라이드 94-95) + +### 3.1 기능 +- 직급관리와 동일한 구조 + +### 3.2 디폴트 직책 +- (없음) + +### 3.3 직책 수정 팝업 +- 직책명 인풋박스: 기존 직책명 표시, 수정 가능 + +## 4. 권한관리 (슬라이드 96) + +### 4.1 관리자 +- 디폴트: 모든 메뉴 권한 설정 +- 수정 불가, 삭제 불가 + +### 4.2 일반 +- 디폴트: 대시보드 제외 모든 메뉴 접근 불가 + +### 4.3 추가 버튼 +- 클릭: 권한 추가 팝업 표시 + +### 4.4 삭제 버튼 +- 클릭: + 1) 해당 권한으로 사원 설정된 경우: "'권한명'을 사용하고 있는 사원이 있습니다. 다 변경 후 삭제가 가능합니다." 알림 Alert 표시 + 2) 해당 권한으로 사원 미설정된 경우: "정말 삭제하시겠습니까?" 확인 Alert 표시 + +### 4.5 체크박스 +- 클릭: 체크 설정/해제 토글 +- 디폴트: 체크 해제 상태 + +### 4.6 관리 +- 읽기 및 수정 권한 + +### 4.7 읽기 +- 읽기만 권한 + +## 5. 근무관리 (슬라이드 97) + +### 5.1 근무 정보 +| 필드명 | 설명 | +|--------|------| +| 근무 유형 | 종류: 고정형, 변형, 맞춤형 | +| 기본 소정 근로 시간 | 주 00시간 | +| 연장 근로 시간 | 주 00시간 | +| 연장 근로 한도 | 52시간 미만 | +| 근무 요일 설정 | 클릭: 설정된 체크 활성/비활성 토글, 디폴트: 월~금 활성 | + +### 5.2 출근 시간 +- 09:00 + +### 5.3 퇴근 시간 +- 18:00 + +### 5.4 휴게 시간 +| 필드명 | 설명 | +|--------|------| +| 총 휴게 시간 | 1시간 | +| 휴게 시간 | 12:00 ~ 13:00 | + +## 6. 출퇴근관리 (슬라이드 99) + +### 6.1 출퇴근 설정 +| 필드명 | 설명 | +|--------|------| +| GPS 출퇴근 | 토글: 기준 좌표로 정해진 거리 기준 이내에 있을 때만 출근/퇴근 등록 가능 | +| 허용 반경 | 주 00m | + +### 6.2 본사 위치 정보 +| 필드명 | 설명 | +|--------|------| +| 본사 주소 | 우편번호 찾기 + 상세주소 | +| 경도 | | +| 위도 | | + +### 6.3 현장 목록 +- 추가 버튼: 현장 등록 팝업 표시 +- 현장명, 주소, 삭제 버튼 + +## 7. 휴가관리 (슬라이드 100) + +### 7.1 기준 셀렉트 박스 +- 종류: 회계연도, 입사일 +- 디폴트: 회계연도 +- 입사일 선택 시 (2) 영역 비활성화 +- 회계연도 기준: 회사의 회계연도를 기준으로 휴가를 부여하고 조회할 수 있습니다. +- 입사일 기준: 사원의 입사일 회계연도 기준으로 휴가를 부여하고 조회할 수 있습니다. + +### 7.2 기준일 월/일 설정 영역 +- 회계연도 기준 시에만 활성화 + +### 7.3 기본 연차 설정 +- 1년간 출근율 80% 이상이면 15일 +- 3년 이상 근속 시 2년에 1일 추가 (최대 25일) +- 1년 미만 또는 출근율 80% 이하인 경우 1일 + - 입사일~회계연도 기준일 사정: 회년도 출근율로 판정 80% 이상이면 15일 + - (3-1) 연차+1년+1일 시작, 이후 2년에 1일 추가 + - 입사일~회계연도 기준으로 전환할 때는 취업규칙 변경, 노사 의견수렴, 전환 시 충북 연차 정산(입사일 기준 vs 회계연도 기준 비교 후 부족분 보전)을 반드시 검토 필요 + +## 8. 카드관리 (슬라이드 101-102) + +### 8.1 카드 목록 +| 필드명 | 설명 | +|--------|------| +| 카드사 | | +| 카드번호 | 앞4자리, 끝4자리 표시 | +| 카드명 | | +| 상태 | | +| 사용자 | 부서명 / 이름 / 직책 | +| 작업 | 상세 버튼 | + +### 8.2 필터 +- 종류: 전체, 사용, 정지 +- 디폴트: 전체 + +### 8.3 카드 상세 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 카드사 | Y | 카드사명 선택 | +| 카드번호 | Y | 1234-1234-1234-1234 | +| 유효기간 | Y | MM/YY | +| 카드 비밀번호 앞 2자리 | Y | 입력 시 마스킹 처리 | +| 카드명 | Y | | +| 상태 | Y | 종류: 사용, 정지. 정지 시 해당 카드의 자동 조회 중단 | +| 사용자 | N | 부서명 / 이름 / 직책. 선택 시 해당 카드의 사용자로 설정 | + +## 9. 계좌관리 (슬라이드 103-104) + +### 9.1 계좌 목록 +| 필드명 | 설명 | +|--------|------| +| 은행 | | +| 계좌번호 | | +| 예금주 | | +| 상태 | | +| 사용자 | 부서명 / 이름 / 직책 | +| 작업 | 상세 버튼 | + +### 9.2 필터 +- 종류: 전체, 사용, 정지 +- 디폴트: 전체 + +### 9.3 계좌 상세 +| 필드명 | 필수 | 설명 | +|--------|------|------| +| 은행 | Y | 은행 선택 | +| 계좌번호 | Y | | +| 예금주 | Y | | +| 계좌명 | Y | | +| 상태 | Y | 종류: 사용, 정지. 정지 시 해당 계좌의 자동 조회 중단 | +| 사용자 | N | 부서명 / 이름 / 직책. 선택 시 해당 계좌의 사용자로 설정 | + +--- + +## 데이터 모델 + +### Position (직급) +``` +- id: bigint +- tenant_id: bigint (FK) +- name: string +- order: int +- created_at: timestamp +``` + +### JobTitle (직책) +``` +- id: bigint +- tenant_id: bigint (FK) +- name: string +- order: int +- created_at: timestamp +``` + +### Role (권한) +``` +- id: bigint +- tenant_id: bigint (FK) +- name: string +- is_system: boolean # 시스템 기본 권한 여부 +- permissions: json # 메뉴별 권한 설정 +- created_at: timestamp +``` + +### WorkSetting (근무 설정) +``` +- id: bigint +- tenant_id: bigint (FK) +- work_type: enum('fixed', 'flexible', 'custom') +- standard_hours: int # 주당 소정 근로 시간 +- overtime_hours: int # 주당 연장 근로 시간 +- overtime_limit: int # 연장 근로 한도 +- work_days: json # ['mon', 'tue', 'wed', 'thu', 'fri'] +- start_time: time +- end_time: time +- break_hours: int +- break_start: time +- break_end: time +``` + +### AttendanceSetting (출퇴근 설정) +``` +- id: bigint +- tenant_id: bigint (FK) +- use_gps: boolean +- allowed_radius: int # 허용 반경 (m) +- headquarters_address: string +- headquarters_latitude: decimal(10,8) +- headquarters_longitude: decimal(11,8) +``` + +### LeaveSetting (휴가 설정) +``` +- id: bigint +- tenant_id: bigint (FK) +- base_type: enum('fiscal_year', 'hire_date') +- fiscal_start_month: int +- fiscal_start_day: int +``` + +### Card (카드) +``` +- id: bigint +- tenant_id: bigint (FK) +- card_company: string +- card_number: string (encrypted) +- expiry_date: string +- card_password: string (encrypted) +- card_name: string +- status: enum('active', 'inactive') +- user_id: bigint (FK, nullable) +- created_at: timestamp +``` + +### BankAccount (계좌) +``` +- id: bigint +- tenant_id: bigint (FK) +- bank_code: string +- account_number: string +- account_holder: string +- account_name: string +- status: enum('active', 'inactive') +- user_id: bigint (FK, nullable) +- created_at: timestamp +``` + +--- + +## API 도출 + +### 직급/직책 API +``` +GET /api/positions # 직급 목록 +POST /api/positions # 직급 추가 +PUT /api/positions/{id} # 직급 수정 +DELETE /api/positions/{id} # 직급 삭제 +PUT /api/positions/reorder # 직급 순서 변경 + +GET /api/job-titles # 직책 목록 +POST /api/job-titles # 직책 추가 +PUT /api/job-titles/{id} # 직책 수정 +DELETE /api/job-titles/{id} # 직책 삭제 +PUT /api/job-titles/reorder # 직책 순서 변경 +``` + +### 권한 API +``` +GET /api/roles # 권한 목록 +POST /api/roles # 권한 추가 +GET /api/roles/{id} # 권한 상세 +PUT /api/roles/{id} # 권한 수정 +DELETE /api/roles/{id} # 권한 삭제 +GET /api/menus # 메뉴 목록 (권한 설정용) +``` + +### 설정 API +``` +GET /api/settings/work # 근무 설정 조회 +PUT /api/settings/work # 근무 설정 수정 +GET /api/settings/attendance # 출퇴근 설정 조회 +PUT /api/settings/attendance # 출퇴근 설정 수정 +GET /api/settings/leave # 휴가 설정 조회 +PUT /api/settings/leave # 휴가 설정 수정 +``` + +### 카드/계좌 API +``` +GET /api/cards # 카드 목록 +POST /api/cards # 카드 등록 +GET /api/cards/{id} # 카드 상세 +PUT /api/cards/{id} # 카드 수정 +DELETE /api/cards/{id} # 카드 삭제 + +GET /api/bank-accounts # 계좌 목록 +POST /api/bank-accounts # 계좌 등록 +GET /api/bank-accounts/{id} # 계좌 상세 +PUT /api/bank-accounts/{id} # 계좌 수정 +DELETE /api/bank-accounts/{id} # 계좌 삭제 +``` diff --git a/system/erp-analysis/08-reports.md b/system/erp-analysis/08-reports.md new file mode 100644 index 0000000..51e9597 --- /dev/null +++ b/system/erp-analysis/08-reports.md @@ -0,0 +1,225 @@ +# 보고서 및 분석 (슬라이드 105-113) + +## 1. 개요 + +보고서 및 분석 모듈은 일일 일보, 지출 예상 내역서, 가지급금 인정이자 계산, AI 리포트 생성 등을 제공합니다. + +## 2. 일일 일보 (슬라이드 106-107) + +### 2.1 일일 일보 조회 +- 매일 전일의 입출금 및 매출 매입 현황 자동 집계 + +### 2.2 현황 카드 +| 항목 | 설명 | +|------|------| +| 전일 잔액 | 조회 기준일 전일 잔액 | +| 당일 입금액 | 전일 입금 합계 | +| 당일 출금액 | 전일 출금 합계 | +| 당일 잔액 | 조회 기준일 잔액 | + +### 2.3 일일 일보 목록 +| 필드명 | 설명 | +|--------|------| +| 구분 | 입금/출금 | +| 거래처명 | | +| 계정과목 | | +| 입금액 | | +| 출금액 | | +| 적요 | | + +### 2.4 엑셀 다운로드 버튼 + +## 3. 지출 예상 내역서 (슬라이드 108-109) + +### 3.1 지출 예상 내역서 조회 +- 예상 지출 금액 및 일정 조회 + +### 3.2 현황 카드 +| 항목 | 설명 | +|------|------| +| 예상 지출 합계 | 월별 예상 지출 합계 | +| 계좌 잔액 | 현재 계좌 잔액 | +| 예상 잔액 | 계좌 잔액 - 예상 지출 합계 | + +### 3.3 지출 예상 내역서 목록 +| 필드명 | 설명 | +|--------|------| +| 예상 지급일 | | +| 품목 | | +| 지출금액 | | +| 거래처 | | +| 계좌 | | + +### 3.4 엑셀 다운로드 버튼 + +### 3.5 월별 합계 +| 항목 | 설명 | +|------|------| +| 2025/11 계 | 11월 지출 합계 | +| 2025/12 계 | 12월 지출 합계 | +| 지출 합계 | 전체 지출 합계 | +| 계좌 잔액 | | +| 최종 차액 | | + +## 4. 가지급금 인정이자 계산 (슬라이드 110-112) + +### 4.1 가지급금 인정이자 계산 예시 (2024년 기준) +- 인정이자율 4.6% (당좌대출이자율 기준, 매년 고시) + +### 4.2 계산 예시 +| 항목 | 금액 | +|------|------| +| 가지급금 잔액 | 15,200,000원 | +| 인정이자 | 699,200원 | +| 법인세 추가 (19%) | 132,848원 | +| 대표자 소득세 추가 (35%) | 244,720원 | +| 대표자 지방소득세 (10%) | 24,472원 | +| **총 세금 부담** | **402,040원** | + +### 4.3 계산식 +``` +잔액 × 0.046 = 인정이자 +인정이자 × 0.19 = 법인세 추가 +인정이자 × 0.35 = 대표자 소득세 추가 +``` + +### 4.4 기본 정산 공식 +``` +정산차액 = 가지급금 총액 - 실사용 총액 +``` + +### 4.5 인정이자 계산 공식 (법인세법 기준) +``` +경과일수 = 정산일 - 지급일 +일이자율 = 연이자율 ÷ 365 +인정이자 = 가지급금 × 일이자율 × 경과일수 +``` + +## 5. AI 리포트 생성 (슬라이드 113) + +### 5.1 AI 리포트 생성 프롬프트 + +#### 작성 규칙 +1. 문장은 간결하고 명확하게 작성 +2. 숫자는 읽기 쉽게 "3,123,000원", "15%" 형식 사용 +3. 계정과목명, 거래처명은 구체적으로 명시 +4. 조치가 필요한 경우 구체적인 행동 권한 포함 +5. 긍정적 변화도 반드시 실상 포함 +6. 법인세, 소득세 영향이 있는 경우 세무 리스크 명시 + +#### 키워드 강조 규칙 +출력 메시지 내 다음 키워드는 프론트엔드에서 색상 강조됩니다: +- **빨간색(경고)**: 초과, 증가, 발생, 필요, 불가 +- **주황색(주의)**: 점검, 확인, 주의, 검토 +- **녹색(긍정)**: 감소, 완료, 정상 +- **파란색(양호)**: 여유, 적정, 양호 + +#### 예시 출력 +입력 데이터 예시에 대한 출력: + +```json +{"리포트": [ + {"영역": "지출분석", "상태": "경고", "메시지": "이번 달 예상 지출이 전월 대비 15% 증가했습니다.", "상세": "매입 비용 증가가 주요 원인입니다."}, + {"영역": "가지급금", "상태": "주의", "메시지": "50일 이상 잔기 미수금 3건(2,500만원) 발생.", "상세": "회수 조치가 필요합니다."}, + {"영역": "카드/계좌", "상태": "경고", "메시지": "법인카드 사용 한도 85% 도달, 잔여 한도 600만원입니다.", "상세": "사용 계획을 점검해 주세요."}, + {"영역": "미수금", "상태": "주의", "메시지": "미수금에 대한 관리가 필요한 상태입니다.", "상세": ""} +], +"요약": "지출 증가와 정기 미수금에 대한 관리가 필요한 상태입니다."} +``` + +--- + +## 데이터 모델 + +### DailyReport (일일 일보) +``` +- id: bigint +- tenant_id: bigint (FK) +- report_date: date +- previous_balance: decimal +- daily_deposit: decimal +- daily_withdrawal: decimal +- current_balance: decimal +- details: json # 입출금 상세 내역 +- created_at: timestamp +``` + +### ExpenseEstimate (지출 예상 내역서) +``` +- id: bigint +- tenant_id: bigint (FK) +- expected_date: date +- item_name: string +- amount: decimal +- vendor_id: bigint (FK, nullable) +- account_id: bigint (FK, nullable) +- created_at: timestamp +``` + +### LoanInterestCalculation (가지급금 인정이자 계산) +``` +- id: bigint +- tenant_id: bigint (FK) +- calculation_date: date +- loan_balance: decimal +- interest_rate: decimal +- recognized_interest: decimal +- corporate_tax_addition: decimal +- income_tax_addition: decimal +- local_tax_addition: decimal +- total_tax_burden: decimal +- created_at: timestamp +``` + +### AIReport (AI 리포트) +``` +- id: bigint +- tenant_id: bigint (FK) +- report_date: date +- report_type: string +- content: json # 리포트 내용 +- summary: text +- created_at: timestamp +``` + +--- + +## API 도출 + +### 일일 일보 API +``` +GET /api/reports/daily # 일일 일보 조회 +GET /api/reports/daily/export # 일일 일보 엑셀 다운로드 +``` + +### 지출 예상 내역서 API +``` +GET /api/reports/expense-estimate # 지출 예상 내역서 조회 +POST /api/reports/expense-estimate # 지출 예상 내역 등록 +PUT /api/reports/expense-estimate/{id}# 지출 예상 내역 수정 +DELETE /api/reports/expense-estimate/{id}# 지출 예상 내역 삭제 +GET /api/reports/expense-estimate/export # 지출 예상 내역서 엑셀 다운로드 +``` + +### 가지급금 인정이자 API +``` +GET /api/reports/loan-interest # 가지급금 인정이자 계산 조회 +POST /api/reports/loan-interest/calculate # 가지급금 인정이자 계산 실행 +``` + +### AI 리포트 API +``` +GET /api/reports/ai # AI 리포트 목록 +POST /api/reports/ai/generate # AI 리포트 생성 +GET /api/reports/ai/{id} # AI 리포트 상세 +DELETE /api/reports/ai/{id} # AI 리포트 삭제 +``` + +### 대시보드/분석 API +``` +GET /api/dashboard/summary # 대시보드 요약 +GET /api/dashboard/charts # 대시보드 차트 데이터 +GET /api/analytics/sales # 매출 분석 +GET /api/analytics/expense # 지출 분석 +GET /api/analytics/receivables # 미수금 분석 +``` \ No newline at end of file diff --git a/system/erp-analysis/99-gap-analysis.md b/system/erp-analysis/99-gap-analysis.md new file mode 100644 index 0000000..9e6f9fe --- /dev/null +++ b/system/erp-analysis/99-gap-analysis.md @@ -0,0 +1,1048 @@ +# 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` | \ No newline at end of file diff --git a/system/item-master-integration.md b/system/item-master-integration.md new file mode 100644 index 0000000..5caf1e9 --- /dev/null +++ b/system/item-master-integration.md @@ -0,0 +1,661 @@ +# ItemMaster 연동 설계서 + +**작성일**: 2025-12-05 +**최종 수정**: 2025-12-08 +**버전**: 1.1 +**상태**: Draft + +--- + +## 1. 개요 + +### 1.1 목적 +품목기준관리(ItemMaster)에서 정의한 필드와 실제 엔티티 데이터를 연동하여, 동적 필드 정의 및 값 저장을 가능하게 한다. + +### 1.2 설계 원칙 +- **기존 테이블 활용**: 신규 테이블 추가 없이 기존 `attributes` JSON 컬럼 활용 +- **범용성**: 품목(products, materials) 외에도 다른 엔티티(orders, clients 등) 확장 가능 +- **성능**: JOIN 없이 단일 쿼리로 조회 가능 +- **유연성**: 테넌트/그룹별 다른 필드 구성 지원 + +--- + +## 2. 현재 구조 + +### 2.1 ItemMaster 테이블 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ item_pages (페이지 정의) │ +├─────────────────────────────────────────────────────────────┤ +│ id, tenant_id, page_name, item_type, source_table, │ +│ is_active │ +│ │ +│ item_type: FG(완제품), PT(반제품), SM(부자재), │ +│ RM(원자재), CS(소모품) │ +│ │ +│ source_table: 실제 저장 테이블명 │ +│ - 'products' (FG, PT) │ +│ - 'materials' (SM, RM, CS) │ +└─────────────────────────────────────────────────────────────┘ + │ + │ 1:N + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ item_sections (섹션 정의) │ +├─────────────────────────────────────────────────────────────┤ +│ id, tenant_id, page_id, title, type, order_no │ +│ │ +│ type: fields(필드형), bom(BOM형) │ +└─────────────────────────────────────────────────────────────┘ + │ + │ 1:N + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ item_fields (필드 정의) │ +├─────────────────────────────────────────────────────────────┤ +│ id, tenant_id, group_id, section_id (nullable) │ +│ field_key ← attributes JSON 키와 매핑 │ +│ field_name ← 화면 표시명 │ +│ field_type ← textbox, number, dropdown, checkbox... │ +│ is_required ← 필수 여부 │ +│ default_value ← 기본값 │ +│ placeholder ← 입력 힌트 │ +│ validation_rules ← 검증 규칙 JSON │ +│ options ← 선택 옵션 JSON │ +│ properties ← 추가 속성 JSON │ +│ category ← 필드 카테고리 │ +│ is_common ← 공통 필드 여부 │ +│ is_active ← 활성 여부 │ +│ │ +│ [내부용 매핑 컬럼 - API 응답에서 hidden] │ +│ source_table ← 원본 테이블명 (products, materials 등) │ +│ source_column ← 원본 컬럼명 (code, name 등) │ +│ storage_type ← 저장방식 (column=DB컬럼, json=JSON) │ +│ json_path ← JSON 저장 경로 (예: attributes.size) │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 2.2 엔티티 테이블 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ products │ +├─────────────────────────────────────────────────────────────┤ +│ [고정 필드] │ +│ id, tenant_id, code, name, unit, category_id │ +│ product_type, is_active, is_sellable, is_purchasable... │ +│ │ +│ [동적 필드] │ +│ attributes JSON ← ItemMaster 필드 값 저장 │ +└─────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────┐ +│ materials │ +├─────────────────────────────────────────────────────────────┤ +│ [고정 필드] │ +│ id, tenant_id, material_code, name, unit, category_id │ +│ material_type, is_active... │ +│ │ +│ [동적 필드] │ +│ attributes JSON ← ItemMaster 필드 값 저장 │ +│ options JSON ← 추가 옵션 저장 │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. 연동 설계 + +### 3.1 매핑 규칙 + +``` +ItemMaster Entity.attributes +┌──────────────────────┐ ┌──────────────────────┐ +│ group_id: 1 │ │ │ +│ field_key: "color" │ ◀═══매핑═══▶ │ {"color": "빨강"} │ +│ field_key: "weight" │ ◀═══매핑═══▶ │ {"weight": 1.5} │ +│ field_key: "spec" │ ◀═══매핑═══▶ │ {"spec": "10x20"} │ +└──────────────────────┘ └──────────────────────┘ + +핵심: item_fields.field_key = attributes JSON의 key +``` + +### 3.2 Group ID 정의 + +| group_id | 엔티티 | 대상 테이블 | 비고 | +|----------|--------|-------------|------| +| 1 | 품목-제품 | products | product_type: FG, PT | +| 2 | 품목-자재 | materials | material_type: SM, RM, CS | +| 3 | 주문 | orders | 향후 확장 | +| 4 | 고객 | clients | 향후 확장 | +| ... | ... | ... | 필요 시 추가 | + +> **참고**: group_id는 `common_codes` 테이블에서 관리하거나, 별도 enum으로 정의 가능 + +### 3.3 데이터 흐름 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 1. 관리자: ItemMaster에서 필드 정의 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ POST /api/v1/item-master/fields │ +│ { │ +│ "group_id": 1, │ +│ "field_key": "color", │ +│ "field_name": "색상", │ +│ "field_type": "dropdown", │ +│ "is_required": true, │ +│ "options": [ │ +│ {"label": "빨강", "value": "red"}, │ +│ {"label": "파랑", "value": "blue"} │ +│ ] │ +│ } │ +│ │ +│ → item_fields 테이블에 저장 │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 2. 사용자: 품목 등록 화면 진입 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ GET /api/v1/item-master/fields?group_id=1 │ +│ │ +│ → 정의된 필드 목록 반환 │ +│ → 프론트엔드가 동적 폼 렌더링 │ +│ │ +│ ┌────────────────────────────────────┐ │ +│ │ [색상 ▼] ← dropdown으로 표시 │ │ +│ │ 빨강 │ │ +│ │ 파랑 │ │ +│ └────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 3. 사용자: 품목 저장 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ POST /api/v1/products │ +│ { │ +│ "code": "P-001", ← 고정 필드 │ +│ "name": "티셔츠", │ +│ "unit": "EA", │ +│ "product_type": "FG", │ +│ "attributes": { ← 동적 필드 │ +│ "color": "red", (field_key: value) │ +│ "size": "XL" │ +│ } │ +│ } │ +│ │ +│ → products 테이블에 저장 │ +│ → attributes JSON에 동적 필드 값 포함 │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 4. 사용자: 품목 조회 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ GET /api/v1/products/1 │ +│ │ +│ { │ +│ "id": 1, │ +│ "code": "P-001", │ +│ "name": "티셔츠", │ +│ "attributes": { │ +│ "color": "red", │ +│ "size": "XL" │ +│ } │ +│ } │ +│ │ +│ → JOIN 없이 한 번에 조회! │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. API 설계 + +### 4.1 ItemMaster API (기존) + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/fields` | 필드 목록 조회 | +| GET | `/api/v1/item-master/fields/{id}` | 필드 상세 조회 | +| POST | `/api/v1/item-master/fields` | 필드 생성 | +| PUT | `/api/v1/item-master/fields/{id}` | 필드 수정 | +| DELETE | `/api/v1/item-master/fields/{id}` | 필드 삭제 | + +**필터 파라미터**: +- `group_id`: 엔티티 그룹 필터 +- `section_id`: 섹션 필터 +- `is_active`: 활성 필터 +- `is_common`: 공통 필드 필터 + +### 4.2 엔티티 API 수정 + +#### 4.2.1 Products API + +**저장 시 attributes 포함**: +```json +POST /api/v1/products +{ + "code": "P-001", + "name": "제품명", + "unit": "EA", + "product_type": "FG", + "attributes": { + "color": "red", + "weight": 1.5, + "custom_field": "value" + } +} +``` + +**조회 시 필드 메타데이터 포함 (선택)**: +``` +GET /api/v1/products/1?include_field_meta=true +``` + +```json +{ + "id": 1, + "code": "P-001", + "name": "제품명", + "attributes": { + "color": "red", + "weight": 1.5 + }, + "field_meta": [ + { + "field_key": "color", + "field_name": "색상", + "field_type": "dropdown", + "value": "red", + "options": [...] + }, + { + "field_key": "weight", + "field_name": "중량", + "field_type": "number", + "value": 1.5 + } + ] +} +``` + +--- + +## 5. 검증 로직 + +### 5.1 저장 시 검증 흐름 + +```php +class ItemFieldValidationService +{ + /** + * attributes 값을 ItemMaster 기준으로 검증 + */ + public function validate(int $groupId, array $attributes): array + { + $errors = []; + + // 1. 해당 그룹의 필드 정의 조회 + $fields = ItemField::where('group_id', $groupId) + ->where('is_active', true) + ->get() + ->keyBy('field_key'); + + // 2. 필수 필드 체크 + foreach ($fields->where('is_required', true) as $field) { + if (!isset($attributes[$field->field_key])) { + $errors[$field->field_key] = "{$field->field_name}은(는) 필수입니다."; + } + } + + // 3. 타입별 검증 + foreach ($attributes as $key => $value) { + if (!$fields->has($key)) { + continue; // 정의되지 않은 필드는 스킵 (또는 에러) + } + + $field = $fields->get($key); + $fieldError = $this->validateFieldValue($field, $value); + if ($fieldError) { + $errors[$key] = $fieldError; + } + } + + return $errors; + } + + /** + * 필드 타입별 값 검증 + */ + private function validateFieldValue(ItemField $field, mixed $value): ?string + { + return match($field->field_type) { + 'number' => $this->validateNumber($field, $value), + 'dropdown' => $this->validateDropdown($field, $value), + 'date' => $this->validateDate($field, $value), + 'checkbox' => $this->validateCheckbox($field, $value), + default => null + }; + } + + private function validateNumber(ItemField $field, mixed $value): ?string + { + if (!is_numeric($value)) { + return "{$field->field_name}은(는) 숫자여야 합니다."; + } + + $rules = $field->validation_rules ?? []; + if (isset($rules['min']) && $value < $rules['min']) { + return "{$field->field_name}은(는) {$rules['min']} 이상이어야 합니다."; + } + if (isset($rules['max']) && $value > $rules['max']) { + return "{$field->field_name}은(는) {$rules['max']} 이하여야 합니다."; + } + + return null; + } + + private function validateDropdown(ItemField $field, mixed $value): ?string + { + $options = $field->options ?? []; + $validValues = array_column($options, 'value'); + + if (!in_array($value, $validValues)) { + return "{$field->field_name}의 값이 유효하지 않습니다."; + } + + return null; + } +} +``` + +### 5.2 Controller에서 사용 + +```php +class ProductsController extends Controller +{ + public function store(ProductStoreRequest $request) + { + $validated = $request->validated(); + + // attributes 검증 (선택적) + if (isset($validated['attributes'])) { + $groupId = 1; // 품목-제품 그룹 + $errors = $this->fieldValidationService->validate( + $groupId, + $validated['attributes'] + ); + + if (!empty($errors)) { + return ApiResponse::error('검증 실패', $errors, 422); + } + } + + $product = $this->productService->create($validated); + + return ApiResponse::success($product, __('message.created')); + } +} +``` + +--- + +## 6. 프론트엔드 연동 + +### 6.1 동적 폼 렌더링 흐름 + +``` +1. 페이지 로드 시 + GET /api/v1/item-master/fields?group_id=1 + +2. 필드 정의 기반 폼 컴포넌트 렌더링 + field_type: textbox → + field_type: number → + field_type: dropdown →