init: SR System — Helpdesk & ITAM Portal

This commit is contained in:
pray4skylark
2026-06-02 13:50:39 +09:00
commit 832c9f096f
262 changed files with 30470 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
# 시스템 요구 기능 정의서 (Functional Requirements)
## 1. 시스템 개요
- **시스템명:** SM/SI 파견 직원 통합 지원 및 IT 자산 관리 포털 (HQ 헬프데스크)
- **목적:** 파견 직원 라이프사이클/커리어 관리, 현장 기술 문제 본사(SR) 지원, IT 자산 생명주기 추적 통합
- **기대 효과:** 본사-파견지 간 정보 간극 해소, 운영 효율성 극대화
## 2. 역할 및 권한 체계 (RBAC)
| 역할 | 코드 | 설명 |
|------|------|------|
| 일반 사용자 | `EMPLOYEE` | 파견지 현장 직원. 포트폴리오 관리, 업무 보고서 작성, SR 티켓 신청, 장비/교육 조회 |
| 본사 관리자 | `MANAGER` | 영업/인사/자산 담당. 직원 현황 관리, 보고 결재, SR 티켓 처리, 장비 인벤토리 제어 |
| 최고 관리자 | `ADMIN` | 전역 계정 관리, 접근 권한 부여, 공통 코드 테이블 동적 제어 |
## 3. 도메인별 기능 요구사항
### 3.1 인사 및 포트폴리오 관리
| 기능 | 설명 | API | 권한 |
|------|------|-----|------|
| 직원 정보 관리 | 기본 인적사항, 재직 상태(재직/휴직/퇴사), 파견 상태(대기/파견중) CRUD | `/api/v1/employees` | ADMIN |
| 포트폴리오 누적 | 투입 프로젝트, 수행 역할, 기간, 개인 기여 기술, 성과 기록 (1:N) | `/api/v1/dispatch-history` | EMPLOYEE |
| 경력 기술서 조회 | 본인 포트폴리오 데이터 통합 조회 | `/api/v1/employees/{id}/portfolio` | EMPLOYEE |
### 3.2 HQ 헬프데스크 (SR 지원)
| 기능 | 설명 | API | 권한 |
|------|------|-----|------|
| SR 티켓 발행 | 현장 기술 난제 발생 시 SOS 요청 (에러 로그, 캡처 이미지 첨부) | `POST /api/v1/tickets` | EMPLOYEE |
| 티켓 목록/칸반 | 상태별(OPEN/IN_PROGRESS/RESOLVED/CLOSED) 칸반 보드 조회 | `GET /api/v1/tickets` | ALL |
| 티켓 상세/타임라인 | 티켓 상세 정보 + 시간순 댓글(파일 포함) 내역 | `GET /api/v1/tickets/{id}` | ALL |
| 댓글 등록 | 본사-현장 간 분석 의견, 스크립트 소통 | `POST /api/v1/tickets/{id}/comments` | ASSIGNED |
| 상태 전환 | OPEN→ASSIGNED→IN_PROGRESS→RESOLVED→CLOSED | `PUT /api/v1/tickets/{id}/status` | MANAGER |
| 필터/검색 | 카테고리, 우선순위, 키워드 기반 검색 | `GET /api/v1/tickets?category=&priority=&keyword=` | ALL |
| SLA 만료 알림 | 목표 처리 기한 초과 시 Slack/Email 알림 자동 발송 | Batch Scheduler | SYSTEM |
### 3.3 IT 자산 관리 (ITAM)
| 기능 | 설명 | API | 권한 |
|------|------|-----|------|
| 장비 마스터 관리 | 자산 코드, 제조사, 모델명 기반 장비 CRUD | `GET/POST /api/v1/equipment` | MANAGER |
| 장비 지급 | AVAILABLE 장비 → 직원 할당 (낙관적 락 동시성 제어) | `POST /api/v1/equipment/{id}/assign` | MANAGER |
| 장비 반납 | IN_USE 장비 회수 + 상태 코멘트 기록 | `PUT /api/v1/equipment/{id}/return` | MANAGER |
| 사용 이력 추적 | 장비별 과거 지급/반납 내역 (1:N) | `GET /api/v1/equipment/{id}/assignments` | MANAGER |
| 유지보수 이력 | 수리, 업그레이드(RAM/SSD), 폐기 이력 및 비용 관리 | `POST /api/v1/equipment/{id}/maintenance` | MANAGER |
| 직원 검색 자동완성 | 장비 지급 대상 사원 검색 (디바운싱 300ms) | `GET /api/v1/employees/search?keyword=` | MANAGER |
### 3.4 업무 보고 및 결재 워크플로우
| 기능 | 설명 | API | 권한 |
|------|------|-----|------|
| 보고서 작성 | 일일/주간/월간 단위 실적, 계획, 애로사항 기재 | `POST /api/v1/reports` | EMPLOYEE |
| 보고서 상태 관리 | DRAFT(임시저장) → SUBMITTED(제출) → APPROVED/REJECTED | `PUT /api/v1/reports/{id}/status` | EMPLOYEE |
| 결재 처리 | 관리자 승인/반려 + 반려 시 피드백 필수 | `PUT /api/v1/reports/{id}/review` | MANAGER |
| SR 연동 자동화 | 보고서 작성 시 해당 주차 해결 완료 SR 내역 자동 바인딩 | Internal (Backend) | SYSTEM |
### 3.5 내부 교육 관리
| 기능 | 설명 | API | 권한 |
|------|------|-----|------|
| 교육 진도 조회 | 사내 커리큘럼별 진도율(%), 수강 상태(NOT_STARTED/ONGOING/COMPLETED) 조회 | `GET /api/v1/training` | EMPLOYEE |
| 진도율 업데이트 | 교육 수강 완료 시 진도율 자동/수동 갱신 | `PUT /api/v1/training/{id}` | SYSTEM |
| 실시간 모니터링 | 관리자 대시보드에서 직원별 교육 이수 현황 파악 | `GET /api/v1/training/summary` | MANAGER |
## 4. 비기능 요구사항
| 항목 | 요구사항 |
|------|---------|
| 보안 | BCrypt 비밀번호 암호화, JWT 기반 인증, RBAC 권한 제어 |
| 데이터 무결성 | Soft Delete 전역 적용, 낙관적 락(Optimistic Lock)으로 동시성 제어 |
| 응답 시간 | 페이지 응답 3초 이내, 검색 자동완성 500ms 이내 |
| 알림 | 이벤트 기반 비동기 알림 (Slack/Email), 트랜잭션 분리 |
| SLA 관리 | Spring Batch 청크 처리로 시간당 대량 티켓 데드라인 스캔 |
| 감사(Audit) | 모든 테이블에 created_at, updated_at 타임스탬프强制 적용 |
+150
View File
@@ -0,0 +1,150 @@
# 시스템 아키텍처 정의서 (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'` 자변환
+220
View File
@@ -0,0 +1,220 @@
# 데이터베이스 설계서 (Database Schema)
## 1. 공통 원칙
- **Soft Delete:** 모든 테이블 `is_deleted CHAR(1) DEFAULT 'N'` — 물리 삭제 금지
- **Audit:** 모든 테이블 `created_at TIMESTAMP`, `updated_at TIMESTAMP` — 감사 로그
- **ID 생성:** `Sequence` + `allocationSize=50` — Oracle 11g 최적화
- **공통 코드:** 드롭다운/상태값은 Common Code 테이블에서 동적 관리
## 2. 공통 코드 인프라
### TB_COMMON_CODE_GROUP (대분류)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| GROUP_CODE | VARCHAR2(50) | PK | 'PROJECT_TYPE', 'ISSUE_STATUS' |
| GROUP_NAME | VARCHAR2(100) | NOT NULL | '프로젝트 유형', '이슈 상태' |
| DESCRIPTION | CLOB | NULLABLE | |
### TB_COMMON_CODE (소분류)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| CODE_ID | NUMBER | PK (Seq) | 시퀀스 자동 증가 |
| GROUP_CODE | VARCHAR2(50) | FK | TB_COMMON_CODE_GROUP 참조 |
| CODE_VALUE | VARCHAR2(50) | UNIQUE, NOT NULL | 내부 로직 코드 ('BUG', 'SI') |
| CODE_NAME | VARCHAR2(100) | NOT NULL | 화면 표시용 ('결함 및 장애') |
| OPTION_VAL_1 | VARCHAR2(100) | NULLABLE | UI 뱃지 색상 |
| OPTION_VAL_2 | VARCHAR2(100) | NULLABLE | SLA 가중치 |
| OPTION_VAL_3 | VARCHAR2(100) | NULLABLE | 연동 키 |
| SORT_ORDER | NUMBER | DEFAULT 1 | 노출 순서 |
| IS_ACTIVE | CHAR(1) | DEFAULT 'Y' | 'Y'/'N' |
| DESCRIPTION | CLOB | NULLABLE | |
**공통 코드 예시 데이터:**
| GROUP_CODE | CODE_VALUE | CODE_NAME | OPTION_VAL_1 (색상) | OPTION_VAL_2 (SLA) |
|------------|-----------|-----------|---------------------|--------------------|
| ISSUE_STATUS | OPEN | 접수 | blue | 48h |
| ISSUE_STATUS | IN_PROGRESS | 처리중 | orange | - |
| ISSUE_STATUS | RESOLVED | 해결 | green | - |
| ISSUE_STATUS | CLOSED | 종료 | gray | - |
| PRIORITY | CRITICAL | 긴급 | red | 4h |
| PRIORITY | HIGH | 높음 | orange | 24h |
| PRIORITY | NORMAL | 보통 | blue | 72h |
| PRIORITY | LOW | 낮음 | gray | 120h |
## 3. 도메인 테이블 명세
### TB_EMPLOYEE (직원 마스터)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| EMP_ID | NUMBER | PK (Seq) | 시스템 고유 사번 |
| LOGIN_ID | VARCHAR2(50) | UNIQUE, NOT NULL | 인증용 ID |
| PASSWORD | VARCHAR2(255) | NOT NULL | BCrypt 암호화 |
| NAME | VARCHAR2(50) | NOT NULL | 실명 |
| EMAIL | VARCHAR2(100) | UNIQUE, NOT NULL | 회사 이메일 |
| ROLE_CODE | VARCHAR2(20) | NOT NULL | ADMIN / MANAGER / EMPLOYEE |
| EMP_STATUS | VARCHAR2(20) | NOT NULL | ACTIVE / ON_LEAVE / RESIGNED |
| DISPATCH_STATUS | VARCHAR2(20) | NOT NULL | WAITING / DISPATCHED |
| JOINED_DATE | DATE | NOT NULL | 입사일 |
| LEFT_DATE | DATE | NULLABLE | 퇴사일 |
| IS_DELETED | CHAR(1) | DEFAULT 'N' | Soft Delete |
### TB_PROJECT (프로젝트 마스터)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| PROJECT_ID | NUMBER | PK (Seq) | |
| PROJECT_TYPE | VARCHAR2(20) | NOT NULL | SI / SM / MIGRATION |
| PROJECT_NAME | VARCHAR2(150) | NOT NULL | 공식 프로젝트명 |
| CONTRACT_COMPANY | VARCHAR2(100) | NOT NULL | 원청 계약사 |
| END_USER_COMPANY | VARCHAR2(100) | NOT NULL | 최종 고객사 |
| CONTRACT_TYPE | VARCHAR2(20) | NOT NULL | TURN_KEY / MM |
| STATUS | VARCHAR2(20) | NOT NULL | PREPARING / ONGOING / COMPLETED / HOLD |
| START_DATE | DATE | NOT NULL | |
| END_DATE | DATE | NOT NULL | |
| WORK_LOCATION_TYPE | VARCHAR2(20) | NOT NULL | ON_SITE / REMOTE / HYBRID |
| WORK_ADDRESS | VARCHAR2(255) | NOT NULL | 파견지 물리 주소 |
| TECH_ENVIRONMENT | CLOB | NULLABLE | 기술 스택 묶음 |
| MAIN_TASK_DESC | CLOB | NOT NULL | 구축 목적 요약 |
| CLIENT_PM_NAME | VARCHAR2(50) | NULLABLE | |
| CLIENT_PM_CONTACT | VARCHAR2(100) | NULLABLE | |
| INTERNAL_MANAGER_ID | NUMBER | FK → TB_EMPLOYEE | 내부 영업 담당자 |
### TB_DISPATCH_HISTORY (파견 투입 이력 = 포트폴리오)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| DISPATCH_ID | NUMBER | PK (Seq) | 포트폴리오 라인 단건 |
| EMP_ID | NUMBER | FK → TB_EMPLOYEE | |
| PROJECT_ID | NUMBER | FK → TB_PROJECT | |
| START_DATE | DATE | NOT NULL | 실제 투입일 |
| END_DATE | DATE | NULLABLE | NULL=현재 투입중 |
| ROLE_TITLE | VARCHAR2(50) | NOT NULL | PM / PL / BACKEND / FRONTEND / DBA |
| CONTRIBUTION_RATE | NUMBER | DEFAULT 100 | 투입률(%) |
| INDIVIDUAL_TECH | VARCHAR2(255) | NOT NULL | 개인이 직접 사용한 기술 |
| PERFORMED_TASKS | CLOB | NOT NULL | 상세 수행 업무 |
| ACHIEVEMENTS | CLOB | NULLABLE | 트러블슈팅 사례 |
| CLIENT_FEEDBACK | CLOB | NULLABLE | 고객사 PM 평가 (본사 은닉) |
| INTERNAL_RATING | NUMBER | NULLABLE | 1~5 |
### TB_ISSUE_TICKET (SR 티켓 마스터)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| TICKET_ID | NUMBER | PK (Seq) | 고유 식별 번호 |
| PROJECT_ID | NUMBER | FK → TB_PROJECT | 발생 현장 |
| REQUESTER_ID | NUMBER | FK → TB_EMPLOYEE | SOS 발행 직원 |
| ASSIGNEE_ID | NUMBER | FK → TB_EMPLOYEE | 본사 해결사 |
| CATEGORY | VARCHAR2(30) | NOT NULL | BUG / FEATURE / SUPPORT / QA |
| PRIORITY | VARCHAR2(20) | NOT NULL | LOW / NORMAL / HIGH / CRITICAL |
| TITLE | VARCHAR2(255) | NOT NULL | |
| DESCRIPTION | CLOB | NOT NULL | 에러 재현 경로 |
| STATUS | VARCHAR2(20) | NOT NULL | OPEN / ASSIGNED / IN_PROGRESS / RESOLVED / CLOSED |
| DUE_DATE | DATE | NULLABLE | SLA 데드라인 |
| RESOLVED_AT | TIMESTAMP | NULLABLE | 해결 일시 |
| RESOLUTION_NOTE | CLOB | NULLABLE | 조치 내역 |
| SLA_WARN_FLAG | CHAR(1) | DEFAULT 'N' | 배치 알림 중복 방지 |
### TB_TICKET_COMMENT (티켓 타임라인 댓글)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| COMMENT_ID | NUMBER | PK (Seq) | |
| TICKET_ID | NUMBER | FK → TB_ISSUE_TICKET | |
| USER_ID | NUMBER | FK → TB_EMPLOYEE | 작성자 |
| COMMENT_TEXT | CLOB | NOT NULL | 분석 의견 |
| ATTACHED_FILE_URL | VARCHAR2(255) | NULLABLE | 첨부파일 경로 |
### TB_WORK_REPORT (업무 보고서)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| REPORT_ID | NUMBER | PK (Seq) | |
| DISPATCH_ID | NUMBER | FK → TB_DISPATCH_HISTORY | |
| USER_ID | NUMBER | FK → TB_EMPLOYEE | 작성자 |
| REPORT_TYPE | VARCHAR2(20) | NOT NULL | DAILY / WEEKLY / MONTHLY / RETURN |
| TARGET_DATE | DATE | NOT NULL | 기준일 |
| COMPLETED_TASKS | CLOB | NOT NULL | SR 연동 자동 취합 영역 |
| PLANNED_TASKS | CLOB | NOT NULL | 차기 계획 |
| ISSUES_AND_RISKS | CLOB | NULLABLE | 특이사항 |
| SUPPORT_REQUESTED | CLOB | NULLABLE | 본사 지원 요청 |
| STATUS | VARCHAR2(20) | NOT NULL | DRAFT / SUBMITTED / APPROVED / REJECTED |
| REVIEWER_ID | NUMBER | FK → TB_EMPLOYEE | 결재자 |
| REVIEW_COMMENT | CLOB | NULLABLE | 반려 사유 |
### TB_EQUIPMENT (IT 자산 마스터)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| EQUIPMENT_ID | NUMBER | PK (Seq) | |
| EQUIPMENT_TYPE | VARCHAR2(50) | NOT NULL | LAPTOP / MONITOR / TEST_DEVICE / ACCESSORY |
| MANUFACTURER | VARCHAR2(50) | NOT NULL | Apple / LG / Samsung |
| MODEL_NAME | VARCHAR2(100) | NOT NULL | MacBook Pro 16 M3 |
| SERIAL_NUMBER | VARCHAR2(100) | UNIQUE, NOT NULL | 기기 고유 바코드 |
| ASSET_CODE | VARCHAR2(50) | UNIQUE, NOT NULL | HQ-LP-2026-0001 |
| SPECIFICATIONS | CLOB (JSON) | NOT NULL | JSON 다품종 사양 |
| STATUS | VARCHAR2(20) | NOT NULL | AVAILABLE / IN_USE / REPAIRING / RETIRED / LOST |
| PURCHASE_DATE | DATE | NOT NULL | |
| WARRANTY_EXP_DATE | DATE | NOT NULL | |
| VERSION | NUMBER | DEFAULT 0 | **낙관적 락** |
### TB_EQUIPMENT_ASSIGNMENT (장비 지급/반납 이력)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| ASSIGNMENT_ID | NUMBER | PK (Seq) | |
| EQUIPMENT_ID | NUMBER | FK → TB_EQUIPMENT | |
| USER_ID | NUMBER | FK → TB_EMPLOYEE | 지급 대상 |
| ASSIGNED_DATE | DATE | NOT NULL | 출고일 |
| RETURNED_DATE | DATE | NULLABLE | NULL=사용중 |
| COND_ON_ASSIGN | VARCHAR2(255) | NOT NULL | 지급시 상태 |
| COND_ON_RETURN | VARCHAR2(255) | NULLABLE | 반납시 상태 |
### TB_EQUIPMENT_MAINTENANCE (장비 유지보수 이력)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| MAINTENANCE_ID | NUMBER | PK (Seq) | |
| EQUIPMENT_ID | NUMBER | FK → TB_EQUIPMENT | |
| REPORTED_BY | NUMBER | FK → TB_EMPLOYEE | 고장 접수자 |
| MAINTENANCE_TYPE | VARCHAR2(30) | NOT NULL | REPAIR / UPGRADE / INSPECTION / DISPOSAL |
| ISSUE_DESCRIPTION | CLOB | NOT NULL | 고장 증상 |
| ACTION_TAKEN | CLOB | NULLABLE | 조치 내역 |
| COST | NUMBER | DEFAULT 0 | 발생 비용 |
| REPORTED_DATE | DATE | NOT NULL | |
| RESOLVED_DATE | DATE | NULLABLE | |
### TB_TRAINING_PROGRESS (교육 진도)
| 컬럼 | 타입 | 제약 | 설명 |
|------|------|------|------|
| PROGRESS_ID | NUMBER | PK (Seq) | |
| USER_ID | NUMBER | FK → TB_EMPLOYEE | |
| COURSE_NAME | VARCHAR2(100) | NOT NULL | 과정명 |
| PROGRESS_RATE | NUMBER | DEFAULT 0 | 0~100 |
| STATUS | VARCHAR2(20) | NOT NULL | NOT_STARTED / ONGOING / COMPLETED |
## 4. ER 관계 요약
```
TB_EMPLOYEE ──1:N── TB_DISPATCH_HISTORY ──N:1── TB_PROJECT
└──1:N── TB_WORK_REPORT
│
└──1:N── TB_ISSUE_TICKET ──1:N── TB_TICKET_COMMENT
│
└──1:N── TB_EQUIPMENT_ASSIGNMENT ──N:1── TB_EQUIPMENT
│ └──1:N── TB_EQUIPMENT_MAINTENANCE
└──1:N── TB_TRAINING_PROGRESS
```
## 5. DDL 생성 참고 사항
- 모든 `SEQUENCE`: `INCREMENT BY 50` (Hibernate `allocationSize=50`과 정합)
- 모든 시퀀스명 컨벤션: `SEQ_TB_XXX`
- 모든 PK 컬럼: `NUMBER` 타입, 시퀀스 자동 할당
- `SPECIFICATIONS` (TB_EQUIPMENT): `CLOB`에 JSON 문자열 저장, 애플리케이션 레벨 직렬화/역직렬화
- 물리 스키마 DDL 파일: `src/main/resources/ddl/oracle_11g_schema.sql` 별도 관리
+412
View File
@@ -0,0 +1,412 @@
# API 명세서 (REST API Specification)
## 1. 공통 규격
### Base URL
```
http://{host}:{port}/api/v1
```
### 공통 응답 포맷
```json
// 성공
{ "success": true, "message": "...", "data": { ... } }
// 실패 (비즈니스 예외)
{ "success": false, "message": "...", "errorCode": "XXX_ERR_000", "data": null }
```
### 인증 헤더
```
Authorization: Bearer {jwt_access_token}
```
### 페이지네이션 (목록 조회)
```
Query Params: ?page=0&size=20&sort=createdAt,desc
Response: {
"content": [...],
"totalElements": 100,
"totalPages": 5,
"number": 0,
"size": 20
}
```
---
## 2. 직원 (Employee)
### 직원 목록 조회
```
GET /employees
Query: ?roleCode=MANAGER&empStatus=ACTIVE&dispatchStatus=DISPATCHED&page=0&size=20
Response: Page<EmployeeDto>
```
### 직원 단건 조회
```
GET /employees/{empId}
Response: EmployeeDto
```
### 직원 검색 (자동완성)
```
GET /employees/search?keyword=김코딩
Response: [{ empId: 1, name: "김코딩", ... }]
```
### 내 정보 조회
```
GET /employees/me
Response: EmployeeDto (현재 로그인 사용자)
```
### 직원 생성
```
POST /employees
Body: {
"loginId": "string",
"password": "string",
"name": "string",
"email": "string",
"roleCode": "EMPLOYEE",
"joinedDate": "2026-01-01"
}
```
### 직원 수정
```
PUT /employees/{empId}
Body: { "email": "new@company.com", ... }
```
### 직원 삭제 (Soft Delete)
```
DELETE /employees/{empId}
```
---
## 3. 프로젝트 (Project)
### 프로젝트 목록 조회
```
GET /projects
Query: ?type=SI&status=ONGOING&page=0&size=20
```
### 프로젝트 단건 조회
```
GET /projects/{projectId}
```
### 프로젝트 생성
```
POST /projects
Body: {
"projectType": "SI",
"projectName": "차세대 시스템 구축",
"contractCompany": "원청사",
"endUserCompany": "고객사",
"contractType": "TURN_KEY",
"startDate": "2026-01-01",
"endDate": "2026-12-31",
"workLocationType": "ON_SITE",
"workAddress": "서울시 강남구",
"mainTaskDesc": "...",
"internalManagerId": 1
}
```
---
## 4. 파견 이력 / 포트폴리오 (Dispatch)
### 파견 이력 목록 (직원별)
```
GET /employees/{empId}/dispatch-histories
```
### 파견 이력 등록
```
POST /dispatch-histories
Body: {
"empId": 1,
"projectId": 1,
"startDate": "2026-01-01",
"roleTitle": "BACKEND",
"individualTech": "Java, Spring, Oracle",
"performedTasks": "..."
}
```
### 포트폴리오 단건 조회
```
GET /dispatch-histories/{dispatchId}
```
---
## 5. SR 티켓 (Ticket)
### 티켓 목록 조회 (칸반)
```
GET /tickets
Query: ?category=BUG&priority=HIGH&status=OPEN&searchKeyword=오라클&page=0&size=50
Response: Page<{
ticketId, title, priority, status, category,
requesterName, assigneeName,
dueDate, createdAt,
isImminent: boolean // dueDate - now < 24h
}>
```
### 티켓 단건 상세 조회
```
GET /tickets/{ticketId}
Response: {
...ticketInfo,
comments: [{
commentId, userId, userName,
commentText, attachedFileUrl, createdAt
}]
}
```
### 티켓 생성
```
POST /tickets
Body: {
"projectId": 1,
"category": "BUG",
"priority": "HIGH",
"title": "오라클 쿼리 튜닝 필요",
"description": "실행 계획 상 Full Scan 발생..."
}
```
### 티켓 상태 전환
```
PUT /tickets/{ticketId}/status?status=IN_PROGRESS
Body (optional): {
"assigneeId": 5 // ASSIGNED 또는 IN_PROGRESS 전환 시 필요
}
Status Flow: OPEN → ASSIGNED → IN_PROGRESS → RESOLVED → CLOSED
```
### 티켓 해결 처리
```
PUT /tickets/{ticketId}/resolve
Body: {
"resolutionNote": "인덱스 재생성 및 통계 갱신 완료"
}
```
### 티켓 삭제 (Soft Delete)
```
DELETE /tickets/{ticketId}
```
---
## 6. 티켓 댓글 (Ticket Comment)
### 댓글 목록 조회
```
GET /tickets/{ticketId}/comments
```
### 댓글 등록
```
POST /tickets/{ticketId}/comments
Body: {
"commentText": "분석 스크립트 첨부합니다.",
"attachedFileUrl": "https://..."
}
```
### 댓글 삭제
```
DELETE /tickets/{ticketId}/comments/{commentId}
```
---
## 7. 업무 보고서 (Report)
### 보고서 목록 조회
```
GET /reports
Query: ?reportType=WEEKLY&status=SUBMITTED&userId=1&page=0&size=20
```
### 보고서 단건 조회
```
GET /reports/{reportId}
```
### 보고서 생성
```
POST /reports
Body: {
"dispatchId": 1,
"reportType": "WEEKLY",
"targetDate": "2026-05-21",
"completedTasks": "본사 시스템 SR 3건 해결 완료",
"plannedTasks": "차주 성능 테스트 진행",
"issuesAndRisks": "납기 일정 협의 필요",
"status": "DRAFT"
}
```
### 보고서 상태 변경 (제출)
```
PUT /reports/{reportId}/status?status=SUBMITTED
```
### 보고서 결재 처리 (관리자 전용)
```
PUT /reports/{reportId}/review
Body: {
"status": "APPROVED",
"reviewComment": "수고하셨습니다."
}
// 또는
Body: {
"status": "REJECTED",
"reviewComment": "완료 실적 내역 SR 상세 분석 내용 보강 요망"
}
```
### 보고서 삭제 (DRAFT 상태만)
```
DELETE /reports/{reportId}
```
---
## 8. IT 자산 (Equipment)
### 장비 목록 조회
```
GET /equipment
Query: ?type=LAPTOP&status=AVAILABLE&manufacturer=Apple&page=0&size=20
```
### 장비 단건 조회
```
GET /equipment/{equipId}
```
### 장비 등록
```
POST /equipment
Body: {
"equipmentType": "LAPTOP",
"manufacturer": "Apple",
"modelName": "MacBook Pro 16 M3",
"serialNumber": "F2G8H3J9K1",
"assetCode": "HQ-LP-2026-0001",
"specifications": { "cpu": "M3 Pro", "ram": "36GB", "ssd": "512GB" },
"purchaseDate": "2026-01-15",
"warrantyExpDate": "2028-01-15"
}
```
### 장비 정보 수정
```
PUT /equipment/{equipId}
```
### 장비 삭제 (Soft Delete)
```
DELETE /equipment/{equipId}
```
### 장비 지급
```
POST /equipment/{equipId}/assign
Body: {
"assigneeId": 2,
"conditionNote": "미개봉 신품"
}
- 낙관적 락(version) 충돌 시 409 Conflict
```
### 장비 반납
```
PUT /equipment/{equipId}/return
Body: {
"conditionNote": "액정 파손 - 수리 필요"
}
```
### 장비 지급 이력 조회
```
GET /equipment/{equipId}/assignments
```
### 장비 유지보수 등록
```
POST /equipment/{equipId}/maintenance
Body: {
"maintenanceType": "REPAIR",
"issueDescription": "키보드 침수 작동 불가",
"actionTaken": "키보드 상판 교체 완료",
"cost": 150000
}
```
### 장비 유지보수 이력 조회
```
GET /equipment/{equipId}/maintenances
```
---
## 9. 교육 (Training)
### 교육 진도 조회 (내 것)
```
GET /training/me
Response: [{ courseName, progressRate, status, updatedAt }]
```
### 직원별 교육 진도 조회 (관리자)
```
GET /training?userId=1
```
### 교육 진도 업데이트
```
PUT /training/{progressId}
Body: { "progressRate": 80, "status": "ONGOING" }
```
### 교육 요약 (관리자 대시보드)
```
GET /training/summary
Response: [{ courseName, totalEnrolled, completedCount, avgProgress }]
```
---
## 10. 알림 (Notification)
### 읽지 않은 알림 카운트
```
GET /notifications/unread
Response: { "count": 3 }
```
### 내 알림 목록
```
GET /notifications?page=0&size=20
```
### 알림 읽음 처리
```
PUT /notifications/{notificationId}/read
```
+238
View File
@@ -0,0 +1,238 @@
# 화면 설계 명세서 (UI & Screen Specification)
**프론트엔드:** Next.js 14+ (App Router), TypeScript, Tailwind CSS, Pinia
## 1. 전역 레이아웃 (Global Layout)
```
┌─────────────────────────────────────────────────┐
│ GNB (Global Navigation Bar) │
│ ┌──────┬─────────────────────────────────┬──┐ │
│ │ Logo │ (검색/제목) │🔔│👤│ │
│ └──────┴─────────────────────────────────┴──┘ │
├──────┬──────────────────────────────────────────┤
│ LNB │ Content Area │
│ │ │
│ Menu │ (Page Component Rendering) │
│ 1 │ │
│ │ │
│ Menu │ │
│ 2 │ │
│ │ │
│ Menu │ │
│ 3 │ │
│ │ │
└──────┴──────────────────────────────────────────┘
```
### GNB (Global Navigation Bar)
- **알림 뱃지(🔔):** `GET /api/v1/notifications/unread` 폴링 — 0개면 숨김
- **프로필:** `GET /api/v1/employees/me` — 사용자명 및 권한 표시
### LNB (Left Navigation Bar) — RBAC 기반 동적 메뉴
| 메뉴 | EMPLOYEE | MANAGER | ADMIN |
|------|----------|---------|-------|
| 내 포트폴리오 | ✅ | ❌ | ❌ |
| SR 티켓 관리 | ✅ | ✅ | ✅ |
| 업무 보고서 | ✅ | ✅ | ✅ |
| 교육 현황 | ✅ | ✅ | ✅ |
| 프로젝트 관리 | ❌ | ✅ | ✅ |
| 장비 자산 관리 | ❌ | ✅ | ✅ |
| 직원 관리 | ❌ | ❌ | ✅ |
| 공통 코드 관리 | ❌ | ❌ | ✅ |
---
## 2. SR 티켓 칸반 보드 (`TicketBoardView.vue`)
### UI 구조
```
┌─────────────────────────────────────────────────────────┐
│ [필터 영역] │
│ 카테고리: [BUG ▼] 우선순위: [HIGH ▼] 검색: [________] │
├─────────┬──────────┬──────────┬──────────┬──────────────┤
│ OPEN │ ASSIGNED │ IN_PROG │ RESOLVED │ CLOSED │
│ (3) │ (2) │ (5) │ (8) │ (12) │
├─────────┼──────────┼──────────┼──────────┼──────────────┤
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │ │
│ │Bug │ │ │High │ │ │Supp │ │ │Bug │ │ │
│ │DB │ │ │API │ │ │배포 │ │ │튜닝 │ │ │
│ │튜닝 │ │ │에러 │ │ │지원 │ │ │완료 │ │ │
│ │🔴⚠️ │ │ │ │ │ │ │ │ │ │ │ │
│ └─────┘ │ └─────┘ │ └─────┘ │ └─────┘ │ │
│ ┌─────┐ │ │ ┌─────┐ │ │ │
│ │Feat │ │ │ │Bug │ │ │ │
│ │화면 │ │ │ │SQL │ │ │ │
│ │개발 │ │ │ │튜닝 │ │ │ │
│ └─────┘ │ │ └─────┘ │ │ │
└─────────┴──────────┴──────────┴──────────┴──────────────┘
```
### 핵심 로직
- **칸반 컬럼:** 상태별 4단 (상단에 컬럼별 카운트)
- **기한 임박:** `dueDate - now < 24h` → 카드 좌상단 🔴 경고 레이블 + 애니메이션
- **드래그 앤 드롭:** 상태 전환 시 `PUT /api/v1/tickets/{id}/status?status=NEW_STATUS`
- **티켓 카드 클릭:** 라우터 push → `/tickets/{ticketId}` (상세 페이지)
---
## 3. SR 티켓 상세/타임라인 (`TicketDetailView.vue`)
### UI 구조
```
┌─────────────────────────────────────────────────────────┐
│ [← 뒤로] [삭제] [상태 변경: IN_PROGRESS ▼] │
├─────────────────────────────────────────────────────────┤
│ 📋 티켓 정보 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 제목: 오라클 쿼리 튜닝 필요 │ │
│ │ 상태: OPEN | 우선순위: HIGH | 카테고리: BUG │ │
│ │ 요청자: 김개발 | 담당자: 미배정 | SLA: 2026-05-22 │ │
│ │ 설명: 실행 계획 상 Full Scan 발생 중... │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ 📎 첨부파일 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ [execution_plan.png] [error_log.txt] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ 💬 타임라인 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 2026-05-21 14:32 | 김개발 │ │
│ │ 오라클 실행 계획 첨부합니다. │ │
│ │ 📎 [execution_plan.png] │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ 2026-05-21 15:10 | 이튜너 (본사) │ │
│ │ 인덱스 힌트 사용해보세요: /*+ INDEX() */ │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ 2026-05-21 16:00 | 김개발 │ │
│ │ 힌트 적용 후 3초→0.5초로 개선되었습니다! ✅ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 댓글 입력: [________________________________] 📎 │ │
│ │ [등록] │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 핵심 로직
- **댓글 등록:** `POST /api/v1/tickets/{id}/comments` → 타임라인 최하단 prepend
- **파일 업로드:** `<input type="file">` → S3/서버 업로드 → URL 반환 → 댓글 첨부
- **상태 전환 버튼:** 현재 상태에 따라 다음 가능한 액션 버튼 노출 (OPEN→ASSIGNED→IN_PROGRESS→RESOLVED→CLOSED)
- **종료된 티켓 봉인:** `status == CLOSED` 시 입력폼 비활성화 + 뱃지 표시
---
## 4. 장비 인벤토리 (`EquipmentInventoryView.vue`)
### UI 구조
```
┌─────────────────────────────────────────────────────────┐
│ 📊 장비 현황 요약 │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │전체 │ │가용 │ │사용중 │ │수리중 │ │폐기 │ │
│ │45 │ │12 │ │28 │ │3 │ │2 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ [필터: LAPTOP ▼] [제조사: Apple ▼] [검색: ____________] │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 자산코드 | 모델명 | 시리얼 | 상태 | 액션 │ │
│ ├──────────────────────────────────────────────────┤ │
│ │HQ-LP-001|MacBook |F2G8... |IN_USE |[반납] │ │
│ │HQ-LP-002|MacBook |H3J9... |AVAILABLE|[지급] │ │
│ │HQ-MO-001|LG 27UN880|L7K2... |IN_USE |[반납] │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
--- 지급 모달 ---
┌──────────────────────────────────────────┐
│ 장비 지급: HQ-LP-002 MacBook Pro M3 │
│ │
│ 대상자 검색: [김_______] │
│ ┌──────────────────────────────────┐ │
│ │ 김코딩 (BACKEND, 파견중) │ │
│ │ 김개발 (DBA, 파견중) │ │
│ └──────────────────────────────────┘ │
│ │
│ 지급 상태 코멘트: [미개봉 신품________] │
│ [취소] [지급 확정] │
└──────────────────────────────────────────┘
```
### 핵심 로직
- **상태 요약 카드:** 각 상태별 장비 카운트 → `GET /api/v1/equipment/summary`
- **조건부 액션 버튼:** `AVAILABLE` → [지급], `IN_USE` → [반납], `REPAIRING` → [수리 완료]
- **사원 검색 자동완성:** `GET /api/v1/employees/search?keyword=` + **300ms 디바운싱**
- **낙관적 락 충돌:** 지급 시 `version` 불일치 → 409 → 토스트 "다른 사용자가 먼저 처리했습니다"
---
## 5. 업무 보고서 (`WorkReportView.vue`)
### UI 구조
```
┌─────────────────────────────────────────────────────────┐
│ 📝 업무 보고서 작성 │
│ │
│ 보고 유형: [WEEKLY ▼] 기준일자: [2026-05-21] │
│ │
│ ✅ 완료 실적 (SR 자동 연동) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ SR-2026-042: 오라클 인덱스 튜닝 (RESOLVED) │ │
│ │ SR-2026-043: 배포 파이프라인 오류 수정 (CLOSED) │ │
│ │ ※ 해당 주차 해결 완료한 SR 내역 자동 바인딩 │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ 완료 실적: [________________________________________] │
│ 차기 계획: [________________________________________] │
│ 특이사항: [_________________________________________] │
│ 본사 지원 요청: [___________________________________] │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 관리자 피드백 (김매니저): 수고하셨습니다. ✅ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ [임시저장] [제출하기] │
└─────────────────────────────────────────────────────────┘
```
### 결재 상태 흐름
```
DRAFT ── [제출] ──> SUBMITTED ── [승인] ──> APPROVED
│
└── [반려] ──> DRAFT (관리자 피드백 필요)
```
### 핵심 로직
- **SR 자동 연동:** 페이지 진입 시 `GET /api/v1/reports/sr-auto-complete?targetDate=...` → 해당 주차 해결 SR 바인딩
- **임시저장 vs 제출:** DRAFT → SUBMITTED 전환 전 벨리데이션 (필수 항목 체크)
- **결재 피드백:** `REJECTED` 상태에서 관리자 피드백 박스 조건부 렌더링
---
## 6. 상태 천이 다이어그램
### SR 티켓
```
OPEN ──[담당자 배정]──> ASSIGNED ──[처리시작]──> IN_PROGRESS ──[해결]──> RESOLVED ──[확인종료]──> CLOSED
│ │ │
└──[취소/삭제]──────────┴───────────────────────┴── (Soft Delete)
```
### 업무 보고서
```
DRAFT ──[제출]──> SUBMITTED ──[승인]──> APPROVED
│
└──[반려]──> DRAFT (+ 피드백)
```
### 장비
```
AVAILABLE ──[지급]──> IN_USE ──[반납]──> AVAILABLE
│ │
└──[고장접수]──> REPAIRING ──[수리완료]──> AVAILABLE
│
└──[폐기]──> RETIRED
```
+321
View File
@@ -0,0 +1,321 @@
# 개발 가이드 및 컨벤션 (Development Guide)
## 1. 프로젝트 디렉토리 구조
### Backend (Spring Boot)
```
src/main/java/com/hq/support/portal/
├── global/
│ ├── common/
│ │ └── ApiResponse.java // 공통 응답 래퍼
│ ├── config/
│ │ ├── AsyncConfig.java // @Async 스레드 풀
│ │ ├── JpaAuditConfig.java // @EnableJpaAuditing
│ │ ├── BatchConfig.java // Spring Batch 메타 설정
│ │ └── SecurityConfig.java // Security Filter Chain
│ ├── error/
│ │ ├── ErrorCode.java // 에러코드 Enum 매트릭스
│ │ ├── GlobalExceptionHandler.java // @RestControllerAdvice
│ │ └── exception/
│ │ └── BusinessException.java // 최상위 예외 클래스
│ └── security/
│ ├── JwtTokenProvider.java // JWT 생성/검증
│ └── JwtAuthenticationFilter.java // 인증 필터
│
├── domain/
│ ├── base/
│ │ └── BaseEntity.java // createdAt, updatedAt, isDeleted
│ ├── employee/
│ │ ├── entity/TbEmployee.java
│ │ ├── repository/EmployeeRepository.java
│ │ └── exception/InvalidEmployeeException.java
│ ├── project/
│ │ ├── entity/TbProject.java
│ │ └── repository/ProjectRepository.java
│ ├── dispatch/
│ │ ├── entity/TbDispatchHistory.java
│ │ └── repository/DispatchRepository.java
│ ├── ticket/
│ │ ├── entity/TbIssueTicket.java
│ │ ├── entity/TbTicketComment.java
│ │ ├── repository/TicketRepository.java
│ │ ├── controller/IssueTicketController.java
│ │ ├── dto/TicketDto.java
│ │ ├── service/IssueTicketService.java
│ │ └── event/TicketCreatedEvent.java
│ ├── report/
│ │ ├── entity/TbWorkReport.java
│ │ └── repository/ReportRepository.java
│ ├── equipment/
│ │ ├── entity/TbEquipment.java
│ │ ├── entity/TbEquipmentAssignment.java
│ │ ├── entity/TbEquipmentMaintenance.java
│ │ └── repository/EquipmentRepository.java
│ └── training/
│ ├── entity/TbTrainingProgress.java
│ └── repository/TrainingRepository.java
│
└── infra/
└── notification/
├── listener/NotificationEventListener.java
└── scheduler/SlaJobScheduler.java
src/main/resources/
├── application.yml
└── ddl/oracle_11g_schema.sql
```
### Frontend (Next.js 14+)
```
src/
├── app/
│ ├── (auth)/login/page.tsx
│ ├── tickets/
│ │ ├── page.tsx // 칸반 보드
│ │ └── [ticketId]/page.tsx // 상세/타임라인
│ ├── equipment/page.tsx // 장비 인벤토리
│ ├── reports/page.tsx // 업무 보고서
│ ├── training/page.tsx // 교육 진도
│ ├── employees/page.tsx // 직원 관리 (ADMIN)
│ └── layout.tsx // GNB + LNB 레이아웃
├── components/
│ ├── layout/
│ │ ├── GNB.tsx
│ │ └── LNB.tsx
│ ├── ticket/
│ │ ├── KanbanBoard.tsx
│ │ ├── TicketCard.tsx
│ │ └── TimelineComment.tsx
│ ├── equipment/
│ │ ├── EquipmentTable.tsx
│ │ └── AssignModal.tsx
│ └── common/
│ ├── ApiResponse.ts
│ └── Pagination.tsx
├── stores/
│ ├── authStore.ts
│ └── notificationStore.ts
├── services/
│ ├── apiClient.ts // Axios 인스턴스 + 인터셉터
│ ├── ticketService.ts
│ ├── equipmentService.ts
│ └── reportService.ts
└── types/
└── index.ts // 전역 TypeScript 타입
```
---
## 2. Backend 코딩 컨벤션
### 2.1 엔티티 네이밍
- **테이블명:** `TB_XXX` (Oracle 11g 컨벤션)
- **엔티티 클래스명:** `TbXxx.java` (PascalCase, 테이블명 매핑)
- **PK 컬럼:** `xxx_id` (NUMBER, Sequence 할당)
### 2.2 ID 생성 전략 (Oracle 11g 최적화)
```java
@Entity
@SequenceGenerator(name = "SEQ_TB_TICKET", sequenceName = "SEQ_TB_TICKET", allocationSize = 50)
public class TbIssueTicket {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TB_TICKET")
private Long ticketId;
}
```
- Oracle DDL 시퀀스: `CREATE SEQUENCE SEQ_TB_TICKET INCREMENT BY 50;`
- `allocationSize = 50` + `INCREMENT BY 50` 반드시 정합
### 2.3 Soft Delete 패턴
```java
@SQLDelete(sql = "UPDATE tb_issue_ticket SET is_deleted = 'Y' WHERE ticket_id = ?")
@Where(clause = "is_deleted = 'N'")
public class TbIssueTicket { ... }
```
- 모든 엔티티에 `@SQLDelete` + `@Where` 선언
- `BaseEntity`에 `isDeleted` 컬럼 공통 상속
### 2.4 레이어드 아키텍처 규칙
| 레이어 | 책임 | 규칙 |
|--------|------|------|
| Controller | HTTP 진입점 | DTO 반환, `@Valid` 검증, 서비스 호출만 |
| Service | 비즈니스 로직 | `@Transactional`, 예외 throw, 이벤트 발행 |
| Repository | DB 접근 | Spring Data JPA, `Specification` 동적 쿼리 |
| DTO | 데이터 전송 | Request/Response 분리, 엔티티 직접 노출 금지 |
### 2.5 예외 처리 계층
```java
// 최상위 예외
public class BusinessException extends RuntimeException {
private final ErrorCode errorCode;
}
// 도메인별 구체 예외
public class TicketClosedException extends BusinessException {
public TicketClosedException() {
super(ErrorCode.CLOSED_TICKET_MOD);
}
}
// ControllerAdvice에서 ErrorCode → ApiResponse 자동 변환
```
### 2.6 EDA (이벤트 기반 알림)
```java
// 발행
@Service
public class IssueTicketService {
@Autowired
private ApplicationEventPublisher publisher;
public TicketDto createTicket(TicketCreateReq req) {
TbIssueTicket ticket = repository.save(req.toEntity());
publisher.publishEvent(new TicketCreatedEvent(ticket));
return TicketDto.from(ticket);
}
}
// 구독 (트랜잭션 완료 후 비동기 실행)
@Component
public class NotificationEventListener {
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleTicketCreated(TicketCreatedEvent event) {
// Slack/Email 발송 (메인 트랜잭션과 완전 격리)
}
}
```
---
## 3. Frontend 코딩 컨벤션
### 3.1 API 통신 (Axios)
```typescript
// apiClient.ts - 공통 인터셉터
const apiClient = axios.create({
baseURL: '/api/v1',
timeout: 10000,
});
apiClient.interceptors.response.use(
(res) => res.data, // ApiResponse.data 자동 언래핑
(err) => {
const { errorCode, message } = err.response.data;
// errorCode 기반 전역 토스트/알림
return Promise.reject({ errorCode, message });
}
);
```
### 3.2 Pinia Store 패턴
```typescript
// stores/authStore.ts
export const useAuthStore = defineStore('auth', () => {
const user = ref<Employee | null>(null);
const roleCode = computed(() => user.value?.roleCode);
async function fetchMe() {
const res = await apiClient.get('/employees/me');
user.value = res.data;
}
return { user, roleCode, fetchMe };
});
```
### 3.3 컴포넌트 네이밍
- **페이지 컴포넌트:** `page.tsx` (App Router), 도메인 폴더 하위
- **UI 컴포넌트:** `PascalCase.tsx` (단일 책임)
- **Props:** Interface 선언 후 `defineProps<Props>()`
- **Event Emit:** `defineEmits<{ eventName: [payload: type] }>()`
---
## 4. 개발 환경 설정
### Backend (application.yml)
```yaml
spring:
datasource:
url: jdbc:oracle:thin:@localhost:1521:XE
username: portal
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: none # 운영 DDL은 별도 스크립트 관리
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle10gDialect
batch:
jdbc:
initialize-schema: always # 배치 메타 테이블 자동 생성
jwt:
secret: ${JWT_SECRET}
access-token-validity: 3600000 # 1시간
refresh-token-validity: 604800000 # 7일
```
### Frontend (.env.local)
```
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api/v1
NEXT_PUBLIC_WS_URL=ws://localhost:8080/ws/notifications
```
---
## 5. 빌드 및 배포
### CI/CD (GitHub Actions)
- **트리거:** `release` 생성 시에만 운영 빌드
- **Push 이벤트:** Lint + Test만 실행 (배포 없음)
- **파이프라인:** Build → Test → Docker Image → Deploy (Nginx Proxy Manager)
### 로컬 빌드 검증
```bash
# Backend
./gradlew clean build
# Frontend
npm run build
npm run lint
```
### Nginx Proxy Manager
- SSL 인증서 관리
- `/api/*` → Backend Container (Reverse Proxy)
- `/*` → Frontend Static/Node Server
- Rate Limit 설정 (API abuse 방어)
---
## 6. DB DDL 관리 규칙
- DDL 파일: `src/main/resources/ddl/oracle_11g_schema.sql`
- 모든 시퀀스: `CREATE SEQUENCE SEQ_TB_XXX INCREMENT BY 50 START WITH 1`
- `ddl-auto: none` — DDL은 스크립트로만 관리 (Hibernate 자동 생성 금지)
- 스키마 변경 시 DDL 파일 버전 관리 (Git)
- 인덱스: 자주 조회하는 컬럼(상태, 날짜, 외래키)에 인덱스 별도 추가
- 공통 코드 데이터: `INSERT` 문으로 시드 데이터 관리
---
## 7. 커밋 컨벤션
한국어로 명확하게 작성 (팀 협업 가독성 보장)
```
feat: SR 티켓 칸반 보드 API 구현
fix: 장비 지급 시 낙관적 락 충돌 해결
refactor: BaseEntity 공통 필드 추출
docs: DB 설계서 최신화
```
### 브랜치 전략
```
main ← develop ← feature/{domain}-{description}
- feature/issue-ticket-kanban
- feature/equipment-assign-optimistic-lock
- fix/report-status-transition-bug
```
+377
View File
@@ -0,0 +1,377 @@
---
name: Premium Enterprise — SR System HQ Helpdesk
version: 2.0.0
merged_from:
- Stitch/Premium Enterprise (v1)
- project_m_dashboard_shell_1
- project_m_dashboard_shell_2
colors:
# === Canvas & Surface ===
surface: '#f8f9ff'
surface-dim: '#cbdbf5'
surface-bright: '#f8f9ff'
surface-container-lowest: '#ffffff'
surface-container-low: '#eff4ff'
surface-container: '#e5eeff'
surface-container-high: '#dce9ff'
surface-container-highest: '#d3e4fe'
on-surface: '#0b1c30'
on-surface-variant: '#464555'
inverse-surface: '#213145'
inverse-on-surface: '#eaf1ff'
outline: '#777587'
outline-variant: '#c7c4d8'
surface-tint: '#4d44e3'
# === Brand Indigo ===
primary: '#3525cd'
on-primary: '#ffffff'
primary-container: '#4f46e5'
on-primary-container: '#dad7ff'
inverse-primary: '#c3c0ff'
# === Accent Purple ===
secondary: '#712ae2'
on-secondary: '#ffffff'
secondary-container: '#8a4cfc'
on-secondary-container: '#fffbff'
# === Semantic Amber (tertiary, for ITAM warnings) ===
tertiary: '#7e3000'
on-tertiary: '#ffffff'
tertiary-container: '#a44100'
on-tertiary-container: '#ffd2be'
# === Semantic Error ===
error: '#ba1a1a'
on-error: '#ffffff'
error-container: '#ffdad6'
on-error-container: '#93000a'
# === Fixed Tints ===
primary-fixed: '#e2dfff'
primary-fixed-dim: '#c3c0ff'
on-primary-fixed: '#0f0069'
on-primary-fixed-variant: '#3323cc'
secondary-fixed: '#eaddff'
secondary-fixed-dim: '#d2bbff'
on-secondary-fixed: '#25005a'
on-secondary-fixed-variant: '#5a00c6'
tertiary-fixed: '#ffdbcc'
tertiary-fixed-dim: '#ffb695'
on-tertiary-fixed: '#351000'
on-tertiary-fixed-variant: '#7b2f00'
background: '#f2f3f8'
on-background: '#0b1c30'
surface-variant: '#d3e4fe'
# === NEW: Status / Semantic Colors (from reference) ===
status-open: '#3b82f6' # Blue — SR Open
status-open-bg: '#eff6ff'
status-resolved: '#10b981' # Emerald — Resolved
status-resolved-bg: '#ecfdf5'
status-critical: '#ef4444' # Red — Critical Priority
status-critical-bg: '#fef2f2'
status-pending: '#f59e0b' # Amber — Pending / In-progress
status-pending-bg: '#fffbeb'
status-closed: '#6b7280' # Gray — Closed / Archived
status-closed-bg: '#f9fafb'
# === NEW: Project Dot Colors (from shell reference) ===
project-dot-green: '#22c55e'
project-dot-orange: '#f97316'
project-dot-blue: '#3b82f6'
project-dot-pink: '#ec4899'
project-dot-purple: '#a855f7'
project-dot-gray: '#d1d5db'
typography:
h1:
fontFamily: Outfit
fontSize: 32px
fontWeight: '600'
lineHeight: '1.2'
h2:
fontFamily: Outfit
fontSize: 24px
fontWeight: '600'
lineHeight: '1.3'
h3:
fontFamily: Outfit
fontSize: 20px
fontWeight: '500'
lineHeight: '1.4'
h4:
fontFamily: Outfit
fontSize: 16px
fontWeight: '600'
lineHeight: '1.4'
body-lg:
fontFamily: Inter
fontSize: 16px
fontWeight: '400'
lineHeight: '1.6'
body-md:
fontFamily: Inter
fontSize: 14px
fontWeight: '400'
lineHeight: '1.5'
body-sm:
fontFamily: Inter
fontSize: 12px
fontWeight: '400'
lineHeight: '1.5'
data-label:
fontFamily: Inter
fontSize: 12px
fontWeight: '500'
lineHeight: '1.2'
letterSpacing: 0.02em
button:
fontFamily: Inter
fontSize: 14px
fontWeight: '600'
lineHeight: '1'
nav-item:
fontFamily: Inter
fontSize: 14px
fontWeight: '500'
lineHeight: '1'
nav-group-label:
fontFamily: Inter
fontSize: 11px
fontWeight: '600'
lineHeight: '1'
letterSpacing: 0.08em
textTransform: uppercase
rounded:
sm: 0.25rem
DEFAULT: 0.5rem
md: 0.75rem
lg: 1rem
xl: 1.5rem
full: 9999px
spacing:
base: 4px
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 32px
gutter: 24px
margin-page: 32px
---
## Brand & Style
This design system establishes an **"Approachable Enterprise"** aesthetic for the SR System — a HQ Helpdesk and IT Asset Management Portal for dispatched SI/SM engineers. It balances the rigor of data-dense corporate tools with a modern, human-centric softness.
The visual style is **Corporate Modern with Tactile Influences**. It utilizes generous whitespace, a high-quality Off-white canvas (`#F2F3F8`), and soft ambient shadows to create clear spatial hierarchy. The intent is to lower cognitive load for power users while maintaining a premium feel through refined typography and intentional roundness.
**Merged from:** Stitch Premium Enterprise v1 + Project M. Dashboard Shell (expanded & icon-collapsed variants).
---
## Colors
The palette is anchored by **Deep Indigo** for primary actions and brand presence. The canvas follows a "Softer Background" philosophy:
- **Canvas:** `#F2F3F8` Off-white, slightly cooler than the v1 value, to contrast white cards more clearly.
- **Surfaces:** Pure White `#FFFFFF` for cards and main content containers.
- **Brand Indigo:** `#4F46E5` for primary buttons, active nav states, and key CTAs.
- **Accents:** Soft purples (`#712AE2`) for secondary actions; muted semantic colors for SR status badges.
- **Status Colors (NEW):** A distinct set of semantic tokens for SR ticket states (Open, In-Progress, Resolved, Closed, Critical) and ITAM asset states. These must remain consistent across all badge, chip, and table row usages.
- **Project Dot Colors (NEW):** 5 distinct hues (green, orange, blue, pink, purple) used as visual identifiers for active dispatch projects in the sidebar project list.
---
## Typography
Dual-font strategy:
- **Outfit** — Headlines, section titles, sidebar brand name.
- **Inter** — All data labels, body text, nav items, badges.
Hierarchy is achieved through weight and tonal contrast. Data labels use `letter-spacing: 0.02em` and `font-weight: 500`.
Nav group labels (e.g., "MY PROJECTS", "MAIN MENU") use `font-size: 11px`, `font-weight: 600`, `letter-spacing: 0.08em`, uppercase.
---
## Layout & Spacing
### Sidebar Behavior (UPDATED from reference)
The sidebar has **two responsive states**:
| State | Width | Content |
|---|---|---|
| **Expanded** (default, ≥1280px) | 250px | Logo + label + full nav text + project list + CTA card |
| **Collapsed** (manual toggle or ≤1024px) | 64px | Icon-only nav + project color dots + icon CTA |
A `>>` / `<<` toggle chevron is placed in the top bar to switch states. Active state = pill-shaped highlight (`8px–12px` rounded rect) in `primary-fixed` tint.
### Top Navigation Bar
- Height: 64px, white background, `1px solid outline-variant` bottom border.
- **Left zone:** Sidebar toggle chevron + Search bar (centered, `#F3F4F6` bg, 12px radius).
- **Right zone:** Calendar icon → Chat icon → Bell icon (with unread badge) → `[Avatar] Name / Location ▾`.
### Main Content Grid
- 12-column fluid grid with 24px gutters, 32px page margins.
- Summary card row at top: 4 equal columns (SR counts, active dispatches, equipment status, pending reports).
- Below: mix of 8+4 or 6+6 column splits for tables + detail panels.
### Page Container
All pages follow a standardized container pattern for layout consistency:
```tsx
className="p-4 sm:p-6 lg:p-8" // Responsive padding
max-w-7xl mx-auto // Content max-width (or max-w-5xl for profile)
```
**Padding:**
- Mobile (< 640px): `p-4` (16px)
- Tablet (640–1024px): `p-6` (24px)
- Desktop (≥ 1024px): `p-8` (32px)
**Max-width:**
- Standard pages: `max-w-7xl` (1280px)
- Profile page: `max-w-5xl` (1024px) — lighter content density
**Components that must use this pattern:**
- All `src/app/(main)/*/page.tsx` files
- All sub-page files in route groups
- The root div of each page should directly use `p-4 sm:p-6 lg:p-8`
**Exceptions:**
- Modals and overlays (use their own sizing)
- The sidebar and header (managed by MainShell)
---
## Elevation & Depth
| Level | Surface | Treatment |
|---|---|---|
| **0 — Canvas** | `#F2F3F8` | Background only |
| **1 — Cards / Sidebar** | White | `1px border (#E5E7EB)` + `box-shadow: 0 1px 3px rgba(0,0,0,0.06)` |
| **2 — Floating / Active** | White | `box-shadow: 0 4px 16px rgba(0,0,0,0.08)` |
| **3 — Modal / Overlay** | White | `box-shadow: 0 20px 48px rgba(0,0,0,0.14)` + backdrop blur |
Hover states increase shadow spread; border color stays constant.
---
## Shapes
- **Content Cards:** `border-radius: 16px` (lg)
- **Buttons / Inputs:** `12px–16px`
- **Sidebar Nav Active State:** Pill-shape or `8px–12px` rounded rect background
- **Status Badges / Chips:** Pill (`border-radius: 9999px`), low-opacity bg tint + high-contrast text
- **Avatars:** `border-radius: 9999px` (circular)
- **Project Dots:** `border-radius: 9999px`, `width: 8px`, `height: 8px`
---
## Components
### Sidebar (UPDATED)
**Expanded State (250px)**
```
┌─────────────────────────┐
│ 🟣 SR System │ ← Logo dot (gradient circle) + Outfit h4
├─────────────────────────┤
│ MAIN MENU │ ← nav-group-label style
│ ⊞ Dashboard │ ← Active: pill bg (#EEF2FF), text (#4F46E5)
│ 📋 SR Issues │
│ 🚀 Dispatch │
│ 💻 ITAM │
│ 📊 Work Reports │
│ 🎓 Training │
│ ⚙️ Settings │
├─────────────────────────┤
│ MY PROJECTS [+] │ ← nav-group-label + icon button
│ 🟢 Samsung Pay SI │
│ 🟠 LG CNS SM │
│ 🔵 Kakao Maintenance │
│ 🔴 SK Hynix Dev │
├─────────────────────────┤
│ ╭───────────────────╮ │
│ │ 💡 Quick Note │ │ ← CTA Card: #FFF9EC bg, amber accent
│ │ Share updates │ │
│ │ [Write a message] │ │
│ ╰───────────────────╯ │
└─────────────────────────┘
```
**Collapsed State (64px)**
Icons only; project list shows 8px color dots; CTA card reduces to single 💡 icon button.
---
### Top Navigation Bar
- **Search:** `placeholder="Search issues, assets, employees..."` — 400px wide at center.
- **Icons (right):** Calendar (`📅`), Chat/Message (`💬`), Bell (`🔔` with red dot if unread).
- **Profile:** Circular avatar (32px) + `Inter Medium` name + subtitle (department/location) + dropdown `▾`.
---
### Summary Cards (Dashboard Header Row)
4 cards with colored left-border accent and inline sparkline or icon:
1. **Open SR Tickets** — Blue left-border, count + delta vs last week.
2. **Active Dispatches** — Indigo left-border, headcount + project list mini chips.
3. **Equipment In-Use** — Amber left-border, asset count + status bar.
4. **Pending Reports** — Purple left-border, overdue count highlighted in red.
---
### Buttons & Controls
- **Primary:** `bg: #4F46E5`, white text, `12px` radius, `px-16 py-8`, Inter SemiBold 14px.
- **Secondary Outlined:** transparent bg, `1px solid #4F46E5`, indigo text.
- **Ghost:** No border, gray text, hover bg `#F3F4F6`.
- **Danger:** `bg: #EF4444` for destructive actions.
- **'New SR' (Primary CTA):** In Top Nav right area — Primary style with `+` icon prefix.
---
### Status Badges / Chips (SR Tickets)
```
OPEN → bg: #EFF6FF, text: #3B82F6, border: none
IN-PROGRESS→ bg: #FFFBEB, text: #F59E0B
RESOLVED → bg: #ECFDF5, text: #10B981
CLOSED → bg: #F9FAFB, text: #6B7280
CRITICAL → bg: #FEF2F2, text: #EF4444, font-weight: 600
```
All pill-shaped (`border-radius: 9999px`), `px-8 py-2`, `font-size: 12px`.
---
### Data Tables
- Header: `font-size: 12px`, Inter SemiBold, `letter-spacing: 0.04em`, uppercase, `color: #6B7280`.
- Row hover: `bg: #F8F9FF`.
- Selected row: `bg: #EEF2FF`.
- Pagination: Simple `< 1 2 3 ... 12 >` strip, `border-top: 1px solid #E5E7EB`.
- Column widths: flexible, min-width per type (`ID: 60px, Date: 100px, Status: 120px, Text: auto`).
---
### SR Issue Detail Panel
A right-side slide-over panel (480px) or full-page route:
- **Header:** Title, SR ID badge, Status badge, Priority chip, Assignee avatar.
- **Thread / Comments:** Chat-bubble layout, alternating left (requester) / right (HQ support).
- **Code Block:** Dark bg (`#1E1E2E`), monospace font (JetBrains Mono 13px), copy button.
- **Attachment Area:** File chip list with extension icon + filename + size.
---
### Dispatch Timeline
Vertical timeline component for employee career:
- Left rail: `2px solid #E5E7EB` with colored dot per project.
- Each entry: Project name (Outfit SemiBold), period badge, role chip, tech stack pill list.
---
### ITAM Asset Viewer
- Expandable JSON spec panel using styled key-value grid.
- Asset status pill in header.
- Maintenance history as compact table below specs.
---
## Responsive Breakpoints
| Breakpoint | Sidebar | Layout |
|---|---|---|
| `≥ 1280px` | 250px expanded | Full dashboard |
| `1024px–1279px` | 64px collapsed (auto) | Icon sidebar |
| `< 1024px` | Hidden (drawer overlay) | Mobile nav bar at bottom |
+643
View File
@@ -0,0 +1,643 @@
# 배포 가이드 (Deployment Guide)
## 1. 전체 아키텍처
### 시스템 구성도
```
[User Browser]
│
├── https://sr.example.com ──────────────────────┐
│ │
▼ ▼
Cloudflare DNS ─── Cloudflare Pages ──── Cloudflare Tunnel
(도메인 관리) (Next.js 정적 호스팅) (outbound 전용)
│
│ http://localhost:8080
▼
TrueNAS Scale
├── Docker: Spring Boot (:8080)
├── Docker: PostgreSQL (:5432)
└── Dataset: 첨부파일 저장소
```
### 데이터 흐름
```
1. User → https://sr.example.com → Cloudflare Pages (Next.js SPA)
2. SPA → GET https://api.sr.example.com/v1/tickets
│
3. Cloudflare DNS → Cloudflare Tunnel (443) → cloudflared 컨테이너
4. cloudflared → http://spring-boot:8080/api/v1/tickets
5. Spring Boot → PostgreSQL (:5432) / Dataset (/data/attachments)
```
### 포트 오픈 현황
| 방향 | 프로토콜 | 포트 | 설명 |
|------|---------|------|------|
| **아웃바운드** | TCP | 443 | cloudflared → Cloudflare Edge |
| 인바운드 | **없음** | - | 포트포워딩 불필요 |
TrueNAS에 **열린 인바운드 포트가 0개**. cloudflared가 아웃바운드 연결만 생성하여 Cloudflare와 통신.
---
## 2. 사전 준비
### 2.1 Cloudflare
- Cloudflare 계정 (https://dash.cloudflare.com)
- 도메인 Cloudflare DNS 위임 완료
- Cloudflare Pages 가입 (무료 티어 가능)
### 2.2 TrueNAS Scale
- TrueNAS Scale 24.04+ (Linux 기반)
- Apps 기능 활성화: **Apps → Settings → Choose Pool** (앱 전용 Dataset 선택)
- Docker 네트워크 확인: `docker network ls`
### 2.3 GitHub
- Frontend Repository (`sr-frontend`)
- Backend Repository (`sr-backend`)
- GitHub Secrets 등록 준비
---
## 3. 1단계: Backend Docker화
### 3.1 Dockerfile
Spring Boot 프로젝트 루트에 `Dockerfile` 생성:
```dockerfile
# Build stage
FROM gradle:8.7-jdk17 AS builder
WORKDIR /app
COPY build.gradle settings.gradle ./
COPY src ./src
RUN gradle build -x test --no-daemon
# Runtime stage
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
```
### 3.2 application-prod.yml
`src/main/resources/application-prod.yml` 생성:
```yaml
spring:
datasource:
url: jdbc:postgresql://postgres:5432/sr_system
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
show-sql: false
servlet:
multipart:
max-file-size: 50MB
max-request-size: 100MB
app:
file:
upload-dir: /data/attachments
jwt:
secret: ${JWT_SECRET}
server:
port: 8080
logging:
level:
com.hq.support.portal: INFO
```
### 3.3 docker-compose.yml
최상위 `docker/infra/docker-compose.yml`:
```yaml
version: "3.8"
services:
postgres:
image: postgres:16
container_name: sr-postgres
restart: unless-stopped
environment:
POSTGRES_DB: sr_system
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- /mnt/apps/sr-system/postgres:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d sr_system"]
interval: 10s
timeout: 5s
retries: 5
spring-boot:
build:
context: .
dockerfile: Dockerfile
container_name: sr-backend
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
SPRING_PROFILES_ACTIVE: prod
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
volumes:
- /mnt/apps/sr-system/attachments:/data/attachments
ports:
- "127.0.0.1:8080:8080"
```
> **중요:** `ports`가 `127.0.0.1:8080:8080`으로 설정됨. 외부 직접 접근 불가, cloudflared를 통해서만 접근 가능.
---
## 4. 2단계: TrueNAS Scale 배포
### 4.1 Dataset 생성
TrueNAS GUI → Storage → Create Dataset:
| 항목 | 경로 | 용도 |
|------|------|------|
| App Config | `/mnt/apps/sr-system` | docker-compose, 환경변수 |
| PostgreSQL Data | `/mnt/apps/sr-system/postgres` | DB 데이터 |
| Attachments | `/mnt/apps/sr-system/attachments` | 첨부파일 저장소 |
### 4.2 환경변수 파일
`/mnt/apps/sr-system/.env` 생성:
```bash
DB_USERNAME=sr_admin
DB_PASSWORD=<복잡한_비밀번호>
JWT_SECRET=<openssl rand -base64 64>
```
### 4.3 Custom App 등록
TrueNAS GUI → Apps → Launch Docker Image 대신 **Custom App** 사용:
1. **App Name:** `sr-system`
2. **Image:** (docker-compose 방식 사용)
3. **Add Container → docker-compose:**
TrueNAS Apps → Discover Apps → Custom App 선택 후 아래 내용 입력:
```yaml
services:
postgres:
image: postgres:16
container_name: sr-postgres
restart: unless-stopped
env_file: /mnt/apps/sr-system/.env
volumes:
- /mnt/apps/sr-system/postgres:/var/lib/postgresql/data
networks:
- sr-network
spring-boot:
image: sr-backend:latest
container_name: sr-backend
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
env_file: /mnt/apps/sr-system/.env
environment:
SPRING_PROFILES_ACTIVE: prod
volumes:
- /mnt/apps/sr-system/attachments:/data/attachments
networks:
- sr-network
networks:
sr-network:
driver: bridge
```
> **참고:** docker-compose 방식 대신 TrueNAS Apps GUI의 **Custom App → Container Images**에서 각 이미지를 개별 등록하고 `Network`를 동일한 bridge 네트워크로 연결해도 됨.
### 4.4 수동 빌드 (초기)
백엔드 코드를 TrueNAS에 복사 후 빌드:
```bash
# TrueNAS SSH 접속
cd /mnt/apps/sr-system
git clone https://github.com/your-org/sr-backend.git
cd sr-backend
docker build -t sr-backend:latest .
docker compose up -d
```
---
## 5. 3단계: Cloudflare Tunnel 설치
### 5.1 Cloudflare Tunnel 생성 (로컬 CLI)
```bash
# 로컬 PC에서 cloudflared 설치
brew install cloudflare/cloudflare/cloudflared
# Cloudflare 로그인
cloudflared tunnel login
# Tunnel 생성
cloudflared tunnel create sr-system-tunnel
# 출력 예시: Tunnel ID: abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# 인증 파일: ~/.cloudflared/abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
```
### 5.2 Config 파일 생성
`~/.cloudflared/config.yml`:
```yaml
tunnel: abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx
credentials-file: /home/.cloudflared/abc12345-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
ingress:
- hostname: api.sr.example.com
service: http://localhost:8080
- service: http_status:404
```
### 5.3 DNS 라우팅 설정
```bash
cloudflared tunnel route dns sr-system-tunnel api.sr.example.com
```
### 5.4 TrueNAS에 cloudflared 컨테이너 배포
**방법 A: Docker Compose에 포함**
`docker/infra/docker-compose.yml`에 cloudflared 추가:
```yaml
services:
# ... postgres, spring-boot ...
cloudflared:
image: cloudflare/cloudflared:latest
container_name: sr-tunnel
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
networks:
- sr-network
```
**방법 B: TrueNAS Apps에서 개별 배포**
1. TrueNAS → Apps → Discover Apps → Custom App
2. **App Name:** `sr-tunnel`
3. **Image:** `cloudflare/cloudflared:latest`
4. **Entrypoint:** `tunnel --no-autoupdate run`
5. **Environment Variables:**
- `TUNNEL_TOKEN`: `<Tunnel Token>`
### 5.5 Tunnel Token 발급
```bash
cloudflared tunnel token sr-system-tunnel > tunnel-token.txt
# 출력된 token을 CLOUDFLARE_TUNNEL_TOKEN 환경변수로 등록
```
### 5.6 동작 확인
```bash
# Tunnel 로그 확인
docker logs sr-tunnel
# 정상 출력 예시:
# 2026/05/21 10:00:00 INF Connection abc12345 registered
# 2026/05/21 10:00:00 INF Route created hostname=api.sr.example.com
# 2026/05/21 10:00:00 INF tunnelId=abc12345
# Spring Boot 헬스체크
curl https://api.sr.example.com/api/v1/actuator/health
# {"status":"UP"}
```
---
## 6. 4단계: Frontend Cloudflare Pages 배포
### 6.1 next.config.ts 설정
```typescript
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "export", // 정적 사이트 내보내기
images: {
unoptimized: true, // 정적 export 시 필수
},
trailingSlash: true,
distDir: "out",
};
export default nextConfig;
```
> **참고:** API Routes나 Server Components가 필요하면 `output: 'export'` 대신 `@cloudflare/next-on-pages` 사용.
### 6.2 환경변수
`.env.production`:
```bash
NEXT_PUBLIC_API_URL=https://api.sr.example.com/api/v1
```
### 6.3 Cloudflare Pages 연결
1. Cloudflare Dashboard → **Workers & Pages → Pages**
2. **Connect to Git** → GitHub 저장소 선택
3. **Build settings:**
- Framework preset: **Next.js**
- Build command: `npm run build && npm run export`
- Build output: `out`
4. **Environment Variables (Advanced):**
- `NEXT_PUBLIC_API_URL`: `https://api.sr.example.com/api/v1`
5. **Deploy**
### 6.4 Custom Domain 설정
Deploy 완료 후:
1. Pages 프로젝트 → **Custom domains** → **Set up custom domain**
2. `sr.example.com` 입력
3. Cloudflare가 자동으로 DNS 레코드 생성 (Proxy ON = 주황 구름)
---
## 7. 5단계: CI/CD
### 7.1 Backend (GitHub Actions)
`.github/workflows/deploy-backend.yml`:
```yaml
name: Deploy Backend
on:
push:
branches: [main]
paths:
- "backend/**"
- "docker/**"
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: Build with Gradle
run: |
cd backend
./gradlew build -x test
- name: Build Docker Image
run: |
cd backend
docker build -t ghcr.io/${{ github.repository }}/sr-backend:latest .
docker tag ghcr.io/${{ github.repository }}/sr-backend:latest \
ghcr.io/${{ github.repository }}/sr-backend:${{ github.sha }}
- name: Push to GitHub Container Registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker push ghcr.io/${{ github.repository }}/sr-backend --all-tags
- name: Deploy to TrueNAS
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.TRUENAS_HOST }}
username: ${{ secrets.TRUENAS_SSH_USER }}
key: ${{ secrets.TRUENAS_SSH_KEY }}
script: |
cd /mnt/apps/sr-system
docker compose pull spring-boot
docker compose up -d spring-boot
docker image prune -f
```
### 7.2 Frontend (GitHub Actions)
`.github/workflows/deploy-frontend.yml`:
```yaml
name: Deploy Frontend
on:
push:
branches: [main]
paths:
- "frontend/**"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install & Build
run: |
cd frontend
npm ci
npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: sr-frontend
directory: frontend/out
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
```
### 7.3 GitHub Secrets 등록
| Secret | 값 |
|--------|-----|
| `TRUENAS_HOST` | TrueNAS IP 주소 (내부망) |
| `TRUENAS_SSH_USER` | SSH 사용자 |
| `TRUENAS_SSH_KEY` | SSH Private Key |
| `CLOUDFLARE_API_TOKEN` | Cloudflare API Token (Pages 권한) |
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare Account ID |
| `TUNNEL_TOKEN` | Cloudflare Tunnel Token |
---
## 8. 보안 설정
### 8.1 Cloudflare WAF 규칙
Cloudflare Dashboard → Security → WAF:
**규칙 1: API 경로만 허용**
```
Field: Hostname
Operator: equals
Value: api.sr.example.com
Then:
URI Path starts with /api/v1 OR /actuator/health
→ Allow
Else → Block
```
**규칙 2: Rate Limiting**
```
When: requests match api.sr.example.com
Rate: 1000 requests per 5 minutes
Action: Block
```
### 8.2 Cloudflare Access (선택 - VPN 대체)
Zero Trust → Access → Applications:
- **App Domain:** `api.sr.example.com`
- **Policy:** 특정 이메일/Google/OAuth 로그인 필수
- **Session Duration:** 24h
> Cloudflare Access를 활성화하면 API도 인증된 사용자만 접근 가능. 단, 프론트엔드 SPA에서 API 호출 시 Access Token 처리 로직이 추가로 필요.
### 8.3 SSL 설정
Cloudflare Dashboard → SSL/TLS:
- **Full (Strict)** 선택
- TrueNAS 측에서는 별도 SSL 인증서 불필요 (cloudflared가 종단 암호화)
### 8.4 DB 접근 제한
PostgreSQL이 `127.0.0.1:5432`에서만 리스닝. 외부 접근 차단.
Docker 네트워크 내에서만 `postgres:5432`로 접근 가능.
---
## 9. 운영
### 9.1 헬스체크
```bash
# Spring Boot Actuator
curl https://api.sr.example.com/api/v1/actuator/health
# DB 연결 확인
curl https://api.sr.example.com/api/v1/actuator/health/db
```
### 9.2 로그 확인
```bash
# TrueNAS SSH 접속 후
docker logs sr-backend # Spring Boot 로그
docker logs sr-postgres # PostgreSQL 로그
docker logs sr-tunnel # Tunnel 로그
docker compose logs -f # 실시간 로그 스트림
```
### 9.3 DB 백업
**ZFS Snapshot (자동):**
TrueNAS GUI → Storage → `/mnt/apps/sr-system/postgres` → Snapshot:
- Schedule: Daily at 03:00
- Retention: 30일
**pg_dump (수동):**
```bash
docker exec sr-postgres pg_dump -U sr_admin sr_system > \
/mnt/apps/sr-system/backups/sr_system_$(date +%Y%m%d).sql
```
### 9.4 Watchtower (자동 업데이트)
docker-compose에 Watchtower 추가:
```yaml
services:
watchtower:
image: containrrr/watchtower
container_name: sr-watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 3600 --cleanup
```
매시간 이미지 체크 → 새 이미지 있으면 자동 재배포.
---
## 10. 문제 해결
### Tunnel 연결 안 됨
```bash
# cloudflared 로그 확인
docker logs sr-tunnel
# DNS 확인
cloudflared tunnel info sr-system-tunnel
# 재시작
docker restart sr-tunnel
```
### Spring Boot 컨테이너 Crash
```bash
# 로그 확인
docker logs sr-backend --tail 50
# DB 연결 테스트
docker exec sr-postgres pg_isready -U sr_admin -d sr_system
# 환경변수 확인
docker exec sr-backend env | grep -E "DB_|JWT_|SPRING_"
```
### Cloudflare Pages 502 Error
- Cloudflare Tunnel이 실행 중인지 확인
- `api.sr.example.com` DNS가 Tunnel UUID를 가리키는지 확인
- Spring Boot가 정상 기동했는지 확인 (`http://localhost:8080/actuator/health`)
- Cloudflare Dashboard → SSL/TLS → **Full (Strict)** 확인
+739
View File
@@ -0,0 +1,739 @@
# SR System — Feature Implementation Plan
> Analysis date: 2026-05-26
> Scope: Calendar, Notifications, User Profile, ADMIN/MANAGER Management
---
## Executive Summary
| Feature | Existing Backend | New Backend | Frontend | Priority | Effort |
|---------|:---:|:---:|:---:|:---:|:---:|
| Calendar | **None** | Calendar aggregation endpoint | CalendarPage + CalendarWidget | P2 | 5d |
| Notifications | **Full** (read, mark-read, unread count) | Add `link_url` field to Notification entity | NotificationDropdown | P1 | 2d |
| User Profile | **Partial** (getMe, portfolio, dispatch-history) | ChangePassword endpoint + Extended EmployeeSummary | ProfilePage | P1 | 4d |
| ADMIN/MANAGER | **Partial** (employee CRUD, report listing) | Dispatch CRUD, CommonCode CRUD, Report summary aggregations | EmployeeEditModal, DispatchManager, ReportDashboard, SettingsPage | P1 (Reports), P2 (Dispatch), P2 (Settings) | 8d total |
**Total estimated effort: 19 days** (full-time, single dev). Parallel work possible — Admin features and Profile can be developed concurrently with Calendar and Notifications.
---
## 1. Calendar Feature
### 1.1 Current State Analysis
| Aspect | Status |
|--------|--------|
| Header Calendar icon | Route: `/issues` (no calendar relevance) |
| Backend calendar endpoint | **Does not exist** |
| Data with dates | `Ticket.dueDate`, `Report.targetDate`, `Project.startDate/endDate`, `DispatchHistory.startDate/endDate` |
| Frontend calendar page | **Does not exist** |
The Header component (line 65):
```tsx
<button onClick={() => router.push('/issues')} ...>
<Calendar className="w-5 h-5" />
</button>
```
### 1.2 What's Missing
1. **Backend: Calendar aggregation endpoint** — No single endpoint to fetch events across domains. Need:
- `GET /api/v1/calendar?start=YYYY-MM-DD&end=YYYY-MM-DD` — returns unified events
- Events aggregated from: Ticket due dates, Report target dates, Dispatch start/end dates
2. **Backend: Calendar event entity** — No dedicated schedule/schedule_type entity. Two options:
- **Option A (Recommended):** Aggregation endpoint that queries existing entities (Ticket, Report, DispatchHistory) and returns a unified DTO. Zero schema change.
- **Option B:** New `Schedule` entity with schedule_type (MEETING, DEADLINE, MILESTONE) — more flexible but adds complexity.
3. **Frontend: Calendar page** (`/app/(main)/calendar/page.tsx`) — Full calendar view with month/week/day modes.
4. **Frontend: Calendar event types** — Ticket due dates, report deadlines, dispatch milestones.
### 1.3 Design Proposal
#### 1.3.1 Backend: Calendar Aggregation Endpoint
**New DTO: `CalendarEventDto`**
```java
public record CalendarEventDto(
String eventType, // TICKET_DUE, REPORT_DUE, DISPATCH_START, DISPATCH_END
Long sourceId, // ticketId / reportId / dispatchId
String title,
String description,
LocalDate eventDate,
String color, // semantic color per type
String linkUrl // navigation URL (/issues/123, /work-reports/456, etc.)
) {}
```
**New Controller Method (in a new `CalendarController` or added to an existing controller):**
```java
@GetMapping("/api/v1/calendar")
@PreAuthorize("hasAnyRole('EMPLOYEE','MANAGER','ADMIN')")
ResponseEntity<ApiResponse<List<CalendarEventDto>>> getCalendar(
@RequestParam @DateTimeFormat(iso=ISO.DATE) LocalDate start,
@RequestParam @DateTimeFormat(iso=ISO.DATE) LocalDate end,
@CurrentUser Employee currentUser)
```
**New Service: `CalendarService`**
- Queries `TicketRepository.findByDueDateBetweenAndRequester_EmpId(start, end, empId)` (for employee) or all tickets (for manager/admin)
- Queries `ReportRepository.findByTargetDateBetweenAndUser_EmpId(start, end, empId)` or all
- Queries `DispatchHistoryRepository.findByStartDateBetween(start, end)` (only active, DISPATCHED)
- Merges results into `List<CalendarEventDto>`
**Event color mapping:**
| Event Type | Color | Icon |
|-----------|-------|------|
| TICKET_DUE | `#3B82F6` (blue) | Ticket |
| REPORT_DUE | `#10B981` (green) | FileText |
| DISPATCH_START | `#F59E0B` (amber) | Play |
| DISPATCH_END | `#EF4444` (red) | Stop |
#### 1.3.2 Frontend: Calendar Page
**Route:** `/calendar`
**Design:**
```
┌─────────────────────────────────────────────────────────────────┐
│ Calendar ◀ 2026.05 ▶ Today │
├──┬────┬────┬────┬────┬────┬────┐ │
│S │ M │ T │ W │ T │ F │ S │ │
├──┼────┼────┼────┼────┼────┼────┤ │
│ │ │ │ │ │ 1 │ 2 │ │
│ │ │ │ │ │ ● │ │ │
│ │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ │
│ │ ● │ ● │ │ ■ │ │ │ │
│ │ 11 │ 12 │ 13 │ 14 │ 15 │ 16 │ │
│ │ │ ▲ │ ● │ │ │ ■ │ │
│ │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ │
│ │ │ │ ● │ │ │ │ │
│ │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ │
│ │ │ │ ■ │ │ │ │ │
├──┴────┴────┴────┴────┴────┴────┤ │
│ Legend: ● Report Due ■ Dispatch ▲ Ticket Due │
└─────────────────────────────────────────────────────────────────┘
```
**Components to create:**
- `src/app/(main)/calendar/page.tsx` — Main calendar page
- `src/components/calendar/CalendarGrid.tsx` — Month grid view (no external library — custom CSS Grid, 7-column)
- `src/components/calendar/CalendarEvent.tsx` — Event chip with color dot + title (truncated)
- `src/components/calendar/EventDetailPanel.tsx` — Slide-over or modal showing event details
- `src/components/calendar/CalendarWidget.tsx` — Mini calendar widget for dashboard (optional, P3)
**Added to sidebar:**
```tsx
{ name: 'Calendar', href: '/calendar', icon: Calendar }
```
### 1.4 Implementation Plan — Calendar
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Create `CalendarEventDto` record | `backend/.../dto/CalendarEventDto.java` | 0.3d |
| 2 | Create `CalendarService` with aggregation logic | `backend/.../service/CalendarService.java` | 0.7d |
| 3 | Create `CalendarController` endpoint | `backend/.../controller/CalendarController.java` | 0.3d |
| 4 | Add `calendarService` to frontend services | `src/services/calendarService.ts` | 0.3d |
| 5 | Add `CalendarEvent` type to frontend types | `src/types/index.ts` | 0.2d |
| 6 | Build `CalendarGrid` component | `src/components/calendar/CalendarGrid.tsx` | 1.5d |
| 7 | Build `CalendarEvent` chip component | `src/components/calendar/CalendarEvent.tsx` | 0.5d |
| 8 | Build `EventDetailPanel` slide-over | `src/components/calendar/EventDetailPanel.tsx` | 0.5d |
| 9 | Build `/calendar` page | `src/app/(main)/calendar/page.tsx` | 0.5d |
| 10 | Update Header Calendar icon to `/calendar` | `src/components/layout/Header.tsx` | 0.1d |
| 11 | Add Calendar to Sidebar | `src/components/layout/Sidebar.tsx` | 0.1d |
| **Total** | | | **5 days** |
---
## 2. Notification System
### 2.1 Current State Analysis
| Aspect | Status |
|--------|--------|
| Backend API | ✅ Full: `GET /notifications`, `GET /notifications/unread`, `PUT /notifications/{id}/read` |
| Frontend notificationStore | ✅ Polls unread count (30s interval), fetches list, marks as read |
| Notification entity fields | `notificationId, type, title, message, isRead, createdAt` |
| Bell icon behavior | Calls `fetchNotifications()` on click but **no dropdown/modal renders** |
| Missing | `link_url` field — no way to navigate to related entity from notification |
### 2.2 What's Missing
1. **Frontend: NotificationDropdown component** — Bell click should show a dropdown listing recent notifications.
2. **Frontend: Click-to-navigate** — Clicking a notification should navigate to the relevant page (ticket detail, report, etc.).
3. **Backend: `linkUrl` field** — Notification entity has `type` but no link to the source entity.
### 2.3 Design Proposal
#### 2.3.1 Backend: Add linkUrl to Notification Entity
**Migration:**
```sql
ALTER TABLE tb_notification ADD COLUMN link_url VARCHAR(500);
```
**Entity update (`Notification.java`):**
```java
@Column(name = "link_url", length = 500)
private String linkUrl;
```
**Service update** — When creating notifications, set `linkUrl`:
| Type | linkUrl Example |
|------|----------------|
| TICKET_ASSIGNED | `/issues/123` |
| TICKET_RESOLVED | `/issues/123` |
| REPORT_APPROVED | `/work-reports/456` |
| REPORT_REJECTED | `/work-reports/456` |
| SLA_WARNING | `/issues/789` |
| EQUIPMENT_ASSIGNED | `/itam/123` |
#### 2.3.2 Frontend: Notification Dropdown
**Component: `NotificationDropdown.tsx`**
```
┌─────────────────────────────────┐
│ Notifications [x] │ ← Header: "Notifications" + close button
├─────────────────────────────────┤
│ 🔵 Ticket #123 assigned to you │ ← Unread: blue left border
│ 2 minutes ago → │
├─────────────────────────────────┤
│ ✅ Report #456 approved │ ← Read: no left border
│ 1 hour ago → │
├─────────────────────────────────┤
│ ⚠️ SLA Warning: #789 Overdue │ ← Critical: red left border
│ 3 hours ago → │
├─────────────────────────────────┤
│ │
│ View All ↗ │ ← Link to full notification page
└─────────────────────────────────┘
```
**Behavior:**
- Dropdown slides down from bell icon (absolute positioned)
- Shows latest 10 notifications
- Click notification → `markAsRead(id)` + navigate to `linkUrl`
- Click "View All" → `/notifications` page (optional, P3)
- Click outside → close dropdown
- Escape key → close dropdown
**Layout:**
- Max height: 400px, overflow-y: auto
- Each item: 12px padding, border-bottom, hover bg-gray-50
- Width: 360px
- Unread items: `bg-indigo-50/30`, blue dot (6px) left
- Categories: Icon + title (bold 13px) + time ago (gray 11px)
### 2.4 Implementation Plan — Notifications
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Add `linkUrl` column to Notification entity | `Notification.java` + migration | 0.3d |
| 2 | Update NotificationListener to set linkUrl | `backend/.../listener/NotificationListener.java` | 0.3d |
| 3 | Add `linkUrl` to frontend Notification type | `src/types/index.ts` | 0.1d |
| 4 | Build `NotificationDropdown` component | `src/components/layout/NotificationDropdown.tsx` | 1.0d |
| 5 | Integrate into Header (replace bell onClick) | `src/components/layout/Header.tsx` | 0.2d |
| 6 | Add mark-all-as-read endpoint (optional) | Backend + service | 0.2d |
| **Total** | | | **2 days** |
---
## 3. User Profile Management
### 3.1 Current State Analysis
| Aspect | Status |
|--------|--------|
| `GET /api/v1/employees/me` | ✅ Returns `EmployeeSummary` (empId, name, email, roleCode, dispatchStatus) |
| `GET /api/v1/employees/{empId}/dispatch-histories` | ✅ Returns `DispatchHistory[]` |
| `GET /api/v1/employees/{empId}/portfolio` | ✅ Returns `PortfolioResponse[]` (with reports + resolved tickets) |
| `PUT /api/v1/employees/{empId}` | ✅ Admin-only update endpoint |
| Change password endpoint | **Missing** |
| Extended profile info (phone, empStatus, joinedDate) | **Missing** from `/me` (EmployeeSummary is minimal) |
| `/profile` page | **Does not exist** |
### 3.2 What's Missing
1. **Backend: `PUT /api/v1/employees/me/password`** — Change password endpoint for current user.
2. **Backend: Extended `/me` response** — `EmployeeSummary` is too minimal. Need phone, empStatus, joinedDate, dispatchStatus label.
3. **Frontend: `/profile` page** — View/edit profile, change password, view dispatch history, view portfolio.
4. **Frontend: Profile editing** — Allow user to edit their own name, email, phone (or restrict to admin-only for certain fields).
### 3.3 Design Proposal
#### 3.3.1 Backend: Change Password Endpoint
**New DTO: `ChangePasswordRequest`**
```java
public record ChangePasswordRequest(
@NotBlank String currentPassword,
@NotBlank @Size(min=8) String newPassword
) {}
```
**New Endpoint in AuthController or EmployeeController:**
```java
@PutMapping("/api/v1/employees/me/password")
@PreAuthorize("hasAnyRole('EMPLOYEE','MANAGER','ADMIN')")
ResponseEntity<ApiResponse<Void>> changePassword(
@Valid @RequestBody ChangePasswordRequest request,
@CurrentUser Employee currentUser)
```
**Logic:**
1. Verify `currentPassword` matches stored hash
2. Encode `newPassword` and save
3. Invalidate existing tokens (optional — add `token_version` field)
#### 3.3.2 Backend: Extended EmployeeSummary
**Update `EmployeeSummary` to include:**
```java
public record EmployeeSummary(
Long empId,
String loginId,
String name,
String email,
String phone, // NEW
RoleCode roleCode,
EmpStatus empStatus, // NEW
DispatchStatus dispatchStatus,
LocalDate joinedDate, // NEW
LocalDate leftDate // NEW (nullable)
) {}
```
#### 3.3.3 Frontend: Profile Page Design
**URL:** `/profile`
**For EMPLOYEE (own profile):**
```
┌─────────────────────────────────────────────────────┐
│ [Avatar] 김민수 │
│ 파견직원 · 재직중 · 파견중 │
│ │
│ ┌─ Personal Info ─────────────────────────────────┐ │
│ │ Login ID: minsu.kim │ │
│ │ Name: 김민수 │ │
│ │ Email: minsu@example.com │ │
│ │ Phone: 010-1234-5678 │ │
│ │ Joined: 2024-03-01 │ │
│ │ Status: ACTIVE (DISPATCHED) │ │
│ │ [Edit Info] [Change Password] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ Dispatch History ──────────────────────────────┐ │
│ │ Timeline with projects, dates, roles │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ Portfolio Summary ─────────────────────────────┐ │
│ │ Aggregated stats: projects, tickets, reports │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
**For MANAGER/ADMIN viewing another employee:**
- URL: `/profile/[empId]`
- Same layout but with employee selector/dropdown at top
- Manager can view but not edit (unless admin)
- Admin can edit fields
#### 3.3.4 Components to Create
| Component | Description |
|-----------|-------------|
| `src/app/(main)/profile/page.tsx` | Own profile view |
| `src/app/(main)/profile/[empId]/page.tsx` | View other employee's profile (MANAGER/ADMIN) |
| `src/components/profile/ProfileCard.tsx` | Personal info card with edit/change-password buttons |
| `src/components/profile/EditProfileModal.tsx` | Modal for editing personal info (admin only or self?) |
| `src/components/profile/ChangePasswordModal.tsx` | Modal with current/new/confirm password fields |
| `src/components/profile/DispatchTimeline.tsx` | Reuse timeline from /dispatch page |
| `src/components/profile/PortfolioStats.tsx` | Summary stats cards (total projects, total tickets resolved, etc.) |
### 3.4 Implementation Plan — User Profile
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Create `ChangePasswordRequest` DTO | Backend dto | 0.1d |
| 2 | Add `changePassword` to AuthService | `AuthService.java` | 0.3d |
| 3 | Add `PUT /employees/me/password` endpoint | `AuthController.java` or `EmployeeController.java` | 0.2d |
| 4 | Extend `EmployeeSummary` to include phone, empStatus, joinedDate | `EmployeeSummary.java` + `EmployeeService.toSummary()` | 0.2d |
| 5 | Add `getMeFull()` and `changePassword()` to employeeService | `src/services/employeeService.ts` | 0.2d |
| 6 | Build `ProfileCard` component | `src/components/profile/ProfileCard.tsx` | 0.5d |
| 7 | Build `ChangePasswordModal` component | `src/components/profile/ChangePasswordModal.tsx` | 0.5d |
| 8 | Build `EditProfileModal` component (admin-only for role/status changes; self-service for email/phone) | `src/components/profile/EditProfileModal.tsx` | 0.5d |
| 9 | Build `PortfolioStats` component | `src/components/profile/PortfolioStats.tsx` | 0.3d |
| 10 | Build `/profile` page | `src/app/(main)/profile/page.tsx` | 0.8d |
| 11 | Build `/profile/[empId]` page (manager/admin view) | `src/app/(main)/profile/[empId]/page.tsx` | 0.4d |
| 12 | Make user avatar/name in Header clickable → `/profile` | `src/components/layout/Header.tsx` | 0.1d |
| **Total** | | | **4 days** |
---
## 4. ADMIN/MANAGER Management Features
### 4.1 Current State Analysis
#### 4.1.1 Employee CRUD
| Operation | Backend | Frontend |
|-----------|:---:|:---:|
| List/View | ✅ `GET /employees` (MANAGER/ADMIN) | ✅ `/employees` page with table view |
| Create | ✅ `POST /employees` (ADMIN) | ✅ Modal in `/employees` page |
| Update | ✅ `PUT /employees/{id}` (ADMIN) | ❌ Only `MoreHorizontal` button with no handler |
| Delete | ✅ `DELETE /employees/{id}` (ADMIN) | ❌ No delete UI |
| Search | ✅ `GET /employees/search` | ✅ Search bar in `/employees` |
**Gap:** Edit and delete functionality missing from frontend. The `MoreHorizontal` button (line 454-456 in employees/page.tsx) is a blank `<button>` with no click handler.
#### 4.1.2 Dispatch Assignment
| Operation | Backend | Frontend |
|-----------|:---:|:---:|
| Create dispatch | ❌ No endpoint | ❌ No page |
| List dispatch by employee | ✅ `GET /employees/{id}/dispatch-histories` | ❌ Only shown in employee's own /dispatch page |
| List all dispatches | ❌ No endpoint | ❌ No management view |
| Link employee to project | ❌ No endpoint | ❌ |
**Gap:** There is NO controller/service method for creating a DispatchHistory. The DispatchHistoryService exists but only has repository calls, no create/update methods. MANAGER/ADMIN have no way to assign employees to projects.
#### 4.1.3 Report Monitoring Dashboard
| Operation | Backend | Frontend |
|-----------|:---:|:---:|
| List all reports | ✅ ReportController (MANAGER/ADMIN see all) | ✅ Works via work-reports page |
| Report review/approval | ✅ `PUT /reports/{id}/review` | ❌ No approval UI for managers |
| Pending count | ❌ No aggregate endpoint | Dashboard fetches `totalElements` from page=1 query (approximate) |
| Report statistics | ❌ No stats endpoint | ❌ |
**Gap:** Manager needs a dedicated report monitoring page showing all submitted reports in a table with quick approve/reject actions. Dashboard count is a workaround.
#### 4.1.4 System Settings (Common Codes)
| Operation | Backend | Frontend |
|-----------|:---:|:---:|
| List codes by group | ✅ `GET /common-codes/{groupCode}` | ❌ No page |
| Create/Update/Delete codes | ❌ No endpoints | ❌ |
**Gap:** Common code management is a pure ADMIN function. There are no CRUD endpoints for common codes and no settings page.
### 4.2 Design Proposals
#### 4.2.1 Employee Edit/Delete
**Frontend: `EmployeeEditModal.tsx`**
- Opens on `MoreHorizontal` click
- Edit: name, email, roleCode, empStatus, dispatchStatus, joinedDate
- Delete: Confirm dialog → soft delete
- After save → refresh employee list
**Add to `/employees` page:**
```tsx
// Replace blank MoreHorizontal button:
<button onClick={() => setEditingEmployee(emp)}>
<MoreHorizontal className="w-4 h-4" />
</button>
```
#### 4.2.2 Dispatch Management
**Backend needs:**
**New Controller: `DispatchHistoryController.java`**
```java
@PostMapping("/api/v1/dispatch-histories")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<DispatchHistory>> create(CreateDispatchRequest request)
@PutMapping("/api/v1/dispatch-histories/{dispatchId}")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<DispatchHistory>> update(Long dispatchId, UpdateDispatchRequest request)
@GetMapping("/api/v1/dispatch-histories")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<Page<DispatchHistory>>> findAll(Pageable pageable, @RequestParam(required=false) Long empId, @RequestParam(required=false) Long projectId)
```
**New DTOs:**
```java
public record CreateDispatchRequest(
@NotNull Long empId,
@NotNull Long projectId,
@NotNull LocalDate startDate,
LocalDate endDate,
@NotBlank String roleTitle,
@NotNull Integer contributionRate,
@NotBlank String individualTech,
@NotBlank String performedTasks
) {}
```
**Frontend: Dispatch Management Page**
**URL:** `/dispatch/manage` (MANAGER/ADMIN only)
```
┌─────────────────────────────────────────────────────┐
│ Dispatch Management [+ New Dispatch] │
├─────────┬──────────┬─────────┬─────────┬────────────┤
│ Employee│ Project │ Role │ Period │ Actions │
├─────────┼──────────┼─────────┼─────────┼────────────┤
│ 김민수 │ Samsung │ Backend │ 24.03~ │ [Edit][Del]│
│ 이영희 │ LG CNS │ Frontend│ 24.06~ │ [Edit][Del]│
│ ... │ ... │ ... │ ... │ ... │
└─────────┴──────────┴─────────┴─────────┴────────────┘
```
**Create Dispatch modal:**
- Employee selector (autocomplete search)
- Project selector (dropdown from `/projects/my` or all projects)
- Date range picker
- Role title, contribution rate, tech stack, tasks
#### 4.2.3 Report Monitoring Dashboard
**URL:** `/work-reports/review` (MANAGER/ADMIN only)
```
┌─────────────────────────────────────────────────────┐
│ Report Review Dashboard │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Submitted │ │Pending │ │Approved │ │Rejected │ │
│ │ 12 │ │ 5 │ │ 45 │ │ 3 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ [Filter: SUBMITTED ▼] [Date: 2026-05 ▼] [Search...]│
├─────────┬─────────┬──────────┬─────────┬────────────┤
│ Employee│ Type │ Date │ Status │ Action │
├─────────┼─────────┼──────────┼─────────┼────────────┤
│ 김민수 │ DAILY │ 05-26 │ SUBMIT │[✅][❌][👁] │
│ 이영희 │ WEEKLY │ 05-20 │ SUBMIT │[✅][❌][👁] │
│ 박철수 │ MONTHLY │ 05-01 │ SUBMIT │[✅][❌][👁] │
└─────────┴─────────┴──────────┴─────────┴────────────┘
```
**Action buttons:**
- ✅ Approve → `PUT /reports/{id}/review { status: "APPROVED" }`
- ❌ Reject → Opens rejection modal with required feedback text
- 👁 View → Navigate to report detail
**New Backend Endpoint (optional):**
```java
@GetMapping("/api/v1/reports/summary")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<ReportSummary>> getSummary()
// Returns counts by status: { submitted, approved, rejected, draft }
```
#### 4.2.4 System Settings (Common Codes)
**Backend needs:**
**New endpoints in `CommonCodeController.java`:**
```java
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<CommonCode>> create(CommonCode code)
@PutMapping("/{codeId}")
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<CommonCode>> update(Long codeId, CommonCode code)
@DeleteMapping("/{codeId}")
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<Void>> delete(Long codeId)
```
**Frontend: Settings Page**
**URL:** `/settings` (ADMIN only)
```
┌─────────────────────────────────────────────────────┐
│ System Settings │
│ ┌──────────────────────┬───────────────────────────┐ │
│ │ Common Codes │ Code Group: [Role ▼] │ │
│ │ ├ Group List │ ┌──────┬──────┬────┬────┐ │ │
│ │ │ • Role │ │ Code │ Name │Sort│ │ │ │
│ │ │ • Report Type │ ├──────┼──────┼────┼────┤ │ │
│ │ │ • Ticket Category │ │EMPLOY│파견직원│ 1 │[✏️][🗑]│ │
│ │ │ • Equipment Type │ │MANAG│본사관리│ 2 │[✏️][🗑]│ │
│ │ │ • ... │ │ADMIN│최고 │ 3 │[✏️][🗑]│ │
│ │ │ │ └──────┴──────┴────┴────┘ │ │
│ │ │ │ [+ Add Code] │ │
│ └──────────────────────┴───────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Other Settings │ │
│ │ □ Enable email notifications │ │
│ │ □ Enable Slack notifications │ │
│ │ Default SLA hours: [48 ▼] │ │
│ │ [Save] │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
### 4.3 Implementation Plan — ADMIN/MANAGER Features
#### Phase A: Report Monitoring Dashboard (P1, ~2 days)
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Add `ReportSummary` DTO + `GET /reports/summary` endpoint | Backend | 0.3d |
| 2 | Add `reportService.getSummary()` to frontend services | `src/services/reportService.ts` | 0.1d |
| 3 | Build report review dashboard page | `src/app/(main)/work-reports/review/page.tsx` | 1.0d |
| 4 | Add approve/reject inline actions | Same as above + modal | 0.4d |
| 5 | Add navigation from dashboard "Pending Reports" card to review page | `src/app/(main)/page.tsx` | 0.1d |
| 6 | Add sidebar link for MANAGER/ADMIN (conditional render) | `src/components/layout/Sidebar.tsx` | 0.1d |
#### Phase B: Employee Edit/Delete (P1, ~1.5 days, already mostly built on backend)
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Build `EmployeeEditModal` component | `src/components/employees/EmployeeEditModal.tsx` | 0.5d |
| 2 | Add delete confirmation dialog | Same component | 0.2d |
| 3 | Wire `MoreHorizontal` button to open edit modal | `src/app/(main)/employees/page.tsx` | 0.3d |
| 4 | Refresh list after edit/delete | Same page | 0.2d |
| 5 | Add employee detail view (linking to `/profile/[empId]`) | Same page | 0.3d |
#### Phase C: Dispatch Management (P2, ~3 days)
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Create `CreateDispatchRequest` + `UpdateDispatchRequest` DTOs | Backend | 0.2d |
| 2 | Create `DispatchHistoryController` with CRUD endpoints | Backend | 0.5d |
| 3 | Add `dispatchHistoryService.getAll()`, `.create()`, `.update()`, `.delete()` to frontend | `src/services/dispatchHistoryService.ts` (new) | 0.3d |
| 4 | Build dispatch management page | `src/app/(main)/dispatch/manage/page.tsx` | 1.0d |
| 5 | Build create/edit dispatch modal with employee search + project select | Same + modal component | 0.8d |
| 6 | Add sidebar link (MANAGER/ADMIN only) | `src/components/layout/Sidebar.tsx` | 0.1d |
#### Phase D: System Settings (P2, ~1.5 days)
| Step | Task | File(s) | Effort |
|------|------|---------|--------|
| 1 | Add POST/PUT/DELETE to CommonCodeController | Backend | 0.3d |
| 2 | Add create/update/delete to `commonCodeService` | `src/services/commonCodeService.ts` (new) | 0.2d |
| 3 | Build settings page with code group list + editor | `src/app/(main)/settings/page.tsx` | 1.0d |
| 4 | Add sidebar link (ADMIN only) | `src/components/layout/Sidebar.tsx` | 0.1d |
---
## 5. Consolidated File List
### 5.1 Backend — Files to Create
| File | Feature | Description |
|------|---------|-------------|
| `dto/CalendarEventDto.java` | Calendar | Calendar event aggregation DTO |
| `service/CalendarService.java` | Calendar | Aggregation logic from Ticket, Report, Dispatch |
| `controller/CalendarController.java` | Calendar | `GET /api/v1/calendar` endpoint |
| `dto/ChangePasswordRequest.java` | Profile | Password change request DTO |
| `dto/CreateDispatchRequest.java` | Dispatch | Dispatch creation request DTO |
| `dto/UpdateDispatchRequest.java` | Dispatch | Dispatch update request DTO |
| `controller/DispatchHistoryController.java` | Dispatch | Full CRUD for dispatch histories |
| `service/DispatchManagementService.java` | Dispatch | Management-level dispatch operations |
### 5.2 Backend — Files to Modify
| File | Feature | Change |
|------|---------|--------|
| `entity/Notification.java` | Notifications | Add `linkUrl` column |
| `dto/EmployeeSummary.java` | Profile | Add phone, empStatus, joinedDate, leftDate fields |
| `service/AuthService.java` | Profile | Add `changePassword()` method |
| `controller/AuthController.java` or `EmployeeController.java` | Profile | Add `PUT /employees/me/password` endpoint |
| `service/EmployeeService.java` | Profile | Update `toSummary()` to include new fields |
| `controller/ReportController.java` | Reports | Add `GET /reports/summary` endpoint |
| `controller/CommonCodeController.java` | Settings | Add POST, PUT, DELETE endpoints |
| `service/CommonCodeService.java` | Settings | Add create, update, delete methods |
### 5.3 Frontend — Files to Create
| File | Feature | Description |
|------|---------|-------------|
| `src/services/calendarService.ts` | Calendar | `GET /calendar?start=&end=` |
| `src/services/dispatchHistoryService.ts` | Dispatch | Full CRUD for dispatch histories |
| `src/services/commonCodeService.ts` | Settings | CRUD for common codes |
| `src/components/calendar/CalendarGrid.tsx` | Calendar | Monthly calendar grid component |
| `src/components/calendar/CalendarEvent.tsx` | Calendar | Event chip component |
| `src/components/calendar/EventDetailPanel.tsx` | Calendar | Event detail modal |
| `src/components/layout/NotificationDropdown.tsx` | Notifications | Bell dropdown component |
| `src/components/profile/ProfileCard.tsx` | Profile | Personal info display/edit card |
| `src/components/profile/ChangePasswordModal.tsx` | Profile | Password change modal |
| `src/components/profile/EditProfileModal.tsx` | Profile | Profile edit modal |
| `src/components/profile/PortfolioStats.tsx` | Profile | Portfolio summary stats |
| `src/components/employees/EmployeeEditModal.tsx` | Admin | Employee edit + delete modal |
| `src/components/dispatch/DispatchFormModal.tsx` | Admin | Create/edit dispatch form |
| `src/app/(main)/calendar/page.tsx` | Calendar | Calendar page |
| `src/app/(main)/profile/page.tsx` | Profile | Own profile page |
| `src/app/(main)/profile/[empId]/page.tsx` | Profile | Employee profile (manager view) |
| `src/app/(main)/work-reports/review/page.tsx` | Reports | Report review dashboard |
| `src/app/(main)/dispatch/manage/page.tsx` | Dispatch | Dispatch management page |
| `src/app/(main)/settings/page.tsx` | Settings | System settings page |
### 5.4 Frontend — Files to Modify
| File | Feature | Change |
|------|---------|--------|
| `src/types/index.ts` | All | Add `Notification.linkUrl`, `CalendarEvent`, `ReportSummary`, `CalendarEvent` types |
| `src/services/index.ts` | All | Export new services |
| `src/services/employeeService.ts` | Profile | Add `getMeFull()`, `changePassword()` |
| `src/services/reportService.ts` | Reports | Add `getSummary()` |
| `src/components/layout/Header.tsx` | Calendar + Profile + Notifications | Calendar → `/calendar`, integrate NotificationDropdown, avatar → `/profile` |
| `src/components/layout/Sidebar.tsx` | All | Add Calendar, Report Review, Settings links (with RBAC) |
| `src/app/(main)/page.tsx` | Reports | Link "Pending Reports" card to `/work-reports/review` |
| `src/app/(main)/employees/page.tsx` | Admin | Wire MoreHorizontal to edit modal |
---
## 6. Recommended Implementation Order
```
Week 1: Quick Wins
Day 1-2: Notifications (Dropdown UI + linkUrl) ← P1, ~2d
Day 3-5: User Profile (ProfilePage + ChangePassword) ← P1, ~4d
Week 2: Calendar + Report Management
Day 1-3: Employee Edit/Delete (EmployeeEditModal) ← P1, ~1.5d
Day 3-5: Report Monitoring Dashboard ← P1, ~2d
Week 3: Calendar + Dispatch
Day 1-5: Calendar (Backend aggregation + Full Calendar page) ← P2, ~5d
Week 4: Admin Features
Day 1-3: Dispatch Management (CRUD endpoints + page) ← P2, ~3d
Day 4-5: System Settings (CommonCode CRUD + Settings page) ← P2, ~1.5d
```
**Alternative — parallel by developer:**
- Dev A: Calendar (5d) + Settings (1.5d) = 6.5d
- Dev B: Notifications (2d) + Profile (4d) = 6d
- Dev C: Employee Edit (1.5d) + Report Dashboard (2d) + Dispatch (3d) = 6.5d
- **Total calendar time: ~1.5 weeks with 3 developers**
---
## 7. Risk Assessment
| Risk | Impact | Mitigation |
|------|--------|------------|
| Calendar aggregation performance with large datasets | Medium | Add DB indexes on `due_date`, `target_date`; paginate results |
| Notification polling load | Low | Already 30s interval — acceptable. Could go to 60s after 30min idle |
| Password change breaks existing sessions | Medium | Option A: Invalidate all tokens on password change. Option B: Add `tokenVersion` to user and check on JWT validation |
| DispatchHistory creation without project exists validation | Medium | Backend must validate project exists and is not completed/hold |
| Common code changes break existing dropdowns | High | Never hard-delete common codes — add `is_active` toggle instead. Frontend caches codes on load |
| Concurrent employee edits by multiple admins | Low | Add `@Version` optimistic lock to Employee entity |
---
## 8. Quick Wins (Low Effort, High Impact)
If you only have 1 day, do these:
1. **Notification Dropdown** (~2h) — Make the bell icon functional. Just build the dropdown UI, no backend changes needed. Notifications already have type/title/message.
2. **Header Calendar fix** (~5min) — Change `onClick={() => router.push('/issues')}` to `onClick={() => router.push('/calendar')}` even before building the calendar page — at least the button has a logical destination.
3. **Header avatar → /profile** (~5min) — Wrap the avatar/name in a Link to `/profile`.
4. **Employee MoreHorizontal → Edit** (~2h) — Wire the existing `PUT /employees/{id}` backend to a simple edit form.
+676
View File
@@ -0,0 +1,676 @@
# Antigravity Skill Bundles
> **Curated collections of skills organized by role and expertise level.** Don't know where to start? Pick a bundle below to get a curated set of skills for your role.
> These packs are curated starter recommendations for humans. Generated bundle ids in `data/bundles.json` are broader catalog/workflow groupings and do not need to map 1:1 to the editorial packs below.
> **Important:** bundles are installable plugin subsets and activation presets, not invokable mega-skills such as `@web-wizard` or `/essentials-bundle`. Use the individual skills listed in the pack, install the bundle as a dedicated marketplace plugin, or use the activation scripts if you want only that bundle's skills active in your live Antigravity directory.
> **Plugin compatibility:** root plugins and bundle plugins only publish plugin-safe skills. If a bundle shows `pending hardening`, the skills still exist in the repository, but that bundle is not yet published for that target. `Requires manual setup` means the bundle is installable, but one or more included skills need an explicit setup step before first use.
## Quick Start
1. **Install the repository or bundle plugin:**
```bash
npx antigravity-awesome-skills
# or clone manually
git clone https://github.com/sickn33/antigravity-awesome-skills.git .agent/skills
```
2. **Choose your bundle** from the list below based on your role or interests.
3. **Use bundle plugins or individual skills** in your AI assistant:
- Claude Code: install the matching marketplace bundle plugin, or invoke `>> /skill-name help me...`
- Codex CLI / Codex app: install the matching bundle plugin where plugin marketplaces are available, or invoke `Use skill-name...`
- Cursor: `@skill-name` in chat
- Gemini CLI: `Use skill-name...`
If you want a bundle to behave like a focused active subset instead of a full install, use:
- macOS/Linux: `./scripts/activate-skills.sh --clear Essentials`
- macOS/Linux: `./scripts/activate-skills.sh --clear "Web Wizard"`
- Windows: `.\scripts\activate-skills.bat --clear Essentials`
---
## Essentials & Core
### 🚀 The "Essentials" Starter Pack
_For everyone. Install these first._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`concise-planning`](../../skills/concise-planning/): Always start with a plan.
- [`lint-and-validate`](../../skills/lint-and-validate/): Keep your code clean automatically.
- [`git-pushing`](../../skills/git-pushing/): Save your work safely.
- [`kaizen`](../../skills/kaizen/): Continuous improvement mindset.
- [`systematic-debugging`](../../skills/systematic-debugging/): Debug like a pro.
---
## Security & Compliance
### 🛡️ The "Security Engineer" Pack
_For pentesting, auditing, and hardening._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`ethical-hacking-methodology`](../../skills/ethical-hacking-methodology/): The Bible of ethical hacking.
- [`burp-suite-testing`](../../skills/burp-suite-testing/): Web vulnerability scanning.
- [`top-web-vulnerabilities`](../../skills/top-web-vulnerabilities/): OWASP-aligned vulnerability taxonomy.
- [`linux-privilege-escalation`](../../skills/linux-privilege-escalation/): Advanced Linux security assessment.
- [`cloud-penetration-testing`](../../skills/cloud-penetration-testing/): AWS/Azure/GCP security.
- [`security-auditor`](../../skills/security-auditor/): Comprehensive security audits.
- [`vulnerability-scanner`](../../skills/vulnerability-scanner/): Advanced vulnerability analysis.
### 🔐 The "Security Developer" Pack
_For building secure applications._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`api-security-best-practices`](../../skills/api-security-best-practices/): Secure API design patterns.
- [`auth-implementation-patterns`](../../skills/auth-implementation-patterns/): JWT, OAuth2, session management.
- [`backend-security-coder`](../../skills/backend-security-coder/): Secure backend coding practices.
- [`frontend-security-coder`](../../skills/frontend-security-coder/): XSS prevention and client-side security.
- [`cc-skill-security-review`](../../skills/cc-skill-security-review/): Security checklist for features.
- [`pci-compliance`](../../skills/pci-compliance/): Payment card security standards.
---
## 🌐 Web Development
### 🌐 The "Web Wizard" Pack
_For building modern, high-performance web apps._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`frontend-design`](../../skills/frontend-design/): UI guidelines and aesthetics.
- [`react-best-practices`](../../skills/react-best-practices/): React & Next.js performance optimization.
- [`react-patterns`](../../skills/react-patterns/): Modern React patterns and principles.
- [`nextjs-best-practices`](../../skills/nextjs-best-practices/): Next.js App Router patterns.
- [`tailwind-patterns`](../../skills/tailwind-patterns/): Tailwind CSS v4 styling superpowers.
- [`form-cro`](../../skills/form-cro/): Optimize your forms for conversion.
- [`seo-audit`](../../skills/seo-audit/): Get found on Google.
### 🖌️ The "Web Designer" Pack
_For pixel-perfect experiences._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`ui-ux-pro-max`](../../skills/ui-ux-pro-max/): Premium design systems and tokens.
- [`frontend-design`](../../skills/frontend-design/): The base layer of aesthetics.
- [`3d-web-experience`](../../skills/3d-web-experience/): Three.js & React Three Fiber magic.
- [`canvas-design`](../../skills/canvas-design/): Static visuals and posters.
- [`mobile-design`](../../skills/mobile-design/): Mobile-first design principles.
- [`scroll-experience`](../../skills/scroll-experience/): Immersive scroll-driven experiences.
### ⚡ The "Full-Stack Developer" Pack
_For end-to-end web application development._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`senior-fullstack`](../../skills/senior-fullstack/): Complete fullstack development guide.
- [`frontend-developer`](../../skills/frontend-developer/): React 19+ and Next.js 15+ expertise.
- [`backend-dev-guidelines`](../../skills/backend-dev-guidelines/): Node.js/Express/TypeScript patterns.
- [`api-patterns`](../../skills/api-patterns/): REST vs GraphQL vs tRPC selection.
- [`database-design`](../../skills/database-design/): Schema design and ORM selection.
- [`stripe-integration`](../../skills/stripe-integration/): Payments and subscriptions.
---
## 🤖 AI & Agents
### 🤖 The "Agent Architect" Pack
_For building AI systems and autonomous agents._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`agent-evaluation`](../../skills/agent-evaluation/): Test and benchmark your agents.
- [`langgraph`](../../skills/langgraph/): Build stateful agent workflows.
- [`mcp-builder`](../../skills/mcp-builder/): Create your own MCP tools.
- [`prompt-engineering`](../../skills/prompt-engineering/): Master the art of talking to LLMs.
- [`ai-agents-architect`](../../skills/ai-agents-architect/): Design autonomous AI agents.
- [`rag-engineer`](../../skills/rag-engineer/): Build RAG systems with vector search.
### 🧠 The "LLM Application Developer" Pack
_For building production LLM applications._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`llm-app-patterns`](../../skills/llm-app-patterns/): Production-ready LLM patterns.
- [`rag-implementation`](../../skills/rag-implementation/): Retrieval-Augmented Generation.
- [`prompt-caching`](../../skills/prompt-caching/): Cache strategies for LLM prompts.
- [`context-window-management`](../../skills/context-window-management/): Manage LLM context efficiently.
- [`langfuse`](../../skills/langfuse/): LLM observability and tracing.
---
## 🎮 Game Development
### 🎮 The "Indie Game Dev" Pack
_For building games with AI assistants._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`game-development/game-design`](../../skills/game-development/game-design/): Mechanics and loops.
- [`game-development/2d-games`](../../skills/game-development/2d-games/): Sprites and physics.
- [`game-development/3d-games`](../../skills/game-development/3d-games/): Models and shaders.
- [`unity-developer`](../../skills/unity-developer/): Unity 6 LTS development.
- [`godot-gdscript-patterns`](../../skills/godot-gdscript-patterns/): Godot 4 GDScript patterns.
- [`algorithmic-art`](../../skills/algorithmic-art/): Generate assets with code.
---
## 🐍 Backend & Languages
### 🐍 The "Python Pro" Pack
_For backend heavyweights and data scientists._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`python-pro`](../../skills/python-pro/): Master Python 3.12+ with modern features.
- [`python-patterns`](../../skills/python-patterns/): Idiomatic Python code.
- [`fastapi-pro`](../../skills/fastapi-pro/): High-performance async APIs.
- [`fastapi-templates`](../../skills/fastapi-templates/): Production-ready FastAPI projects.
- [`django-pro`](../../skills/django-pro/): The battery-included framework.
- [`python-testing-patterns`](../../skills/python-testing-patterns/): Comprehensive testing with pytest.
- [`async-python-patterns`](../../skills/async-python-patterns/): Python asyncio mastery.
### 🟦 The "TypeScript & JavaScript" Pack
_For modern web development._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`typescript-expert`](../../skills/typescript-expert/): TypeScript mastery and advanced types.
- [`javascript-pro`](../../skills/javascript-pro/): Modern JavaScript with ES6+.
- [`react-best-practices`](../../skills/react-best-practices/): React performance optimization.
- [`nodejs-best-practices`](../../skills/nodejs-best-practices/): Node.js development principles.
- [`nextjs-app-router-patterns`](../../skills/nextjs-app-router-patterns/): Next.js 14+ App Router.
### 🦀 The "Systems Programming" Pack
_For low-level and performance-critical code._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`rust-pro`](../../skills/rust-pro/): Rust 1.75+ with async patterns.
- [`go-concurrency-patterns`](../../skills/go-concurrency-patterns/): Go concurrency mastery.
- [`golang-pro`](../../skills/golang-pro/): Go development expertise.
- [`memory-safety-patterns`](../../skills/memory-safety-patterns/): Memory-safe programming.
- [`cpp-pro`](../../skills/cpp-pro/): Modern C++ development.
---
## 🦄 Product & Business
### 🦄 The "Startup Founder" Pack
_For building products, not just code._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`product-manager-toolkit`](../../skills/product-manager-toolkit/): RICE prioritization, PRD templates.
- [`competitive-landscape`](../../skills/competitive-landscape/): Competitor analysis.
- [`competitor-alternatives`](../../skills/competitor-alternatives/): Create comparison pages.
- [`launch-strategy`](../../skills/launch-strategy/): Product launch planning.
- [`copywriting`](../../skills/copywriting/): Marketing copy that converts.
- [`stripe-integration`](../../skills/stripe-integration/): Get paid from day one.
### 📊 The "Business Analyst" Pack
_For data-driven decision making._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`business-analyst`](../../skills/business-analyst/): AI-powered analytics and KPIs.
- [`startup-metrics-framework`](../../skills/startup-metrics-framework/): SaaS metrics and unit economics.
- [`startup-financial-modeling`](../../skills/startup-financial-modeling/): 3-5 year financial projections.
- [`market-sizing-analysis`](../../skills/market-sizing-analysis/): TAM/SAM/SOM calculations.
- [`kpi-dashboard-design`](../../skills/kpi-dashboard-design/): Effective KPI dashboards.
### 📈 The "Marketing & Growth" Pack
_For driving user acquisition and retention._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`content-creator`](../../skills/content-creator/): SEO-optimized marketing content.
- [`seo-audit`](../../skills/seo-audit/): Technical SEO health checks.
- [`programmatic-seo`](../../skills/programmatic-seo/): Create pages at scale.
- [`analytics-tracking`](../../skills/analytics-tracking/): Set up GA4/PostHog correctly.
- [`ab-test-setup`](../../skills/ab-test-setup/): Validated learning experiments.
- [`email-sequence`](../../skills/email-sequence/): Automated email campaigns.
---
## DevOps & Infrastructure
### 🌧️ The "DevOps & Cloud" Pack
_For infrastructure and scaling._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`docker-expert`](../../skills/docker-expert/): Master containers and multi-stage builds.
- [`aws-serverless`](../../skills/aws-serverless/): Serverless on AWS (Lambda, DynamoDB).
- [`kubernetes-architect`](../../skills/kubernetes-architect/): K8s architecture and GitOps.
- [`terraform-specialist`](../../skills/terraform-specialist/): Infrastructure as Code mastery.
- [`environment-setup-guide`](../../skills/environment-setup-guide/): Standardization for teams.
- [`deployment-procedures`](../../skills/deployment-procedures/): Safe rollout strategies.
- [`bash-linux`](../../skills/bash-linux/): Terminal wizardry.
### 📊 The "Observability & Monitoring" Pack
_For production reliability._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`observability-engineer`](../../skills/observability-engineer/): Comprehensive monitoring systems.
- [`distributed-tracing`](../../skills/distributed-tracing/): Track requests across microservices.
- [`slo-implementation`](../../skills/slo-implementation/): Service Level Objectives.
- [`incident-responder`](../../skills/incident-responder/): Rapid incident response.
- [`postmortem-writing`](../../skills/postmortem-writing/): Blameless postmortems.
- [`performance-engineer`](../../skills/performance-engineer/): Application performance optimization.
---
## 📊 Data & Analytics
### 📊 The "Data & Analytics" Pack
_For making sense of the numbers._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`analytics-tracking`](../../skills/analytics-tracking/): Set up GA4/PostHog correctly.
- [`claude-d3js-skill`](../../skills/claude-d3js-skill/): Beautiful custom visualizations with D3.js.
- [`sql-pro`](../../skills/sql-pro/): Modern SQL with cloud-native databases.
- [`postgres-best-practices`](../../skills/postgres-best-practices/): Postgres optimization.
- [`ab-test-setup`](../../skills/ab-test-setup/): Validated learning.
- [`database-architect`](../../skills/database-architect/): Database design from scratch.
### 🔄 The "Data Engineering" Pack
_For building data pipelines._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`data-engineer`](../../skills/data-engineer/): Data pipeline architecture.
- [`airflow-dag-patterns`](../../skills/airflow-dag-patterns/): Apache Airflow DAGs.
- [`dbt-transformation-patterns`](../../skills/dbt-transformation-patterns/): Analytics engineering.
- [`vector-database-engineer`](../../skills/vector-database-engineer/): Vector databases for RAG.
- [`embedding-strategies`](../../skills/embedding-strategies/): Embedding model selection.
---
## 🎨 Creative & Content
### 🎨 The "Creative Director" Pack
_For visuals, content, and branding._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`canvas-design`](../../skills/canvas-design/): Generate posters and diagrams.
- [`frontend-design`](../../skills/frontend-design/): UI aesthetics.
- [`content-creator`](../../skills/content-creator/): SEO-optimized blog posts.
- [`copy-editing`](../../skills/copy-editing/): Polish your prose.
- [`algorithmic-art`](../../skills/algorithmic-art/): Code-generated masterpieces.
- [`interactive-portfolio`](../../skills/interactive-portfolio/): Portfolios that land jobs.
---
## 🐞 Quality Assurance
### 🐞 The "QA & Testing" Pack
_For breaking things before users do._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`test-driven-development`](../../skills/test-driven-development/): Red, Green, Refactor.
- [`systematic-debugging`](../../skills/systematic-debugging/): Debug like Sherlock Holmes.
- [`browser-automation`](../../skills/browser-automation/): End-to-end testing with Playwright.
- [`e2e-testing-patterns`](../../skills/e2e-testing-patterns/): Reliable E2E test suites.
- [`ab-test-setup`](../../skills/ab-test-setup/): Validated experiments.
- [`code-review-checklist`](../../skills/code-review-checklist/): Catch bugs in PRs.
- [`test-fixing`](../../skills/test-fixing/): Fix failing tests systematically.
---
## 🔧 Specialized Packs
### 📱 The "Mobile Developer" Pack
_For iOS, Android, and cross-platform apps._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`mobile-developer`](../../skills/mobile-developer/): Cross-platform mobile development.
- [`react-native-architecture`](../../skills/react-native-architecture/): React Native with Expo.
- [`flutter-expert`](../../skills/flutter-expert/): Flutter multi-platform apps.
- [`ios-developer`](../../skills/ios-developer/): iOS development with Swift.
- [`app-store-optimization`](../../skills/app-store-optimization/): ASO for App Store and Play Store.
### 🔗 The "Integration & APIs" Pack
_For connecting services and building integrations._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`stripe-integration`](../../skills/stripe-integration/): Payments and subscriptions.
- [`twilio-communications`](../../skills/twilio-communications/): SMS, voice, WhatsApp.
- [`hubspot-integration`](../../skills/hubspot-integration/): CRM integration.
- [`plaid-fintech`](../../skills/plaid-fintech/): Bank account linking and ACH.
- [`algolia-search`](../../skills/algolia-search/): Search implementation.
### 🎯 The "Architecture & Design" Pack
_For system design and technical decisions._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`senior-architect`](../../skills/senior-architect/): Comprehensive software architecture.
- [`architecture-patterns`](../../skills/architecture-patterns/): Clean Architecture, DDD, Hexagonal.
- [`microservices-patterns`](../../skills/microservices-patterns/): Microservices architecture.
- [`event-sourcing-architect`](../../skills/event-sourcing-architect/): Event sourcing and CQRS.
- [`architecture-decision-records`](../../skills/architecture-decision-records/): Document technical decisions.
### 🧱 The "DDD & Evented Architecture" Pack
_For teams modeling complex domains and evolving toward evented systems._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`domain-driven-design`](../../skills/domain-driven-design/): Route DDD work from strategic modeling to implementation patterns.
- [`ddd-strategic-design`](../../skills/ddd-strategic-design/): Subdomains, bounded contexts, and ubiquitous language.
- [`ddd-context-mapping`](../../skills/ddd-context-mapping/): Cross-context integration and anti-corruption boundaries.
- [`ddd-tactical-patterns`](../../skills/ddd-tactical-patterns/): Aggregates, value objects, repositories, and domain events.
- [`cqrs-implementation`](../../skills/cqrs-implementation/): Read/write model separation.
- [`event-store-design`](../../skills/event-store-design/): Event persistence and replay architecture.
- [`saga-orchestration`](../../skills/saga-orchestration/): Cross-context long-running transaction coordination.
- [`projection-patterns`](../../skills/projection-patterns/): Materialized read models from event streams.
### 🤖 The "Automation Builder" Pack
_For connecting tools and building repeatable automated workflows._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`workflow-automation`](../../skills/workflow-automation/): Design durable automation flows for AI and business systems.
- [`mcp-builder`](../../skills/mcp-builder/): Create tool interfaces agents can use reliably.
- [`make-automation`](../../skills/make-automation/): Build automations in Make/Integromat.
- [`airtable-automation`](../../skills/airtable-automation/): Automate Airtable records, bases, and views.
- [`notion-automation`](../../skills/notion-automation/): Automate Notion pages, databases, and blocks.
- [`slack-automation`](../../skills/slack-automation/): Automate Slack messaging and channel workflows.
- [`googlesheets-automation`](../../skills/googlesheets-automation/): Automate spreadsheet updates and data operations.
### 💼 The "RevOps & CRM Automation" Pack
_For revenue operations, support handoffs, and CRM-heavy automation._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`hubspot-automation`](../../skills/hubspot-automation/): Automate contacts, companies, deals, and tickets.
- [`sendgrid-automation`](../../skills/sendgrid-automation/): Automate email sends, contacts, and templates.
- [`zendesk-automation`](../../skills/zendesk-automation/): Automate support tickets and reply workflows.
- [`google-calendar-automation`](../../skills/google-calendar-automation/): Schedule events and manage availability.
- [`outlook-calendar-automation`](../../skills/outlook-calendar-automation/): Automate Outlook meetings and invitations.
- [`stripe-automation`](../../skills/stripe-automation/): Automate billing, invoices, and subscriptions.
- [`shopify-automation`](../../skills/shopify-automation/): Automate products, orders, customers, and inventory.
### 💳 The "Commerce & Payments" Pack
_For monetization, payments, and commerce workflows._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`stripe-integration`](../../skills/stripe-integration/): Build robust checkout, subscription, and webhook flows.
- [`paypal-integration`](../../skills/paypal-integration/): Integrate PayPal payments and related flows.
- [`plaid-fintech`](../../skills/plaid-fintech/): Link bank accounts and handle ACH-related use cases.
- [`hubspot-integration`](../../skills/hubspot-integration/): Connect CRM data into product and revenue workflows.
- [`algolia-search`](../../skills/algolia-search/): Add search and discovery to commerce experiences.
- [`monetization`](../../skills/monetization/): Design pricing and monetization systems deliberately.
### 🏢 The "Odoo ERP" Pack
_For teams building or operating around Odoo-based business systems._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`odoo-module-developer`](../../skills/odoo-module-developer/): Create custom Odoo modules cleanly.
- [`odoo-orm-expert`](../../skills/odoo-orm-expert/): Work effectively with Odoo ORM patterns and performance.
- [`odoo-sales-crm-expert`](../../skills/odoo-sales-crm-expert/): Optimize sales pipelines, leads, and forecasting.
- [`odoo-ecommerce-configurator`](../../skills/odoo-ecommerce-configurator/): Configure storefront, catalog, and order flows.
- [`odoo-performance-tuner`](../../skills/odoo-performance-tuner/): Diagnose and improve slow Odoo instances.
- [`odoo-security-rules`](../../skills/odoo-security-rules/): Apply secure access controls and rule design.
- [`odoo-docker-deployment`](../../skills/odoo-docker-deployment/): Deploy and run Odoo in Docker-based environments.
### ☁️ The "Azure AI & Cloud" Pack
_For building on Azure across cloud, AI, and platform services._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`azd-deployment`](../../skills/azd-deployment/): Ship Azure apps with Azure Developer CLI workflows.
- [`azure-functions`](../../skills/azure-functions/): Build serverless workloads with Azure Functions.
- [`azure-ai-openai-dotnet`](../../skills/azure-ai-openai-dotnet/): Use Azure OpenAI from .NET applications.
- [`azure-search-documents-py`](../../skills/azure-search-documents-py/): Build search, hybrid search, and indexing in Python.
- [`azure-identity-py`](../../skills/azure-identity-py/): Handle Azure authentication flows in Python services.
- [`azure-monitor-opentelemetry-ts`](../../skills/azure-monitor-opentelemetry-ts/): Add telemetry and tracing from TypeScript apps.
### 📲 The "Expo & React Native" Pack
_For shipping mobile apps with Expo and React Native._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`react-native-architecture`](../../skills/react-native-architecture/): Structure production React Native apps well.
- [`expo-api-routes`](../../skills/expo-api-routes/): Build API routes in Expo Router and EAS Hosting.
- [`expo-dev-client`](../../skills/expo-dev-client/): Build and distribute Expo development clients.
- [`expo-tailwind-setup`](../../skills/expo-tailwind-setup/): Set up Tailwind and NativeWind in Expo apps.
- [`expo-cicd-workflows`](../../skills/expo-cicd-workflows/): Automate builds and releases with EAS workflows.
- [`expo-deployment`](../../skills/expo-deployment/): Deploy Expo apps and manage release flow.
- [`app-store-optimization`](../../skills/app-store-optimization/): Improve App Store and Play Store discoverability.
### 🍎 The "Apple Platform Design" Pack
_For teams designing native-feeling Apple platform experiences._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`hig-foundations`](../../skills/hig-foundations/): Learn the core Apple Human Interface Guidelines.
- [`hig-patterns`](../../skills/hig-patterns/): Apply Apple interaction and UX patterns correctly.
- [`hig-components-layout`](../../skills/hig-components-layout/): Use Apple layout and navigation components well.
- [`hig-inputs`](../../skills/hig-inputs/): Design for gestures, keyboards, Pencil, focus, and controllers.
- [`hig-components-system`](../../skills/hig-components-system/): Work with widgets, live activities, and system surfaces.
- [`hig-platforms`](../../skills/hig-platforms/): Adapt experiences across Apple device families.
### 🧩 The "Makepad Builder" Pack
_For building UI-heavy apps with the Makepad ecosystem._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`makepad-basics`](../../skills/makepad-basics/): Start with Makepad fundamentals and mental model.
- [`makepad-layout`](../../skills/makepad-layout/): Handle sizing, flow, alignment, and layout composition.
- [`makepad-widgets`](../../skills/makepad-widgets/): Build interfaces from Makepad widgets.
- [`makepad-event-action`](../../skills/makepad-event-action/): Wire interaction and event handling correctly.
- [`makepad-shaders`](../../skills/makepad-shaders/): Create GPU-driven visual effects and custom drawing.
- [`makepad-deployment`](../../skills/makepad-deployment/): Package and ship Makepad projects.
### 🔎 The "SEO Specialist" Pack
_For technical SEO, content structure, and search growth._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`seo-fundamentals`](../../skills/seo-fundamentals/): Build from sound SEO principles and search constraints.
- [`seo-content-planner`](../../skills/seo-content-planner/): Plan clusters, calendars, and content gaps.
- [`seo-content-writer`](../../skills/seo-content-writer/): Produce search-aware content drafts with intent alignment.
- [`seo-structure-architect`](../../skills/seo-structure-architect/): Improve hierarchy, internal links, and structure.
- [`seo-cannibalization-detector`](../../skills/seo-cannibalization-detector/): Find overlapping pages competing for the same intent.
- [`seo-content-auditor`](../../skills/seo-content-auditor/): Audit existing content quality and optimization gaps.
- [`schema-markup`](../../skills/schema-markup/): Add structured data to support richer search results.
### 📄 The "Documents & Presentations" Pack
_For document-heavy workflows, spreadsheets, PDFs, and presentations._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`office-productivity`](../../skills/office-productivity/): Coordinate document, spreadsheet, and presentation workflows.
- [`docx-official`](../../skills/docx-official/): Create and edit Word-compatible documents.
- [`pptx-official`](../../skills/pptx-official/): Create and edit PowerPoint-compatible presentations.
- [`xlsx-official`](../../skills/xlsx-official/): Create and analyze spreadsheet files with formulas and formatting.
- [`pdf-official`](../../skills/pdf-official/): Extract, generate, and manipulate PDFs programmatically.
- [`google-slides-automation`](../../skills/google-slides-automation/): Automate presentation updates in Google Slides.
- [`google-sheets-automation`](../../skills/google-sheets-automation/): Automate reads and writes in Google Sheets.
---
## 🧰 Maintainer & OSS
### 🛠️ The "OSS Maintainer" Pack
_For shipping clean changes in public repositories._
**Plugin status:** Codex plugin-safe · Claude plugin-safe
- [`commit`](../../skills/commit/): High-quality conventional commits.
- [`create-pr`](../../skills/create-pr/): PR creation with review-ready context.
- [`requesting-code-review`](../../skills/requesting-code-review/): Ask for targeted, high-signal reviews.
- [`receiving-code-review`](../../skills/receiving-code-review/): Apply feedback with technical rigor.
- [`changelog-automation`](../../skills/changelog-automation/): Keep release notes and changelogs consistent.
- [`git-advanced-workflows`](../../skills/git-advanced-workflows/): Rebase, cherry-pick, bisect, recovery.
- [`documentation-templates`](../../skills/documentation-templates/): Standardize docs and handoffs.
### 🧱 The "Skill Author" Pack
_For creating and maintaining high-quality SKILL.md assets._
**Plugin status:** Codex pending hardening · Claude pending hardening
- [`skill-creator`](../../skills/skill-creator/): Design effective new skills.
- [`skill-developer`](../../skills/skill-developer/): Implement triggers, hooks, and skill lifecycle.
- [`writing-skills`](../../skills/writing-skills/): Improve clarity and structure of skill instructions.
- [`documentation-generation-doc-generate`](../../skills/documentation-generation-doc-generate/): Generate maintainable technical docs.
- [`lint-and-validate`](../../skills/lint-and-validate/): Validate quality after edits.
- [`verification-before-completion`](../../skills/verification-before-completion/): Confirm changes before claiming done.
## 📚 How to Use Bundles
### 1) Pick by immediate goal
- Need to ship a feature now: `Essentials` + one domain pack (`Web Wizard`, `Python Pro`, `DevOps & Cloud`).
- Need reliability and hardening: add `QA & Testing` + `Security Developer`.
- Need product growth: add `Startup Founder` or `Marketing & Growth`.
### 2) Start with 3-5 skills, not 20
Pick the minimum set for your current milestone. Expand only when you hit a real gap.
### 3) Invoke skills consistently
- **Claude Code**: install a bundle plugin or use `>> /skill-name help me...`
- **Codex CLI**: install a bundle plugin where marketplaces are available, or use `Use skill-name...`
- **Cursor**: `@skill-name` in chat
- **Gemini CLI**: `Use skill-name...`
### 4) Build your personal shortlist
Keep a small list of high-frequency skills and reuse it across tasks to reduce context switching.
## 🧩 Recommended Bundle Combos
### Ship a SaaS MVP (2 weeks)
`Essentials` + `Full-Stack Developer` + `QA & Testing` + `Startup Founder`
### Harden an existing production app
`Essentials` + `Security Developer` + `DevOps & Cloud` + `Observability & Monitoring`
### Build an AI product
`Essentials` + `Agent Architect` + `LLM Application Developer` + `Data Engineering`
### Grow traffic and conversions
`Web Wizard` + `Marketing & Growth` + `Data & Analytics`
### Launch and maintain open source
`Essentials` + `OSS Maintainer` + `Architecture & Design`
---
## Learning Paths
### Beginner → Intermediate → Advanced
**Web Development:**
1. Start: `Essentials` → `Web Wizard`
2. Grow: `Full-Stack Developer` → `Architecture & Design`
3. Master: `Observability & Monitoring` → `Security Developer`
**AI/ML:**
1. Start: `Essentials` → `Agent Architect`
2. Grow: `LLM Application Developer` → `Data Engineering`
3. Master: Advanced RAG and agent orchestration
**Security:**
1. Start: `Essentials` → `Security Developer`
2. Grow: `Security Engineer` → Advanced pentesting
3. Master: Red team tactics and threat modeling
**Open Source Maintenance:**
1. Start: `Essentials` → `OSS Maintainer`
2. Grow: `Architecture & Design` → `QA & Testing`
3. Master: `Skill Author` + release automation workflows
---
## Contributing
Found a skill that should be in a bundle? Or want to create a new bundle? [Open an issue](https://github.com/sickn33/antigravity-awesome-skills/issues) or submit a PR!
---
## Related Documentation
- [Getting Started Guide](getting-started.md)
- [Full Skill Catalog](../../CATALOG.md)
- [Contributing Guide](../../CONTRIBUTING.md)
---
_Last updated: March 2026 | Total Skills: 1,340+ | Total Bundles: 37_