대한수중·핀수영협회
대한수중·핀수영협회 외주 개발
2025.11 – 2026.01
기존 홈페이지의 노후화된 UI/UX와 비효율적인 관리 시스템을 개선하기 위해 Next.js 기반으로 전면 재개발했습니다. 공식 협회 사이트로 현재 운영 중입니다.
팀 구성
주요 기능
- 협회 소개 · 종목 소개 · 대회정보 페이지
- 게시판 시스템 (공지사항, 갤러리, 대회일정 등 22개)
- 관리자 대시보드 (팝업 · 회원 · 소개 페이지 콘텐츠 관리)
담당 역할
- SEO & 메타데이터전체 페이지 SEO 구조 개선
- 콘텐츠/게시판 기능 및 공통 레이아웃 설계게시판 CRUD, 공통 컴포넌트 개발, GNB·라우팅 설계 구현
- 성능 최적화이미지·SVG 최적화, 폰트 최적화 및 렌더링 성능 개선
- 운영/배포 파이프라인GitHub Actions 기반 CD 파이프라인 구축 (rolling CD 포함)
주요 성과
운영형 게시판 공통화 설계
디자인 미확정·요구사항 변경이 잦은 환경에서 마감 기한은 타이트하여, 변경에 강한 구조 설계가 필수적인 상황이었습니다.
Compound Component 패턴으로 PostForm을 설계해 게시판마다 필요한 필드만 조합해 사용하도록 했습니다. Generic 기반 DataTable<T>로 다양한 도메인 데이터를 단일 컴포넌트로 렌더링하고, 도메인마다 컬럼 정의만 주입하는 구조로 분리했습니다. JSDoc 기반 인터페이스 문서화로 서브 컴포넌트 조합 방식과 props 계약을 명시해 팀 내 불필요한 구현 문의를 최소화했습니다.
신규 게시판 추가 시 서브 컴포넌트 조합과 컬럼 정의만으로 구현 가능. 22개 게시판 전반에 일관된 UX 유지, 운영 요구사항 변경에 빠르게 대응 가능한 구조를 확보했습니다.
Compound Component — 게시판마다 필드 조합만 교체
<PostForm.Root onSubmit={handleSubmit} isSubmitting={submitting}>
{isAdmin && <PostForm.PinField />}
{isAdmin && <PostForm.ShowField />}
<PostForm.TitleField placeholder={titlePlaceholder} />
<PostForm.ContentField />
<PostForm.AttachmentField />
<PostForm.Actions />
</PostForm.Root>Generic DataTable<T> — Column 정의만 주입, 테이블 로직 재사용
// Column<BranchItem>[] 정의만 작성하면 테이블 완성
const columns: Column<BranchItem>[] = [
{ key: "name", header: "지부명", accessor: (row) => row.name, width: "300px" },
{ key: "president", header: "회장", accessor: (row) => row.president, width: "100px" },
{ key: "phone", header: "전화", accessor: (row) => row.phone, width: "120px" },
{ key: "email", header: "메일", accessor: (row) => row.email, width: "180px" },
];
<DataTable columns={columns} data={data}
getRowId={(row) => String(row.id)}
onSelectionChange={setSelectedRows} />주요 보안 취약점(XSS·SSRF) 탐지 및 방어 구현
사용자 입력과 게시글을 다루는 구조에서 보안 취약점이 발생할 수 있다고 판단해 직접 점검했고, XSS · SSRF 취약점을 확인했습니다.
XSS는 isomorphic-dompurify를 도입해 렌더링 전 sanitizeHtml()로 악성 스크립트를 제거했습니다. SSRF는 Route Handler URL을 http/https로 제한하고 허용 API 호스트만 fetch하도록 검증 로직을 적용했습니다.
XSS · SSRF 각 공격 벡터의 발생 원리와 방어 패턴을 이해하고 운영 코드에 적용했습니다.
LCP 80% 단축 (3.0s → 0.6s) 폰트 최적화
이전
3.0s
이후
0.6s
운영 배포 후 Lighthouse 측정 결과 Performance 83점, LCP가 3초를 초과하는 이슈를 확인했습니다. Next.js 이미지 최적화로 이미지가 WebP로 서빙되고 있었음에도 LCP 요소로 잡혀 Font 파일 로딩이 병목임을 개발자 도구 Performance 탭으로 확인했습니다.
기존 Font 전체 파일(2MB)을 단일 로드하는 방식에서, 폰트를 서브셋 woff2 파일로 분할하고 Dynamic Subsetting 방식을 적용해 브라우저가 실제 사용되는 문자 범위의 청크만 요청하도록 변경했습니다.
LCP 점수 3.0초 → 0.6초 (약 80% 단축). 폰트 구조 개선을 통한 LCP 최적화 전략을 이해했습니다.