| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- electron
- contextBridge
- 마이그레이션
- 아키텍처
- python
- 온디바이스AI
- Android
- REST API
- php
- 메일자동화
- github actions
- 상태관리
- 도메인설계
- next.js
- Kotlin
- 소셜로그인
- 프론트엔드
- 크롤링
- 백엔드
- FastAPI
- 인증
- sqlite
- JWT
- playwright
- 보안
- 배포
- React
- Vite
- javascript
- typescript
- Today
- Total
HM소프트
TipTap 에디터·인증·E2E 테스트 구현 — 연구기관 사이트 (3) 본문
TipTap 헤드리스 에디터의 SSR 하이드레이션 불일치를 immediatelyRender false로 피하고, NextAuth 세션 전략을 JWT로 잡아 엣지 미들웨어가 DB 없이 역할을 판단하게 한다. 인증 설정을 엣지용·DB용으로 분리, 미들웨어와 API 가드 이중 방어, 파일 업로드 경로 순회 차단, 빌드 서버를 띄운 Playwright E2E까지 기록한다.
TipTap 에디터·인증·E2E 테스트 구현을 정리한다.

3편: 편집기·인증·테스트
1편 콘텐츠·검색, 2편 i18n·SEO·접근성·성능에 이어 시리즈 마지막이다. 관리자가 콘텐츠를 쓰는 리치 텍스트 에디터(TipTap), 사용자 인증과 MyPage, 그리고 전체를 검증한 E2E 테스트다.
콘텐츠 편집기 — TipTap
관리자가 게시판·연구성과 같은 콘텐츠를 작성하려면 리치 텍스트 에디터가 필요하다. 그냥 textarea로는 서식·이미지·링크를 못 다룬다. TipTap(ProseMirror 기반의 헤드리스 에디터)을 도입했다.
TipTap을 고른 이유:
- 헤드리스: UI를 우리가 원하는 대로 입힐 수 있다(기관 사이트 디자인에 맞춤).
- 확장 가능: 필요한 기능(서식, 링크, 이미지 등)만 익스텐션으로 켠다.
- 구조화된 데이터: 내용을 JSON 문서로 다뤄, 저장·렌더가 일관된다.
const editor = useEditor({
extensions: [StarterKit, Link, Image],
content: initialContent,
onUpdate: ({ editor }) => setDoc(editor.getJSON()), // 구조화 문서로 저장
});
관리자 페이지를 와이어프레임부터 잡았는데(초기 15페이지 → 17페이지로 확장), 그 관리자 화면들에서 TipTap으로 콘텐츠를 편집한다.
인증과 MyPage
사용자 인증 시스템을 개선하고, MyPage(내 정보·활동)를 만들었다. 인증은 사이트의 보호된 기능(MyPage, 관리자)과 공개 기능(콘텐츠 열람)을 가르는 경계다. Phase를 나눠 인증을 단계적으로 강화하며 MyPage, i18n(2편), 테스트를 함께 반영했다.
보안·코드 위생
중간중간 보안과 코드 품질도 챙겼다.
- 보안 오버라이드 / lint 이슈 정리: 의존성 보안 경고와 린트 문제를 해결.
- 업로드 경로 정리 + 미들웨어를 프록시로 이전: 파일 업로드 경로를 정비하고, 미들웨어를 프록시 방식으로 옮겨 구조를 정리.
- 관리자 API 파일 UTF-8 재작성: 인코딩이 어긋난 파일들을 UTF-8로 통일(다국어 사이트라 인코딩이 특히 중요).
E2E 테스트 — Playwright
마지막으로 Playwright E2E 테스트로 전체를 검증했다. 처음엔 스모크 테스트(핵심 동선이 도는지)부터 시작해, 점차 확장했다.
- 스모크: 주요 페이지가 뜨는지, 서버가 정상인지
- 확장: 연구역량, 검색(1편), 뉴스, 다국어(2편) 같은 핵심 기능별 시나리오
test('통합 검색이 동작한다', async ({ page }) => {
await page.goto('/');
await page.getByRole('searchbox').fill('테스트');
await page.keyboard.press('Enter');
await expect(page.getByRole('tab')).toHaveCount(3); // 카테고리 탭(게시판/장비/연구성과)
});
test('언어 전환이 동작한다', async ({ page }) => {
await page.goto('/ko');
await page.getByRole('link', { name: 'EN' }).click();
await expect(page).toHaveURL(/\/en/);
});
기능을 추가할 때마다 E2E 시나리오를 같이 늘리니, 다국어·검색·인증처럼 서로 얽힌 기능들이 "한쪽을 고치면 다른 쪽이 깨지는" 회귀를 막을 수 있었다. (Playwright 서버 설정도 초기에 한 번 잡아두니 이후가 수월했다.)
정리하며
- TipTap(헤드리스)으로 디자인 맞춤 + 구조화된 콘텐츠 편집.
- 인증·MyPage로 보호/공개 경계를 명확히.
- 인코딩·업로드 경로·미들웨어 같은 위생 작업이 다국어 사이트 안정성에 기여.
- Playwright E2E를 기능과 함께 키워 회귀를 차단.
시리즈를 마치며
세 편에 걸쳐 연구기관 웹사이트를 정리했다.
- 1편: 콘텐츠 모델 + pg_trgm 통합 검색 + PostgreSQL 마이그레이션
- 2편: i18n·SEO·접근성·성능 — "보이지 않는 완성도"
- 3편: TipTap 편집기·인증·E2E 테스트
기관 사이트는 화려한 기능보다 다국어·검색·접근성·SEO·테스트 같은 기반이 품질을 좌우한다는 걸 다시 확인한 프로젝트였다.
'외주 개발일지' 카테고리의 다른 글
| 네이버·카카오 소셜 로그인 구현과 bcrypt 함정 — 교육 플랫폼 (2) (0) | 2026.06.13 |
|---|---|
| 상품·카테고리 도메인 설계와 복합 필터 구현 — 이커머스 백엔드 (1) (0) | 2026.06.13 |
| 웹 국제화(i18n)·SEO·접근성·성능 최적화 — 연구기관 사이트 (2) (0) | 2026.06.13 |
| pg_trgm 통합 검색과 콘텐츠 모델 설계 — PostgreSQL (1) (0) | 2026.06.13 |
| Room 마이그레이션과 단위 테스트 98개 — 안드로이드 (3) (0) | 2026.06.12 |