# 시스템 아키텍처 정의서 (System Architecture) ## 1. 기술 스택 | 계층 | 기술 | 버전 | |------|------|------| | Backend | Spring Boot | 3.x | | | Java | 17 | | | Spring Data JPA | - | | | Spring Security | - | | | Spring Batch | - | | Frontend | Next.js | 14+ (App Router) | | | TypeScript | - | | | Tailwind CSS | - | | | Pinia (State Management) | - | | Database | PostgreSQL | 15 | | Infra | Nginx Proxy Manager | - | | CI/CD | GitHub Actions | Release 트리거 | | Notification | Slack Webhook / Email | - | ## 2. 전역 시스템 레이어 구조 ``` ┌─────────────────────────────────────────────────────────────┐ │ Frontend (Next.js 14+) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │ │ Pinia │ │ Axios │ │ Tailwind │ │ Dynamic LNB │ │ │ │ Storage │ │ Intercep.│ │ CSS │ │ (RBAC) │ │ │ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │ └──────────────────────┬──────────────────────────────────────┘ │ HTTPS / REST API ▼ ┌─────────────────────────────────────────────────────────────┐ │ Cloudflare Tunnel (SSL / Zero-Trust Proxy) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Backend (Spring Boot 3.x / Java 17) │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Security Layer │ │ │ │ ┌─────────────────┐ ┌──────────────────────────┐ │ │ │ │ │ JWT Token │ │ Security Filter Chain │ │ │ │ │ │ Provider │ │ (RBAC Authorization) │ │ │ │ │ └─────────────────┘ └──────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ API Layer (REST Controllers) │ │ │ │ EmployeeController / TicketController / ... │ │ │ └──────────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Service Layer (Business Logic + Transaction) │ │ │ │ ├─ @Transactional 선언 │ │ │ │ └─ ApplicationEventPublisher (EDA 발행) │ │ │ └──────────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Persistence Layer (Spring Data JPA) │ │ │ │ ├─ Entity / Repository / Specification │ │ │ │ ├─ @SQLDelete + @Where (Soft Delete 전역 필터) │ │ │ │ └─ @SequenceGenerator(allocationSize=50) │ │ │ └──────────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Infrastructure Layer │ │ │ │ ├─ @TransactionalEventListener(AFTER_COMMIT) │ │ │ │ ├─ @Async Notification Listener │ │ │ │ └─ Spring Batch SLA Scheduler (Chunk Size=100) │ │ │ └──────────────────────────────────────────────────────┘ │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ PostgreSQL 15 Database │ │ ├─ Sequence (INCREMENT BY 50) │ │ ├─ Common Code Table (동적 드롭다운) │ │ └─ Batch Metadata Schema │ └─────────────────────────────────────────────────────────────┘ ``` ## 3. ApiResponse 공통 규격 모든 API 응답은 아래 포맷을 강제합니다. **성공:** ```json { "success": true, "message": "요청이 성공적으로 처리되었습니다.", "data": { ... } } ``` **실패 (비즈니스 예외):** ```json { "success": false, "message": "이미 결재가 완료된 보고서는 수정할 수 없습니다.", "errorCode": "RPT_ERR_001", "data": null } ``` ## 4. 글로벌 예외 처리 (GlobalExceptionHandler) - 모든 도메인 예외는 `BusinessException` (RuntimeException 상속) 통일 - `@RestControllerAdvice`가 감지 → `ErrorCode` Enum 매핑 → `ApiResponse.error()` 변환 ### ErrorCode 매트릭스 | Enum | HTTP Status | ErrorCode | 메시지 | |------|------------|-----------|--------| | `RESIGNED_EMPLOYEE` | 400 | EMP_ERR_001 | 퇴사 처리된 직원 정보는 수정할 수 없습니다 | | `LOCKED_REPORT` | 400 | RPT_ERR_001 | 결재 완료 보고서는 수정/삭제할 수 없습니다 | | `FUTURE_REPORT_DATE` | 400 | RPT_ERR_002 | 미래 날짜의 업무 보고는 작성할 수 없습니다 | | `CLOSED_TICKET_MOD` | 400 | TCK_ERR_001 | 종료된 티켓은 댓글/수정이 불가능합니다 | | `ASSIGNEE_REQUIRED` | 400 | TCK_ERR_002 | 담당자 미배정 티켓은 IN_PROGRESS 전환 불가 | | `EQUIP_NOT_AVAILABLE` | 400 | EQP_ERR_001 | 지급 가능한 재고 상태가 아닙니다 | | `INVALID_ASSIGNEE` | 400 | EQP_ERR_002 | 재직 중인 직원에게만 장비 지급 가능 | | `SYSTEM_CONCURRENCY` | 409 | SYS_ERR_001 | 동시성 충돌 - 다시 시도해 주세요 | ## 5. 이벤트 기반 비동기 알림 (EDA) ```mermaid sequenceDiagram Controller->>Service: 요청 처리 Service->>DB: 트랜잭션 커밋 Service->>EventPublisher: 이벤트 발행 EventPublisher->>Listener: @TransactionalEventListener(AFTER_COMMIT) Listener->>Slack/Email: @Async 비동기 발송 Note over Listener: 메인 트랜잭션과 완전 격리 ``` ## 6. SLA 만료 배치 아키텍처 (Spring Batch) - **트리거:** Spring Scheduler (매시간) - **Chunk Size:** 100건 단위 청크 분할 - **필터 조건:** `SLA_WARN_FLAG = 'N'` AND `status NOT IN (RESOLVED, CLOSED)` AND `due_date < NOW()` - **처리:** 대상 티켓 탐색 → 알림 이벤트 발행 → `SLA_WARN_FLAG = 'Y'` 갱신 - **PostgreSQL 메타데이터:** 배치 전용 메타 테이블 스키마 별도 구축 ## 7. Soft Delete 전역 아키텍처 ```java // BaseEntity 패턴 @SQLDelete(sql = "UPDATE tb_xxx SET is_deleted = 'Y' WHERE id = ?") @Where(clause = "is_deleted = 'N'") ``` - 모든 엔티티가 `BaseEntity` 상속 (created_at, updated_at, is_deleted) - 조회 시 `@Where` 조건절 자동 적용 → 조건절 누수 방지 - 물리 삭제 `DELETE` → `UPDATE is_deleted='Y'` 자변환