init: SR System — Helpdesk & ITAM Portal
This commit is contained in:
@@ -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 타임스탬프强制 적용 |
|
||||
@@ -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'` 자변환
|
||||
@@ -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` 별도 관리
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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 |
|
||||
@@ -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)** 확인
|
||||
@@ -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.
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user