CTRL_F Frontend 아키텍처 문서
최종 산출물 - 시스템 아키텍처 명세서
1. 전체 시스템 아키텍처
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Web Browser (SPA) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ CTRL_F Frontend Application │ │ │
│ │ │ React 19.2 + TypeScript 5.9 │ │ │
│ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
│
│ HTTPS (Port 443)
▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ GATEWAY LAYER │
│ ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Nginx (Reverse Proxy) │ │
│ │ - Static File Serving │ │
│ │ - SPA Routing (try_files) │ │
│ │ - API Proxy to Backend Services │ │
│ └───────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ BACKEND SERVICES LAYER │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Education Service │ │Infrastructure Service│ │ Chat Service │ │
│ │ (Port 9002) │ │ (Port 9003) │ │ (Port 9005) │ │
│ │ │ │ │ │ │ │
│ │ - 교육 콘텐츠 관리 │ │ - 파일 스토리지 │ │ - AI 챗봇 API │ │
│ │ - 영상 진행률 추적 │ │ - S3 Presigned URL │ │ - 세션/메시지 관리 │ │
│ │ - 퀴즈 관리 │ │ - RAG 문서 관리 │ │ - FAQ 서비스 │ │
│ │ - 수강 현황 │ │ - 조직도 정보 │ │ - 피드백 수집 │ │
│ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ AUTHENTICATION LAYER │
│ ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Keycloak (Port 8090) │ │
│ │ - OAuth2 / OpenID Connect │ │
│ │ - Realm: ctrlf │ │
│ │ - Client ID: web-app │ │
│ │ - Role-Based Access Control │ │
│ └───────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
2. 프론트엔드 애플리케이션 아키텍처
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ CTRL_F Frontend Application │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│ │ ENTRY POINT │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ index.html │───▶│ main.tsx │───▶│ App.tsx │ │ │
│ │ └─────────────┘ └─────────────┘ └──────┬──────┘ │ │
│ │ │ │ │
│ │ React Router DOM │ │
│ │ │ │ │
│ └───────────────────────────────────────────────┼──────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────────────────────────┼──────────────────────────────────┐ │
│ │ LAYOUT LAYER │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ Layout.tsx │ │ │
│ │ │ ┌──────────────┐ ┌──────────────────────────────┐ ┌──────────────────┐ │ │ │
│ │ │ │ Topbar │ │ Main Content │ │ FloatingChatbot │ │ │ │
│ │ │ │ (Header) │ │ (Page Components) │ │ Root │ │ │ │
│ │ │ └──────────────┘ └──────────────────────────────┘ └──────────────────┘ │ │ │
│ │ │ ┌──────────────┐ │ │ │
│ │ │ │ Sidebar │ │ │ │
│ │ │ │ (Navigation) │ │ │ │
│ │ │ └──────────────┘ │ │ │
│ │ └────────────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────────────┐ │
│ │ PAGE LAYER (8 Pages) │ │
│ │ │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Dashboard │ │ MyPage │ │ Approval │ │ Message │ │ │
│ │ │ Page │ │ │ │ Page │ │ Page │ │ │
│ │ │ (홈/대시보드) │ │ (마이페이지) │ │ (전자결재) │ │ (메신저) │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
│ │ │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Event │ │ Notice │ │ OrgChart │ │ Education │ │ │
│ │ │ Page │ │ Page │ │ Page │ │ Page │ │ │
│ │ │ (행사일정) │ │ (공지사항) │ │ (조직도) │ │ (교육) │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
3. 플로팅 챗봇 패널 아키텍처
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ FloatingChatbotRoot (패널 관리자) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Panel State Management │ │
│ │ (useReducer + Z-index 관리) │ │
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┬───────────────┼───────────────┬───────────────┐ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ChatbotApp │ │ EduPanel │ │ QuizPanel │ │ Admin │ │ Reviewer │ │
│ │ │ │ │ │ │ │ Dashboard │ │ Desk │ │
│ │ ┌───────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌───────┐ │ │ ┌───────┐ │ │
│ │ │Sidebar│ │ │ │Education│ │ │ │ Quiz │ │ │ │ 8 Tabs│ │ │ │Review │ │ │
│ │ │ │ │ │ │ Video │ │ │ │Questions│ │ │ │ │ │ │ │ Queue │ │ │
│ │ │Chat │ │ │ │ Player │ │ │ │ │ │ │ │Chatbot│ │ │ │ │ │ │
│ │ │Window │ │ │ │ │ │ │ │ Timer │ │ │ │Edu │ │ │ │Review │ │ │
│ │ │ │ │ │ │Progress │ │ │ │ │ │ │ │Quiz │ │ │ │Detail │ │ │
│ │ └───────┘ │ │ │ Tracker │ │ │ │ Score │ │ │ │Metrics│ │ │ │ │ │ │
│ │ │ │ └─────────┘ │ │ └─────────┘ │ │ │Logs │ │ │ │Action │ │ │
│ │ 드래그/ │ │ │ │ │ │ │Account│ │ │ │ Bar │ │ │
│ │ 리사이즈 │ │ 드래그/ │ │ 드래그/ │ │ │Policy │ │ │ └───────┘ │ │
│ │ │ │ 리사이즈 │ │ 리사이즈 │ │ │FAQ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │ └───────┘ │ │ 드래그/ │ │
│ │ │ │ 리사이즈 │ │
│ │ 드래그/ │ │ │ │
│ │ 리사이즈 │ └─────────────┘ │
│ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Creator Studio View │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ - 교육 콘텐츠 생성 │ │ │
│ │ │ - 영상 업로드 │ │ │
│ │ │ - 스크립트 편집 (Scene Editor) │ │ │
│ │ │ - 검수 요청 │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
4. 컴포넌트 계층 구조
src/
├── main.tsx # 애플리케이션 진입점
├── App.tsx # 라우터 설정
├── keycloak.ts # Keycloak 인스턴스
├── index.css # 전역 스타일
│
├── auth/
│ └── roles.ts # 역할 정의 및 권한 로직
│ ├── UserRole (4가지)
│ │ ├── SYSTEM_ADMIN
│ │ ├── CONTENTS_REVIEWER
│ │ ├── VIDEO_CREATOR
│ │ └── EMPLOYEE
│ ├── Capability (3가지)
│ │ ├── OPEN_ADMIN_DASHBOARD
│ │ ├── OPEN_REVIEWER_DESK
│ │ └── OPEN_CREATOR_STUDIO
│ └── Functions
│ ├── normalizeRoles()
│ ├── pickPrimaryRole()
│ └── can()
│
├── types/
│ └── chat.ts # 채팅 관련 타입 정의
│ ├── ChatRole
│ ├── ChatDomain (6가지 UI)
│ ├── ChatServiceDomain (4가지 서버)
│ ├── ChatMessage
│ ├── ChatSession
│ ├── ChatAction
│ └── FaqItem
│
├── utils/
│ └── chat.ts # 유틸리티 함수
│ ├── buildSessionTitleFromMessage()
│ ├── buildLastMessagePreview()
│ └── computePanelPosition()
│
├── pages/ # 페이지 컴포넌트 (8개)
│ ├── Dashboard.tsx
│ ├── MyPage.tsx
│ ├── ApprovalPage.tsx
│ ├── MessagePage.tsx
│ ├── EventPage.tsx
│ ├── NoticePage.tsx
│ ├── OrgChartPage.tsx
│ └── EducationPage.tsx
│
├── components/
│ ├── Layout.tsx # 공통 레이아웃
│ │
│ ├── common/
│ │ └── api/
│ │ └── authHttp.ts # HTTP 클라이언트 (인증 포함)
│ │
│ ├── chatbot/ # 챗봇 관련 (40+ 파일)
│ │ ├── [UI Components]
│ │ │ ├── FloatingChatbotRoot.tsx
│ │ │ ├── FloatingDock.tsx
│ │ │ ├── ChatbotApp.tsx
│ │ │ ├── ChatWindow.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ ├── EduPanel.tsx
│ │ │ ├── QuizPanel.tsx
│ │ │ ├── ReviewerDeskView.tsx
│ │ │ ├── ReviewerQueue.tsx
│ │ │ ├── ReviewerDetail.tsx
│ │ │ ├── ReviewerActionBar.tsx
│ │ │ ├── ReviewerOverlays.tsx
│ │ │ ├── CreatorStudioView.tsx
│ │ │ ├── CreatorScriptSceneEditor.tsx
│ │ │ ├── CreatorTrainingSelect.tsx
│ │ │ └── ProjectFilesModal.tsx
│ │ │
│ │ ├── [API Layer]
│ │ │ ├── chatApi.ts # 채팅 API (1700+ 줄)
│ │ │ ├── educationServiceApi.ts
│ │ │ ├── creatorApi.ts
│ │ │ ├── reviewerApi.ts
│ │ │ ├── reviewerApiHttp.ts
│ │ │ ├── ragDocumentsApi.ts
│ │ │ ├── infraPresignApi.ts
│ │ │ └── s3Transfer.ts
│ │ │
│ │ ├── [State Stores]
│ │ │ ├── policyStore.ts # 정책 문서 상태
│ │ │ └── reviewFlowStore.ts # 검수/게시 상태
│ │ │
│ │ ├── [Custom Hooks]
│ │ │ ├── useCreatorStudioController.ts
│ │ │ ├── useReviewerDeskController.ts
│ │ │ └── useStableEvent.ts
│ │ │
│ │ ├── [Types]
│ │ │ ├── creatorStudioTypes.ts
│ │ │ ├── reviewerApiTypes.ts
│ │ │ ├── reviewerDeskTypes.ts
│ │ │ ├── policyTypes.ts
│ │ │ └── adminRagGapTypes.ts
│ │ │
│ │ ├── [Mocks & Data]
│ │ │ ├── quizData.ts
│ │ │ ├── policyMocks.ts
│ │ │ └── adminRagGapMocks.ts
│ │ │
│ │ └── [Utils]
│ │ ├── creatorStudioCatalog.ts
│ │ ├── creatorStudioUtils.ts
│ │ └── reviewerApiErrors.ts
│ │
│ └── dashboard/ # 관리자 대시보드 (25+ 파일)
│ ├── AdminDashboardView.tsx # 메인 대시보드
│ ├── AdminFilterBar.tsx
│ ├── AdminPolicyView.tsx
│ ├── AdminRagGapView.tsx
│ │
│ ├── api/ # 대시보드 전용 API
│ │ ├── chatApi.ts
│ │ ├── educationApi.ts
│ │ ├── quizApi.ts
│ │ ├── metricApi.ts
│ │ ├── logApi.ts
│ │ ├── userApi.ts
│ │ ├── faqApi.ts
│ │ ├── ragApi.ts
│ │ └── utils.ts
│ │
│ ├── components/
│ │ ├── KpiRow.tsx
│ │ ├── PiiReportCard.tsx
│ │ └── tabs/ # 8개 탭 컴포넌트
│ │ ├── AdminChatbotTab.tsx
│ │ ├── AdminEducationTab.tsx
│ │ ├── AdminQuizTab.tsx
│ │ ├── AdminMetricsTab.tsx
│ │ ├── AdminLogsTab.tsx
│ │ ├── AdminAccountsTab.tsx
│ │ ├── AdminPolicyTab.tsx
│ │ └── AdminFAQTab.tsx
│ │
│ └── types/
│ ├── index.ts
│ ├── response.ts
│ ├── adminDashboardTypes.ts
│ └── adminFilterTypes.ts
│
└── assets/ # 정적 리소스
└── [이미지, 아이콘 등]
5. 데이터 흐름 아키텍처
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ DATA FLOW │
└─────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ USER INTERACTION │
│ │
│ [사용자 입력] ─────────────────────────────────────────────────────────────────────────▶ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ REACT COMPONENTS │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ useState │ │ useReducer │ │ useRef │ │ │
│ │ │ (로컬 상태) │ │ (복잡한 상태) │ │ (DOM 참조) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ EXTERNAL STORES │ │
│ │ │ │
│ │ ┌────────────────────────────┐ ┌────────────────────────────┐ │ │
│ │ │ policyStore.ts │ │ reviewFlowStore.ts │ │ │
│ │ │ │ │ │ │ │
│ │ │ - Policy Document 관리 │ │ - Review Items 관리 │ │ │
│ │ │ - Version Control │ │ - Published Videos 관리 │ │ │
│ │ │ - 구독 패턴 (Observer) │ │ - 구독 패턴 (Observer) │ │ │
│ │ │ - useSyncExternalStore │ │ - useSyncExternalStore │ │ │
│ │ └────────────────────────────┘ └────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ API LAYER │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ authHttp.ts (HTTP Client) │ │ │
│ │ │ │ │ │
│ │ │ - Keycloak 토큰 자동 주입 │ │ │
│ │ │ - 요청 중복 제거 (Dedupe) │ │ │
│ │ │ - 401 에러 시 토큰 갱신 후 재시도 │ │ │
│ │ │ - 타임아웃 방어 │ │ │
│ │ └───────────────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌───────────────────────────────┼───────────────────────────────┐ │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ chatApi │ │educationApi │ │ reviewerApi │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ - 메시지 │ │ - 교육 목록 │ │ - 검수 목록 │ │ │
│ │ │ - 세션 │ │ - 영상 재생 │ │ - 승인/반려 │ │ │
│ │ │ - FAQ │ │ - 진행률 │ │ - 락 관리 │ │ │
│ │ │ - 피드백 │ │ - 퀴즈 │ │ │ │ │
│ │ │ - 스트리밍 │ │ │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ BACKEND SERVICES │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Chat Service │ │ Education Svc │ │ Infra Service │ │ │
│ │ │ (9005) │ │ (9002) │ │ (9003) │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────────────────────────┘
6. 인증 흐름 아키텍처
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ AUTHENTICATION FLOW │
└─────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ │ │ │ │
│ Browser │ │ Frontend │ │ Keycloak │
│ │ │ App │ │ Server │
│ │ │ │ │ │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ 1. 앱 접속 │ │
│ ─────────────────────────────▶│ │
│ │ │
│ │ 2. keycloak.init() │
│ │ (login-required) │
│ │──────────────────────────────▶│
│ │ │
│ 3. 로그인 페이지 리다이렉트 │ │
│◀──────────────────────────────│◀──────────────────────────────│
│ │ │
│ 4. 사용자 로그인 (ID/PW) │ │
│──────────────────────────────────────────────────────────────▶│
│ │ │
│ 5. Authorization Code │ │
│◀──────────────────────────────────────────────────────────────│
│ │ │
│ 6. Code → Token Exchange │ │
│ ─────────────────────────────▶│──────────────────────────────▶│
│ │ │
│ │ 7. Access Token + Refresh │
│ │◀──────────────────────────────│
│ │ │
│ │ 8. 토큰 저장 (메모리) │
│ │ - Access Token │
│ │ - Refresh Token │
│ │ - Token Parsed (roles 포함) │
│ │ │
│ 9. 앱 렌더링 완료 │ │
│◀──────────────────────────────│ │
│ │ │
│ │ │
│ [API 요청 시] │ │
│ │ │
│ 10. API 호출 │ │
│ ─────────────────────────────▶│ │
│ │ │
│ │ 11. updateToken(30) │
│ │ (만료 30초 전 자동 갱신) │
│ │──────────────────────────────▶│
│ │ │
│ │ 12. 새 Access Token │
│ │◀──────────────────────────────│
│ │ │
│ │ 13. Authorization Header │
│ │ Bearer {token} │
│ │─────────────────────▶ Backend │
│ │ │
│ │ │
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ TOKEN STRUCTURE │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ keycloak.tokenParsed = { │
│ sub: "user-uuid", │
│ name: "홍길동", │
│ email: "user@company.com", │
│ realm_access: { │
│ roles: ["SYSTEM_ADMIN", "EMPLOYEE", ...] │
│ }, │
│ resource_access: { │
│ "web-app": { │
│ roles: ["VIDEO_CREATOR", ...] │
│ } │
│ }, │
│ exp: 1234567890, │
│ iat: 1234567800 │
│ } │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────┘