Files
SR-SYSTEM/docs/02-architecture.md
T
2026-06-02 13:50:39 +09:00

151 lines
9.2 KiB
Markdown

# 시스템 아키텍처 정의서 (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'` 자변환