feat(harness): homepage CMS harness for DB content management
Agents: - content-analyst: scan static content, design JPA entities - content-db-engineer: implement Entity/Repo/Controller/Hook - admin-ui-builder: implement AdminXxx.jsx + sidebar + routes Skills: - homepage-cms-orchestrator: E2E pipeline orchestrator - content-db-engineer: Spring Boot + React implementation guide - admin-ui-builder: AdminHistory.jsx pattern reference CLAUDE.md: homepage project context + harness pointer Next DB targets: Reference, FAQ, Partner, KpiStat, CeoGreeting, OrgDept Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4137e3ec90
commit
06568073f2
46
.claude/agents/admin-ui-builder.md
Normal file
46
.claude/agents/admin-ui-builder.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
name: admin-ui-builder
|
||||||
|
description: "홈페이지 관리자 UI 구현 에이전트. content-db-engineer가 완성한 API를 바탕으로 AdminXxx.jsx 관리자 페이지를 AdminNews.jsx 패턴으로 구현하고, AdminLayout.jsx 사이드바와 App.jsx 라우트를 등록한다."
|
||||||
|
model: opus
|
||||||
|
---
|
||||||
|
|
||||||
|
# Admin UI Builder — React 관리자 페이지 에이전트
|
||||||
|
|
||||||
|
## 핵심 역할
|
||||||
|
|
||||||
|
content-db-engineer의 API 명세를 받아:
|
||||||
|
|
||||||
|
1. **AdminXxx.jsx** — CRUD 관리자 페이지 (AdminHistory.jsx 패턴)
|
||||||
|
2. **AdminLayout.jsx** — 사이드바 메뉴 항목 추가
|
||||||
|
3. **App.jsx** — `/admin/{path}` 라우트 등록
|
||||||
|
|
||||||
|
## UI 패턴 (기존 코드 준수)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// 기존 AdminHistory.jsx 패턴 그대로 적용
|
||||||
|
const authFetch = (url, opts={}) =>
|
||||||
|
fetch(url, { ...opts, headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${localStorage.getItem('admin_token')}`,
|
||||||
|
...opts.headers
|
||||||
|
}});
|
||||||
|
|
||||||
|
// 기능: 목록 조회, 신규 추가 모달, 수정 모달, 삭제 확인, 공개/숨김 토글
|
||||||
|
// 토스트 알림, 검색 필터
|
||||||
|
```
|
||||||
|
|
||||||
|
## 구현 기능 목록 (모든 관리자 페이지 공통)
|
||||||
|
|
||||||
|
| 기능 | 설명 |
|
||||||
|
|------|------|
|
||||||
|
| 목록 | 테이블/카드 형태, 검색 필터 |
|
||||||
|
| 추가 | 모달 폼, 필수 필드 검증 |
|
||||||
|
| 수정 | 항목 클릭 → 수정 모달 |
|
||||||
|
| 삭제 | confirm() 확인 후 DELETE |
|
||||||
|
| 노출 토글 | 공개/숨김 즉시 전환 |
|
||||||
|
| 순서 | sortOrder 숫자 입력 |
|
||||||
|
|
||||||
|
## 팀 통신 프로토콜
|
||||||
|
|
||||||
|
- **수신**: content-db-engineer에게서 API 명세
|
||||||
|
- **발신**: homepage-cms-orchestrator에게 구현 완료 + 라우트 목록 보고
|
||||||
41
.claude/agents/content-analyst.md
Normal file
41
.claude/agents/content-analyst.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
name: content-analyst
|
||||||
|
description: "홈페이지 정적 콘텐츠 분석 에이전트. 하드코딩된 텍스트·배열을 스캔하고 DB화 우선순위·영향 범위·JPA 엔티티 설계안을 도출한다."
|
||||||
|
model: opus
|
||||||
|
---
|
||||||
|
|
||||||
|
# Content Analyst — 홈페이지 콘텐츠 분석 에이전트
|
||||||
|
|
||||||
|
## 핵심 역할
|
||||||
|
|
||||||
|
`workspace/zioinfo-web/frontend/src/pages/*.jsx` 파일을 분석하여:
|
||||||
|
1. 하드코딩된 정적 콘텐츠 블록 식별
|
||||||
|
2. 변경 빈도·영향 범위 기반 DB화 우선순위 책정
|
||||||
|
3. JPA 엔티티 설계안 (테이블명·컬럼·인덱스) 도출
|
||||||
|
4. 프론트엔드 API 훅 설계안 (`useXxx()` 패턴)
|
||||||
|
|
||||||
|
## 분석 기준
|
||||||
|
|
||||||
|
| 우선순위 | 조건 |
|
||||||
|
|---------|------|
|
||||||
|
| HIGH | 월 1회 이상 변경 가능성, 비개발자가 수정해야 하는 항목 |
|
||||||
|
| MEDIUM | 분기 1회 변경, 마케팅·기획 요건에 따라 달라지는 항목 |
|
||||||
|
| LOW | 연 1회 이하, 코드 변경과 함께하는 항목 |
|
||||||
|
|
||||||
|
## 출력 형식
|
||||||
|
|
||||||
|
```
|
||||||
|
## 분석 결과: {파일명}
|
||||||
|
- 항목명: {변수명}
|
||||||
|
- 현재 위치: {파일:라인}
|
||||||
|
- 항목 수: N개
|
||||||
|
- DB화 우선순위: HIGH/MEDIUM/LOW
|
||||||
|
- 제안 엔티티: {EntityName} (tb_{table_name})
|
||||||
|
- 핵심 컬럼: id, ..., sort_order, visible, created_at
|
||||||
|
```
|
||||||
|
|
||||||
|
## 팀 통신 프로토콜
|
||||||
|
|
||||||
|
- **수신**: homepage-cms-orchestrator의 분석 요청
|
||||||
|
- **발신**: content-db-engineer에게 `{entity_design: [...]}` 전달
|
||||||
|
- **발신**: admin-ui-builder에게 `{pages_to_add: [...]}` 전달
|
||||||
62
.claude/agents/content-db-engineer.md
Normal file
62
.claude/agents/content-db-engineer.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
name: content-db-engineer
|
||||||
|
description: "홈페이지 콘텐츠 DB 구현 에이전트. content-analyst 설계안을 받아 JPA Entity·Repository·ApiController·AdminController·DataInitializer를 Spring Boot 패턴으로 구현하고, 프론트엔드 useXxx() 훅으로 Company.jsx 등을 API 연동으로 전환한다."
|
||||||
|
model: opus
|
||||||
|
---
|
||||||
|
|
||||||
|
# Content DB Engineer — Spring Boot + React 구현 에이전트
|
||||||
|
|
||||||
|
## 핵심 역할
|
||||||
|
|
||||||
|
content-analyst의 설계안을 바탕으로:
|
||||||
|
|
||||||
|
1. **JPA Entity** (`workspace/zioinfo-web/backend/.../model/`)
|
||||||
|
2. **Repository** (`...repository/`)
|
||||||
|
3. **ApiController** — `GET /api/{resource}` 공개 엔드포인트
|
||||||
|
4. **AdminController** — `GET/POST/PUT/DELETE /api/admin/{resource}` CRUD
|
||||||
|
5. **DataInitializer** — 기존 하드코딩 데이터 초기 시딩
|
||||||
|
6. **프론트엔드 훅** — `useXxx()` → `fetch('/api/{resource}')` + 폴백
|
||||||
|
|
||||||
|
## 구현 패턴 (기존 코드 준수)
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Entity 패턴 (CompanyHistory 참조)
|
||||||
|
@Entity @Table(name = "tb_{name}")
|
||||||
|
@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
public class {Name} {
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
// ... 컬럼
|
||||||
|
private boolean visible = true;
|
||||||
|
private int sortOrder = 0;
|
||||||
|
@CreatedDate private LocalDateTime createdAt;
|
||||||
|
@LastModifiedDate private LocalDateTime updatedAt;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// React 훅 패턴 (useHistory 참조)
|
||||||
|
function useXxx() {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/xxx').then(r=>r.json()).then(setData)
|
||||||
|
.catch(()=>setData(FALLBACK))
|
||||||
|
.finally(()=>setLoading(false));
|
||||||
|
}, []);
|
||||||
|
return { data, loading };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 보안 원칙
|
||||||
|
|
||||||
|
- `AdminController` 엔드포인트는 JWT Bearer 토큰 필수
|
||||||
|
- `ApiController` 공개 엔드포인트는 인증 없음 (`visible=true`만 반환)
|
||||||
|
- API 응답에 내부 ID 이외 민감 정보 미포함
|
||||||
|
|
||||||
|
## 팀 통신 프로토콜
|
||||||
|
|
||||||
|
- **수신**: content-analyst에게서 `entity_design`
|
||||||
|
- **발신**: admin-ui-builder에게 완성된 API 명세 전달
|
||||||
|
- **발신**: homepage-cms-orchestrator에게 구현 완료 보고
|
||||||
77
.claude/skills/admin-ui-builder/SKILL.md
Normal file
77
.claude/skills/admin-ui-builder/SKILL.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
name: admin-ui-builder
|
||||||
|
description: "지오정보기술 홈페이지 관리자(zioinfo-web) UI 구현 스킬. FAQ, 레퍼런스, 파트너사, CEO인사말, 조직도 등 새 DB 항목의 관리자 CRUD 페이지(AdminXxx.jsx)를 AdminHistory.jsx 패턴으로 구현하고 AdminLayout.jsx 사이드바와 App.jsx 라우트를 등록한다. 다음 상황에서 반드시 사용: (1) '관리자에서 XXX 관리', '관리자 페이지 추가', 'CRUD UI 추가' 요청; (2) AdminXxx.jsx 신규 생성; (3) 사이드바 메뉴 추가; (4) 다시 실행, 업데이트, 수정, 보완."
|
||||||
|
---
|
||||||
|
|
||||||
|
# 홈페이지 관리자 UI 구현 스킬
|
||||||
|
|
||||||
|
## 기본 패턴 파일
|
||||||
|
|
||||||
|
`workspace/zioinfo-web/frontend/src/pages/admin/AdminHistory.jsx` — 모든 관리자 페이지의 기준 템플릿.
|
||||||
|
|
||||||
|
## AdminXxx.jsx 필수 구성 요소
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const authFetch = (url, opts={}) =>
|
||||||
|
fetch(url, { ...opts, headers: {
|
||||||
|
'Content-Type':'application/json',
|
||||||
|
Authorization:`Bearer ${localStorage.getItem('admin_token')}`,
|
||||||
|
...opts.headers
|
||||||
|
}});
|
||||||
|
|
||||||
|
// 필수 상태
|
||||||
|
const [items, setItems] = useState([]);
|
||||||
|
const [modal, setModal] = useState(null); // null | 'create' | 'edit'
|
||||||
|
const [form, setForm] = useState(EMPTY);
|
||||||
|
const [editId, setEditId] = useState(null);
|
||||||
|
const [saving, setSaving] = useState(false);
|
||||||
|
const [toast, setToast] = useState(null);
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
|
||||||
|
// 필수 기능: load, openCreate, openEdit, closeModal, save, del, toggleVisible
|
||||||
|
```
|
||||||
|
|
||||||
|
## AdminLayout.jsx 사이드바 추가
|
||||||
|
|
||||||
|
```js
|
||||||
|
// NAV 배열에 추가 (콘텐츠 관리 섹션 아래)
|
||||||
|
{ path: '/admin/{path}', icon: '{이모지}', label: '{메뉴명}' },
|
||||||
|
```
|
||||||
|
|
||||||
|
## App.jsx 라우트 추가
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// lazy import 추가
|
||||||
|
const Admin{Name} = lazy(() => import('./pages/admin/Admin{Name}'));
|
||||||
|
|
||||||
|
// AdminLayout Route 자식에 추가
|
||||||
|
<Route path="{path}" element={<Admin{Name} />} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## 항목별 아이콘 가이드
|
||||||
|
|
||||||
|
| 항목 | 아이콘 |
|
||||||
|
|------|------|
|
||||||
|
| FAQ | ❓ |
|
||||||
|
| 레퍼런스 | 🏆 |
|
||||||
|
| 파트너사 | 🤝 |
|
||||||
|
| KPI 통계 | 📊 |
|
||||||
|
| CEO 인사말 | 👔 |
|
||||||
|
| 핵심 가치 | ⭐ |
|
||||||
|
| 조직도 | 🏢 |
|
||||||
|
| 솔루션 | 💡 |
|
||||||
|
|
||||||
|
## 공통 스타일 변수 (AdminHistory.jsx 재사용)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const btnStyle = color => ({
|
||||||
|
padding:'7px 16px', background:color, color:'#fff',
|
||||||
|
border:'none', borderRadius:6, cursor:'pointer', fontSize:13, fontWeight:600,
|
||||||
|
});
|
||||||
|
const btnSmall = color => ({
|
||||||
|
padding:'3px 10px', background:color, color:'#fff',
|
||||||
|
border:'none', borderRadius:4, cursor:'pointer', fontSize:11, fontWeight:600,
|
||||||
|
});
|
||||||
|
const labelStyle = { display:'flex', flexDirection:'column', gap:4, fontSize:13, fontWeight:600, color:'#475569' };
|
||||||
|
const inputStyle = { padding:'8px 10px', border:'1px solid #cbd5e1', borderRadius:6, fontSize:13, outline:'none', marginTop:2 };
|
||||||
|
```
|
||||||
122
.claude/skills/content-db-engineer/SKILL.md
Normal file
122
.claude/skills/content-db-engineer/SKILL.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
name: content-db-engineer
|
||||||
|
description: "지오정보기술 홈페이지(zioinfo-web) 정적 콘텐츠를 DB로 전환하는 구현 스킬. FAQ, 파트너사, 레퍼런스, CEO인사말, 조직도, KPI통계, 솔루션 소개 등 하드코딩 데이터를 Spring Boot JPA Entity + React API 훅으로 전환한다. 다음 상황에서 반드시 사용: (1) '홈페이지 XXX를 DB로 관리', 'FAQ DB화', '파트너사 관리자 추가' 요청; (2) 신규 Entity/Repository/Controller 구현; (3) 프론트 하드코딩 → API 연동 전환; (4) DataInitializer 초기 데이터 시딩; (5) 다시 실행, 업데이트, 수정, 보완 요청."
|
||||||
|
---
|
||||||
|
|
||||||
|
# 홈페이지 콘텐츠 DB 전환 스킬
|
||||||
|
|
||||||
|
## 기술 스택
|
||||||
|
|
||||||
|
| 레이어 | 기술 |
|
||||||
|
|--------|------|
|
||||||
|
| Backend | Spring Boot 3.2.5 + JPA (Hibernate 6) |
|
||||||
|
| DB | H2 (dev) / 서버 내장 |
|
||||||
|
| Frontend | React 18 + Vite |
|
||||||
|
| 인증 | JWT Bearer (관리자) / 없음 (공개 API) |
|
||||||
|
|
||||||
|
## 표준 구현 순서
|
||||||
|
|
||||||
|
```
|
||||||
|
1. JPA Entity → model/ 디렉토리
|
||||||
|
2. JpaRepository → repository/ 디렉토리
|
||||||
|
3. ApiController → GET /api/{resource} (공개)
|
||||||
|
4. AdminController → CRUD /api/admin/{resource} (JWT 필요)
|
||||||
|
5. DataInitializer → initXxx() 메서드 추가
|
||||||
|
6. React 훅 → useXxx() in Company.jsx 또는 해당 페이지
|
||||||
|
7. 컴포넌트 → API 데이터 사용, 정적 배열 제거
|
||||||
|
```
|
||||||
|
|
||||||
|
## 파일 위치 규칙
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/src/main/java/kr/co/zioinfo/web/
|
||||||
|
├── model/ ← Entity (CompanyHistory.java 참조)
|
||||||
|
├── repository/ ← JpaRepository
|
||||||
|
├── controller/
|
||||||
|
│ ├── ApiController.java ← 공개 GET 추가
|
||||||
|
│ └── AdminController.java ← CRUD 추가
|
||||||
|
└── config/
|
||||||
|
└── DataInitializer.java ← initXxx() 추가
|
||||||
|
|
||||||
|
frontend/src/pages/
|
||||||
|
├── {Page}.jsx ← useXxx() 훅 + API 데이터 사용
|
||||||
|
└── admin/
|
||||||
|
└── Admin{Name}.jsx ← 관리자 CRUD 페이지
|
||||||
|
```
|
||||||
|
|
||||||
|
## 우선순위별 DB화 항목
|
||||||
|
|
||||||
|
### HIGH — 즉시 구현
|
||||||
|
|
||||||
|
| 항목 | 파일 | 엔티티 | 공개 API |
|
||||||
|
|------|------|--------|---------|
|
||||||
|
| 구축 레퍼런스 | Business.jsx | `Reference` (tb_reference) | GET /api/references |
|
||||||
|
| FAQ | Support.jsx | `Faq` (tb_faq) | GET /api/faqs |
|
||||||
|
| 파트너사 | Business.jsx | `Partner` (tb_partner) | GET /api/partners |
|
||||||
|
| KPI 통계 | Home.jsx | `KpiStat` (tb_kpi_stat) | GET /api/stats |
|
||||||
|
|
||||||
|
### MEDIUM — 단계적 구현
|
||||||
|
|
||||||
|
| 항목 | 파일 | 엔티티 | 공개 API |
|
||||||
|
|------|------|--------|---------|
|
||||||
|
| CEO 인사말 | Company.jsx | `CeoGreeting` (tb_ceo_greeting) | GET /api/ceo-greeting |
|
||||||
|
| 핵심 가치 | Company.jsx | `CoreValue` (tb_core_value) | GET /api/core-values |
|
||||||
|
| 조직도 | Company.jsx | `OrgDept` (tb_org_dept) | GET /api/org-depts |
|
||||||
|
| 솔루션 설명 | SolutionPage.jsx | `SolutionFeature` (tb_solution_feature) | GET /api/solutions/{type}/features |
|
||||||
|
|
||||||
|
## Entity 공통 필드
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
private boolean visible = true;
|
||||||
|
private int sortOrder = 0;
|
||||||
|
@CreatedDate private LocalDateTime createdAt;
|
||||||
|
@LastModifiedDate private LocalDateTime updatedAt;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 프론트엔드 훅 패턴
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function useXxx(FALLBACK = []) {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/xxx')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(d => setData(d.length > 0 ? d : FALLBACK))
|
||||||
|
.catch(() => setData(FALLBACK))
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}, []);
|
||||||
|
return { data, loading };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## AdminController 패턴
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 목록
|
||||||
|
@GetMapping("/admin/{resource}")
|
||||||
|
public List<Entity> list() { return repo.findAllByOrderBySortOrderAsc(); }
|
||||||
|
|
||||||
|
// 생성
|
||||||
|
@PostMapping("/admin/{resource}")
|
||||||
|
public Entity create(@RequestBody Entity body) {
|
||||||
|
body.setId(null); return repo.save(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 수정
|
||||||
|
@PutMapping("/admin/{resource}/{id}")
|
||||||
|
public ResponseEntity<Entity> update(@PathVariable Long id, @RequestBody Entity body) {
|
||||||
|
return repo.findById(id).map(e -> {
|
||||||
|
// 필드 복사
|
||||||
|
return ResponseEntity.ok(repo.save(e));
|
||||||
|
}).orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 삭제
|
||||||
|
@DeleteMapping("/admin/{resource}/{id}")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long id) {
|
||||||
|
repo.deleteById(id); return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
|
```
|
||||||
146
.claude/skills/homepage-cms-orchestrator/SKILL.md
Normal file
146
.claude/skills/homepage-cms-orchestrator/SKILL.md
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
---
|
||||||
|
name: homepage-cms-orchestrator
|
||||||
|
description: "지오정보기술 홈페이지(zioinfo-web) 콘텐츠 DB 관리 오케스트레이터. 하드코딩된 FAQ·레퍼런스·파트너사·KPI통계·CEO인사말·조직도·핵심가치·솔루션 설명을 DB로 전환하고 관리자 UI를 구현한다. 다음 상황에서 반드시 사용: (1) '홈페이지 XXX를 DB로', '관리자에서 관리 가능하게', 'FAQ DB화', '레퍼런스 CRUD 추가' 요청; (2) 신규 콘텐츠 항목 DB 전환; (3) 관리자 페이지 추가; (4) 기존 구현 수정·보완; (5) '다시 실행', '업데이트', '수정', '보완' 요청. 현재 DB 관리 중: 뉴스, 채용공고, 회사연혁, 문의, 회원."
|
||||||
|
---
|
||||||
|
|
||||||
|
# 홈페이지 CMS 오케스트레이터
|
||||||
|
|
||||||
|
**실행 모드:** 파이프라인 (서브 에이전트)
|
||||||
|
`content-analyst` → `content-db-engineer` → `admin-ui-builder` 순차 실행
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 0: 컨텍스트 확인
|
||||||
|
|
||||||
|
요청 분류:
|
||||||
|
- **신규 DB 전환**: "XXX를 DB로 관리해줘" → Phase 1-3 전체 실행
|
||||||
|
- **관리자 UI만**: "관리자 페이지 추가해줘" → Phase 3만
|
||||||
|
- **기존 수정**: "XXX 수정해줘" → 해당 Phase만
|
||||||
|
|
||||||
|
현재 DB 관리 중인 항목 (건너뜀):
|
||||||
|
- 뉴스/공지 (`/api/admin/news`)
|
||||||
|
- 채용공고 (`/api/admin/recruit`)
|
||||||
|
- 회사연혁 (`/api/admin/history`)
|
||||||
|
- 문의 (`/api/admin/inquiries`)
|
||||||
|
- 회원 (`/api/admin/members`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: 분석 (content-analyst)
|
||||||
|
|
||||||
|
대상 항목 파악:
|
||||||
|
```
|
||||||
|
frontend/src/pages/{Page}.jsx 읽기
|
||||||
|
→ 하드코딩 배열/객체 식별
|
||||||
|
→ DB화 우선순위 산정
|
||||||
|
→ JPA 엔티티 설계안 작성
|
||||||
|
```
|
||||||
|
|
||||||
|
**HIGH 우선순위 구현 목록:**
|
||||||
|
|
||||||
|
| 항목 | 파일 | 엔티티명 | 테이블명 | API |
|
||||||
|
|------|------|---------|---------|-----|
|
||||||
|
| 구축 레퍼런스 | Business.jsx | `Reference` | tb_reference | /api/references |
|
||||||
|
| FAQ | Support.jsx | `Faq` | tb_faq | /api/faqs |
|
||||||
|
| 파트너사 | Business.jsx | `Partner` | tb_partner | /api/partners |
|
||||||
|
| KPI 통계 | Home.jsx | `KpiStat` | tb_kpi_stat | /api/stats |
|
||||||
|
|
||||||
|
**MEDIUM 우선순위:**
|
||||||
|
|
||||||
|
| 항목 | 파일 | 엔티티명 | 테이블명 | API |
|
||||||
|
|------|------|---------|---------|-----|
|
||||||
|
| CEO 인사말 | Company.jsx | `CeoGreeting` | tb_ceo_greeting | /api/ceo-greeting |
|
||||||
|
| 핵심 가치 | Company.jsx | `CoreValue` | tb_core_value | /api/core-values |
|
||||||
|
| 조직도 부서 | Company.jsx | `OrgDept` | tb_org_dept | /api/org-depts |
|
||||||
|
| 솔루션 기능 | SolutionPage.jsx | `SolutionFeature` | tb_solution_feature | /api/solutions/{type}/features |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: 구현 (content-db-engineer)
|
||||||
|
|
||||||
|
`content-db-engineer` 스킬 참조하여:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Entity 파일 생성
|
||||||
|
2. Repository 인터페이스 생성
|
||||||
|
3. ApiController에 GET 엔드포인트 추가
|
||||||
|
4. AdminController에 CRUD 추가
|
||||||
|
5. DataInitializer에 initXxx() 추가 (기존 하드코딩 데이터 시딩)
|
||||||
|
6. 프론트 페이지에 useXxx() 훅 추가, 정적 배열 제거
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: 관리자 UI (admin-ui-builder)
|
||||||
|
|
||||||
|
`admin-ui-builder` 스킬 참조하여:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. AdminXxx.jsx 생성 (AdminHistory.jsx 패턴)
|
||||||
|
2. AdminLayout.jsx NAV 배열에 메뉴 추가
|
||||||
|
3. App.jsx lazy import + Route 추가
|
||||||
|
4. 빌드 검증 (vite build)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: 배포
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 로컬 빌드 검증
|
||||||
|
cd workspace/zioinfo-web/frontend
|
||||||
|
node_modules/.bin/vite.cmd build --outDir C:\Temp\zioinfo-build
|
||||||
|
|
||||||
|
# 2. 서버 배포 (deploy_history.py 패턴)
|
||||||
|
python C:\GUARDiA\deploy_history.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 관리자 URL 목록
|
||||||
|
|
||||||
|
| 항목 | 관리자 URL |
|
||||||
|
|------|----------|
|
||||||
|
| 뉴스/공지 (기존) | /admin/news |
|
||||||
|
| 채용공고 (기존) | /admin/recruit |
|
||||||
|
| 회사연혁 (기존) | /admin/history |
|
||||||
|
| 문의 (기존) | /admin/inquiries |
|
||||||
|
| 레퍼런스 (신규) | /admin/references |
|
||||||
|
| FAQ (신규) | /admin/faqs |
|
||||||
|
| 파트너사 (신규) | /admin/partners |
|
||||||
|
| KPI 통계 (신규) | /admin/stats |
|
||||||
|
| CEO 인사말 (신규) | /admin/ceo-greeting |
|
||||||
|
| 핵심 가치 (신규) | /admin/core-values |
|
||||||
|
| 조직도 (신규) | /admin/org |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 테스트 시나리오
|
||||||
|
|
||||||
|
**정상 흐름:**
|
||||||
|
1. `GET /api/faqs` → FAQ 목록 JSON 반환
|
||||||
|
2. 관리자 로그인 → `/admin/faqs` 페이지 접근
|
||||||
|
3. FAQ 추가 모달 → 저장 → 목록 갱신
|
||||||
|
4. 홈페이지 `/support/*` → API에서 FAQ 동적 로드
|
||||||
|
|
||||||
|
**에러 흐름:**
|
||||||
|
1. API 실패 → 프론트 폴백(FALLBACK 배열) 표시
|
||||||
|
2. 인증 없이 POST → 401 반환
|
||||||
|
3. 존재하지 않는 ID DELETE → 404 반환
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 테스트 시나리오 (should-trigger)
|
||||||
|
|
||||||
|
- "FAQ를 DB로 관리하고 싶어"
|
||||||
|
- "레퍼런스 관리자에서 추가/삭제 가능하게"
|
||||||
|
- "파트너사 목록 DB화해줘"
|
||||||
|
- "CEO 인사말 수정할 수 있게 해줘"
|
||||||
|
- "홈페이지 통계 수치 관리자에서 바꾸고 싶어"
|
||||||
|
|
||||||
|
## 테스트 시나리오 (should-NOT-trigger)
|
||||||
|
|
||||||
|
- "뉴스 작성해줘" → `/admin/news` (기존 구현)
|
||||||
|
- "채용공고 수정" → `/admin/recruit` (기존 구현)
|
||||||
|
- "홈페이지 디자인 수정" → 직접 CSS 편집
|
||||||
|
- "ITSM에 새 기능 추가" → guardia-orchestrator
|
||||||
45
CLAUDE.md
Normal file
45
CLAUDE.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 지오정보기술 홈페이지 (zioinfo-web)
|
||||||
|
|
||||||
|
> Spring Boot 3.2.5 + React 18 + Vite | 서버: zioinfo.co.kr:8082
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 기술 스택
|
||||||
|
|
||||||
|
| 레이어 | 기술 |
|
||||||
|
|--------|------|
|
||||||
|
| Backend | Spring Boot 3.2.5 (Java 17), JPA, H2 |
|
||||||
|
| Frontend | React 18 + Vite, React Router DOM |
|
||||||
|
| 인증 | JWT (관리자) / 자체 JWT (회원) |
|
||||||
|
| 서버 | 101.79.17.164, Spring Boot 포트 8082 |
|
||||||
|
| 빌드 | `mvn clean package -DskipTests` → jar → `/opt/zioinfo/app/app.jar` |
|
||||||
|
|
||||||
|
## 배포 파이프라인
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 프론트 빌드: node_modules\.bin\vite.cmd build --outDir C:\Temp\zioinfo-build
|
||||||
|
2. 백엔드 배포: python C:\GUARDiA\deploy_history.py (패턴 참조)
|
||||||
|
3. 서버 재시작: systemctl restart zioinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
## DB 관리 항목 현황
|
||||||
|
|
||||||
|
| 항목 | 엔티티 | 공개 API | 관리자 UI |
|
||||||
|
|------|--------|---------|---------|
|
||||||
|
| 뉴스/공지 | News | GET /api/news | /admin/news |
|
||||||
|
| 채용공고 | Recruit | GET /api/recruit | /admin/recruit |
|
||||||
|
| 회사 연혁 | CompanyHistory | GET /api/history | /admin/history |
|
||||||
|
| 문의 | Inquiry | POST /api/inquiry | /admin/inquiries |
|
||||||
|
| 회원 | Member | - | /admin/members |
|
||||||
|
|
||||||
|
## 하네스: 홈페이지 CMS
|
||||||
|
|
||||||
|
**목표:** 홈페이지 정적 텍스트(FAQ·레퍼런스·파트너사·CEO인사말·조직도 등)를 DB로 전환하고 관리자에서 CRUD 가능하게 유지
|
||||||
|
|
||||||
|
**트리거:** 홈페이지 콘텐츠를 DB로 관리, 관리자 페이지 추가, FAQ·레퍼런스·파트너사 등 새 항목 DB화 요청 시 `homepage-cms-orchestrator` 스킬을 사용하라.
|
||||||
|
|
||||||
|
**변경 이력:**
|
||||||
|
| 날짜 | 변경 내용 | 대상 | 사유 |
|
||||||
|
|------|----------|------|------|
|
||||||
|
| 2026-05-31 | 초기 하네스 구성 | 전체 | 홈페이지 CMS 체계화 |
|
||||||
|
| 2026-05-31 | 회사 연혁 DB 전환 완료 | CompanyHistory + AdminHistory | 첫 번째 DB화 사례 |
|
||||||
Loading…
Reference in New Issue
Block a user