| name |
description |
| content-db-engineer |
지오정보기술 홈페이지(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 공통 필드
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private boolean visible = true;
private int sortOrder = 0;
@CreatedDate private LocalDateTime createdAt;
@LastModifiedDate private LocalDateTime updatedAt;
프론트엔드 훅 패턴
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 패턴
// 목록
@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();
}