Narratix는 취준생들이 흩어진 경험을 모으고, 자기소개서를 효율적으로 작성/관리할 수 있도록 돕는 플랫폼입니다.
- 자소서 초안, 문항, 경험 메모가 여러 곳에 흩어져 재활용이 어렵다
- 지원 일정과 작성 진행도를 함께 관리하기 어렵다
- 첨삭 과정이 메시지/문서로 분산되어 피드백 반영이 비효율적이다
경험 아카이빙: 업로드한 자료를 구조화해 기업/문항 단위로 재활용작성 생산성: 문항 중심 편집 + 검색/필터로 빠른 작성 흐름 지원피드백 루프: 공유 기반 첨삭으로 수정 사이클 단축
-
[나의 채용공고] 공고 등록 또는 [자료 업로드] PDF 업로드로 자기소개서 생성
- 텍스트로 공고 정보와 문항 직접 작성
- PDF 업로드 시 AI가 자동 파싱 후 라이브러리에 저장
-
[라이브러리] 에서 자료 탐색 및 스크랩
- 기업별/문항별로 아카이빙된 자료 열람
- 재활용할 내용 스크랩
-
[자기소개서] 에서 문항별 초안 작성 / 수정
- 사이드바에서 스크랩하거나 아카이빙된 자료를 참고하며 작성
-
[자기소개서] 공유 링크 기반 실시간 첨삭 진행
-
[나의 채용공고] 채용 캘린더로 지원 일정 관리
- IA 문서: Narratix IA
작성자
첨삭자
홈 대시보드: 작성 통계, 시즌 지원 현황, 임박 일정 확인채용공고 관리: 캘린더 기반 공고 등록/수정/삭제자료 업로드: 자기소개서 파일 업로드 후 AI 라벨링 및 저장자기소개서 작성: 문항 단위 작성, 검색/필터 기반 문서 탐색친구 첨삭: 공유된 자기소개서 코멘트 작성 및 반영라이브러리: 기업별/문항별 아카이빙, 스크랩 기반 재활용인증: 로그인/회원가입 및 보호 라우팅
아키텍처 링크
.
├─ frontend/ # React + TypeScript + Vite
│ ├─ src/pages # 페이지 라우트 진입점
│ ├─ src/features # 도메인별 기능 모듈
│ ├─ src/shared # 공통 컴포넌트/API/훅/유틸
│ └─ src/workers # Web Worker 환경에 대한 워커 관리
└─ backend/ # Spring Boot
└─ src/main/java/com/jackpot/narratix/
├─ domain/ # 도메인별 비즈니스 로직
│ ├─ controller/ # REST API 엔드포인트, WebSocket 메시지 핸들러
│ ├─ service/ # 비즈니스 로직
│ ├─ repository/ # 데이터 접근
│ ├─ entity/ # JPA 엔티티
│ ├─ event/ # 도메인 이벤트 (WebSocket, Notification)
│ └─ exception/ # 도메인별 예외 및 에러 코드
│
└─ global/ # 공통 인프라 및 횡단 관심사
├─ auth/ # JWT 인증
├─ config/ # 설정
├─ interceptor/ # STOMP 채널 인터셉터
├─ websocket/ # WebSocket 인프라
├─ sse/ # SSE 구독 및 발송
└─ exception/ # 전역 예외 처리 핸들러 및 공통 에러 코드
| 이름 | 포지션 | 담당 도메인 |
|---|---|---|
| 강유진 | Frontend | 실시간 텍스트 에디터 / 협업 첨삭 UI |
| 박소민 | Frontend | 라이브러리(기업·문항) / 나의 채용공고(캘린더) / 자기소개서 작성 (랜딩 페이지 및 검색) |
| 윤종근 | Frontend | 실시간 첨삭, 실시간 알림, 자료 업로드 |
| 김승환 | Backend & Infra | WebSocket 실시간 첨삭, SSE 알림, 자기소개서, 첨삭 링크 관리 |
| 이정민 | Backend & Infra | 자료 업로드, 라이브러리, 검색 , aws 인프라 구축 |
- contentEditable 기반 커스텀 에디터 구현 (Enter·Delete·Undo·Redo 직접 구현 및 트러블슈팅)
- WebSocket 이벤트 수신 후 컴포넌트 상태 반영 설계 및 미업데이트 이슈 해결
- 첨삭 기능 프론트엔드 데이터 구조 설계
📄 관련 문서: 실시간 협업 텍스트 에디터: 동작 흐름 완전 분석 · 에디터 구현 · WebSocket 설계 · WebSocket 트러블슈팅 · 데이터 구조
- FSD(Feature-Sliced Design) Lite 아키텍처 설계: 프로젝트 확장성과 유지보수성을 위해 기존 Layered 구조를 features, shared, pages 계층으로 재설계 및 점진적 리팩토링 주도
- 라이브러리(기업·문항) 핵심 기능 구현: 중첩 라우팅(Nested Routing)을 활용한 상세 뷰 설계, 실시간 검색(useSearch) 및 문항 스크랩 배지 로직 개발
- 나의 채용공고 및 커스텀 캘린더 구축: 외부 라이브러리 없이 순수 Date 객체 기반의 캘린더 로직(
useCalendar)을 구현하고, 공고 CRUD(등록·수정·삭제) 기능 연동 - 사용자 경험(UX) 및 웹 접근성 고도화: 모달 포커스 트랩(Focus Trap), 키보드 조작 가능한 드롭다운, 토스트 알림 등 재사용 가능한 인터랙션 UI 설계
- 성능 최적화 및 안정성 확보: TanStack Query 기반 API 캡슐화, Tree-shaking을 고려한 아이콘 관리 체계 구축 및
React.memo를 통한 불필요한 리렌더링 방지
📄 관련 문서: [박소민] - 중첩 라우팅 환경에서의 상태 관리 전략 (Memory vs URL), [박소민] ‐ 커스텀 캘린더 구현기
- STOMP/SockJS 기반 실시간 자소서 첨삭 기능 구축: useStompClient 커스텀 훅을 설계하여 웹소켓 연결 생명주기를 안정적으로 관리, 첨삭 모드 활성화 여부에 따른 연결/해제 로직을 구현
- 웹소켓 이벤트 및 TanStack Query 연동 데이터 동기화: useSocketMessage 핸들러를 분리하여 이벤트(TEXT_UPDATE, REVIEW_CREATED 등) 수신 시 invalidateQueries로 실시간 UI를 갱신하고 서버로부터 TEXT_REPLACE_ALL 이벤트 수신 시 프론트엔드 캐시의 텍스트와 버전을 즉시 동기화하여 협업 중 발생할 수 있는 버전 꼬임 현상
- SSE(Server-Sent Events) 기반 실시간 알림 파이프라인 최적화: useSSE 커스텀 훅을 도입해 브라우저 포커싱 상태에 따른 연결 제어 및 다중 탭 환경에서의 연결 초과(400 에러) 방지 로직을 구현하고 수신된 알림 데이터를 TanStack Query 캐시 동기화하여 실시간 배지 및 리스트 갱신 처리
- 자료 업로드 기능: 자기소개서 PDF 자동 파싱 기능을 위해 PDF 파일 업로드 관련 로직과 사용자의 입력 검증 로직을 구현
- 인메모리 기반 토큰 관리 및 Silent Refresh 구현: 보안 강화를 위해 Access Token을 JS 변수(인메모리)에 저장하여 XSS 공격을 원천 차단하고 silentRefresh 로직을 구축하여 새로고침 시에도 사용자 세션이 끊기지 않도록 구현
📄 관련 문서:
- [윤종근] ‐ SSE 기반 실시간 알림의 연결이 자동 해제가 되는 문제 해결 이야기
- [윤종근] ‐ 웹소켓 연결에 관한 정보
- [윤종근] ‐ 인메모리 기반 액세스 토큰 관리 및 Silent Refresh 소개
- [윤종근] ‐ SSE 기반 실시간 알림의 연결이 자동 해제가 되는 문제 해결 이야기 (SSE 연결 이야기 1편)
- [윤종근] - SSE 기반 실시간 알림이 연속된 새로고침에서 재연결이 발생하는 문제점 (SSE 연결 이야기 2편)
- 비동기 이벤트 기반 아키텍처 구현: 자기소개서 PDF 업로드 및 AI 라벨링의 비동기 처리 과정에서 발생할 수 있는 상태 유실 문제를 해결하기 위해 비동기 이벤트 기반 아키텍처 구축
- WebSocket/STOMP 기반 실시간 자소서 첨삭 기능 구현: WebSocket과 STOMP를 사용해 작성자(Writer)와 첨삭자(Reviewer) 간 실시간 자소서 첨삭 기능 구현
- Operational Transformation 알고리즘을 사용한 중앙 집중 동시 편집 기능 구현: 자기소개서 작성자(Writer)와 첨삭자(Reviewer)가 자기소개서 동시 편집 시 충돌 없이 일관된 상태를 유지하도록 Operational Transformation 알고리즘을 도입하여 모든 사용자가 동일한 결과를 보도록 구현
- Write Back 패턴을 사용하여 실시간 저장 로직 최적화: 매 텍스트 변경마다 DB IO를 발생시키지 않고, Redis에 Delta(변경분)를 임시 저장하고, 임계값 도달 시 DB에 Delta를 Flush하는 Write Back 캐싱 전략 구현
- Redis 분산 락을 이용한 웹소켓 접속 유저 제한 정책 구현: 하나의 첨삭 링크에 Writer와 Reviewer 각 1명만 동시 접속이 가능하도록 Redis 분산 락 기반 제한 정책 구현, Lock의 TTL을 30초로 설정하여 비정상 종료 시에도 락이 자동 해제되도록 구현, Lock 갱신 로직에서 Pipeline과 Lua Script를 조합해 단일 네트워크 IO로 모든 세션의 Lock TTL을 10초마다 갱신하도록 구현
- SSE 기반 알림 발송 로직 구축: Server-Sent Events를 활용하여 서버에서 클라이언트로 단방향 실시간 알림을 전송하는 시스템 구현
📄 관련 문서:
- [김승환] - 비동기 이벤트 아키텍처 개선기
- [김승환] ‐ WebSocket vs. SSE
- [김승환] ‐ 실시간 첨삭 기능, 어떻게 구현할 것인가? (데이터 구조부터 OT 알고리즘까지)
- [김승환] ‐ 동시 편집(OT) 알고리즘 구현 중 만난 버전 충돌 개선기
- [김승환] ‐ 트랜잭션 경계 재설계와 낙관적 락을 통한 리뷰 생성 로직 개선
- [김승환] 웹소켓 다중 서버 환경에서 Redis 분산락과 Pipelining으로 단일 접속 제어하기
- [김승환] WebSocket과 달리, SSE에서는 onCompletion이 왜 바로 호출되지 않았을까?
- 자료 업로드 관련 기능 및 인프라 구축: AWS S3, Lambda, SQS를 조합한 비동기 아키텍처 설계 및 구축, (S3업로드 -> lambda 호출 -> pdf 추출 -> ai라벨링 -> SSE 실시간 알림) 로직 구현
- 라이브러리 & 스크랩 기능: 라이브러리, 문항 스크랩 기능의 비즈니스 로직을 구현
- 검색 기능: 자기소개서 및 문항 대상 검색 기능 구현 및 전문 검색을 도입한 최적화
- Auth 로직 구현: JWT 기반 로그인, 로그아웃 등 전반적인 사용자 인증 관련 로직을 구현
📄 관련 문서:
- [이정민] - pdf업로드 및 AI 라벨링 기능을 위한 이벤트 기반 비동기 파이프라인
- [이정민] - 스크랩 내 QnA 검색 최적화 (Full‐Text Search 도입)
- [이정민] ‐ 스크랩 검색 오류 해결 (불용어 필터링 설정, LazyInitializationException)
- [이정민] ‐ 업로드 완료 알림 중복과 누락 문제 해결하기 (feat. REQUIRES_NEW, CAS)
- [이정민] - AWS 인프라(Terraform) 및 Lambda 구현 코드
- [트러블슈팅] React + contentEditable 에디터의 네이티브 동작 제어
contentEditable의 예측 불가능한 동작을 제어하고, 직접 Undo/Redo 스택을 구현하며 문제를 해결한 과정입니다.
- [고민] TypeScript 제너릭을 활용한 타입 안전성 높은 재사용 탭 컴포넌트 구현
as타입 단언 없이도 타입 안정성을 보장하는 유연한 컴포넌트를 설계하며 겪은 고민을 담았습니다.
- [고민] 중첩 라우팅 환경에서의 상태 관리 전략 (Memory vs URL)
- 복잡한 UI 상태를 메모리(State)로 관리할지, URL로 관리할지에 대한 트레이드오프를 고려하여 최적의 방식을 선택했습니다.
- [고민] 비동기 이벤트 아키텍처 개선기
- [고민] - WebSocket vs. SSE
- [고민] ‐ 실시간 첨삭 기능, 어떻게 구현할 것인가? (데이터 구조부터 OT 알고리즘까지)
- [고민] 웹소켓 다중 서버 환경에서 Redis 분산락과 Pipelining으로 단일 접속 제어하기
- [정리] - pdf업로드 및 AI 라벨링 기능을 위한 비동기 파이프라인
- [최적화] - 스크랩 내 QnA 검색 최적화 (Full‐Text Search 도입)
- [최적화] ‐ 트랜잭션 경계 재설계와 낙관적 락을 통한 리뷰 생성 로직 개선
- [트러블 슈팅] ‐ 스크랩 검색 오류 해결 (불용어 필터링 설정, LazyInitializationException)
- [트러블 슈팅] ‐ 업로드 완료 알림 중복과 누락 문제 해결하기 (feat. REQUIRES_NEW, CAS)
- [트러블 슈팅] ‐ 동시 편집(OT) 알고리즘 구현 중 만난 버전 충돌 개선기
- [트러블 슈팅] WebSocket과 달리, SSE에서는 onCompletion이 왜 바로 호출되지 않았을까?
- Node.js 20+
pnpm9+- Java 17
cd frontend
pnpm install
pnpm dev환경 변수 (frontend/.env)
VITE_API_BASE_URL=<YOUR_API_BASE_URL>
VITE_SOCKET_URL=<YOUR_SOCKET_URL>
VITE_SERVICE_BASE_URL=<YOUR_SERVICE_BASE_URL>
VITE_DEV_BASE_URL=<YOUR_DEV_BASE_URL>








