프로젝트 개요
목록 | 내용 |
---|---|
프로젝트명 | LLearn - AI 기반 개인화 학습 플랫폼 |
개발기간 | 2025년 6월 - 2025년 8월 (2개월) |
역할 | 백엔드 및 AI Agent 개발 (개인 프로젝트) |
기여도 | 100% (단독 개발) |
개발환경 | Python 3.13, FastAPI, MySQL, Redis, Docker, Prometheus |
비즈니스 배경 및 문제 정의
자기주도 학습의 한계를 해결하기 위한 AI 멘토링 기반 학습 플랫폼 구축
비즈니스 문제점:
- MOOC 플랫폼의 극도로 낮은 완료율 (5-15%)
- 체계적인 학습 설계 및 지속적 피드백 부재
- 개인 학습의 고립성과 방향성 상실
- 멘토 접근성의 한계 및 비용 부담
핵심 솔루션:
- AI 기반 개인화된 커리큘럼 생성: 목표와 기간에 따른 맞춤형 학습 설계
- 5단계 AI 피드백 시스템: 정확성, 누락, 오류, 심화질문, 확장학습 평가
- 소셜 학습 환경: 좋아요, 댓글, 팔로우를 통한 학습 동기 부여
- 진도 관리 및 통계: 학습 현황 추적 및 성취감 제공
과학적 근거:
- 인출 연습(Retrieval Practice): 학습 후 요약이 장기 기억에 50% 더 효과적
- Testing Effect: 피드백이 있을 때 학습 효과 2배 증가
- 분산 학습: 주차별 커리큘럼을 통한 효과적 학습법 적용
Sequence Diagram
1. 회원가입 & 로그인
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database Note over U,D: 회원가입 플로우 U->>F: 회원가입 정보 입력 F->>A: POST /auth/signup Note right of A: 유효성 검증<br/>- 이메일 형식<br/>- 비밀번호 규칙<br/>- 이름 중복 체크 A->>D: 이메일/이름 중복 확인 D-->>A: 중복 여부 반환 alt 중복 존재 A-->>F: 400 Bad Request (중복 오류) F-->>U: 오류 메시지 표시 else 중복 없음 A->>A: 비밀번호 해시화 A->>D: 사용자 정보 저장 D-->>A: 저장 완료 (user_id 반환) A-->>F: 201 Created (회원가입 성공) F-->>U: 가입 완료 메시지 end Note over U,D: 로그인 플로우 U->>F: 이메일/비밀번호 입력 F->>A: POST /auth/login (form-data) A->>D: 이메일로 사용자 조회 D-->>A: 사용자 정보 반환 alt 사용자 없음 A-->>F: 401 Unauthorized F-->>U: "이메일이 존재하지 않습니다" else 사용자 존재 A->>A: 비밀번호 검증 alt 비밀번호 불일치 A-->>F: 401 Unauthorized F-->>U: "비밀번호가 일치하지 않습니다" else 비밀번호 일치 A->>A: JWT 토큰 생성 A-->>F: 200 OK (access_token, role) F->>F: 토큰을 로컬 스토리지에 저장 F-->>U: 로그인 성공, 메인 페이지 이동 end end
2. AI 커리큘럼 생성
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant L as LLM Service participant D as Database Note over U,D: AI 커리큘럼 생성 플로우 U->>F: 커리큘럼 생성 폼 작성 Note right of U: - 학습 목표<br/>- 기간 (1-24주)<br/>- 난이도 (beginner/intermediate/expert)<br/>- 추가 세부사항 F->>A: POST /curriculums/generate Note right of A: Authorization 헤더 검증 A->>A: JWT 토큰에서 user_id 추출 A->>A: 사용자 커리큘럼 개수 확인 (최대 10개) alt 커리큘럼 개수 초과 A-->>F: 403 Forbidden (최대 10개 제한) F-->>U: "최대 10개까지만 생성 가능합니다" else 생성 가능 A->>A: 요청 데이터 유효성 검증 A->>L: LLM 커리큘럼 생성 요청 Note right of L: 프롬프트 템플릿:<br/>- 목표: {goal}<br/>- 기간: {period}주<br/>- 난이도: {difficulty}<br/>- 세부사항: {details} L->>L: GPT-4o-mini로 커리큘럼 생성 Note right of L: 응답 형식:<br/>- title: 커리큘럼 제목<br/>- week_schedules: 주차별 스케줄<br/> - week_number<br/> - title<br/> - lessons (1-5개) alt LLM 생성 실패 L-->>A: 500 Internal Error A-->>F: 500 Server Error F-->>U: "AI 생성에 실패했습니다. 다시 시도해주세요" else LLM 생성 성공 L-->>A: 구조화된 커리큘럼 데이터 A->>A: 응답 데이터 검증 및 파싱 A->>D: 커리큘럼 저장 Note right of D: curriculums 테이블<br/>+ week_schedules 테이블 D-->>A: 저장 완료 (curriculum_id) A-->>F: 201 Created (생성된 커리큘럼) F-->>U: 생성 완료, 커리큘럼 상세 페이지 이동 end end
3. 학습 요약 작성 및 AI 피드백
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database participant L as LLM Service Note over U,L: 학습 요약 작성 플로우 U->>F: 특정 주차 학습 완료 후 요약 작성 Note right of U: 100-5000자 학습 요약 F->>A: POST /curriculums/{id}/weeks/{week}/summaries A->>A: 권한 확인 (커리큘럼 소유자인지) A->>D: 해당 주차가 존재하는지 확인 D-->>A: 주차 정보 반환 alt 주차 없음 또는 권한 없음 A-->>F: 404 Not Found / 403 Forbidden F-->>U: 오류 메시지 표시 else 유효한 요청 A->>D: 요약 저장 D-->>A: 저장 완료 (summary_id) A-->>F: 201 Created (요약 생성 완료) F-->>U: 요약 저장 완료, AI 피드백 생성 버튼 활성화 end Note over U,L: AI 피드백 생성 플로우 U->>F: AI 피드백 생성 요청 F->>A: POST /summaries/{summary_id}/feedbacks/generate A->>A: 권한 확인 (요약 작성자인지) A->>D: 기존 피드백 존재 여부 확인 D-->>A: 피드백 존재 여부 alt 이미 피드백 존재 A-->>F: 400 Bad Request (이미 피드백 존재) F-->>U: "이미 피드백이 생성되었습니다" else 피드백 없음 A->>D: 커리큘럼 주차별 레슨 데이터 조회 D-->>A: 해당 주차 레슨 목록 A->>D: 사용자 요약 내용 조회 D-->>A: 요약 내용 A->>L: AI 피드백 생성 요청 Note right of L: 5단계 평가 프롬프트:<br/>1. 정확성 (내용이 정확한가?)<br/>2. 누락 (빠진 중요 내용은?)<br/>3. 오류 (잘못 이해한 부분은?)<br/>4. 심화질문 (더 깊이 생각할 점은?)<br/>5. 확장학습 (추가로 학습할 내용은?)<br/>+ 0.0-10.0 점수 L->>L: GPT-4o-mini로 피드백 생성 alt LLM 생성 실패 L-->>A: 500 Internal Error A-->>F: 500 Server Error F-->>U: "AI 피드백 생성에 실패했습니다" else LLM 생성 성공 L-->>A: 구조화된 피드백 (comment + score) A->>A: 점수 기반 등급 계산 (A+, A, B+, B, C+, C, D) A->>D: 피드백 저장 D-->>A: 저장 완료 (feedback_id) A-->>F: 201 Created (피드백 생성 완료) F-->>U: 피드백 표시 (점수, 등급, 상세 코멘트) end end
4. 소셜 기능 (좋아요/댓글/북마크)
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database participant R as Redis Cache Note over U,R: 좋아요 기능 U->>F: 커리큘럼 좋아요 클릭 F->>A: POST /curriculums/{id}/like A->>A: JWT에서 user_id 추출 A->>D: 커리큘럼 접근 가능 여부 확인 D-->>A: 커리큘럼 정보 반환 A->>D: 이미 좋아요 했는지 확인 D-->>A: 좋아요 존재 여부 alt 이미 좋아요함 A-->>F: 409 Conflict (중복 좋아요) F-->>U: "이미 좋아요를 눌렀습니다" else 좋아요 안함 A->>D: 좋아요 레코드 생성 D-->>A: 생성 완료 A->>R: 좋아요 카운트 캐시 무효화 Note right of R: 키: like_count:{curriculum_id} A-->>F: 201 Created (좋아요 성공) F->>F: UI 업데이트 (하트 아이콘 활성화) F-->>U: 좋아요 완료 end Note over U,R: 좋아요 취소 U->>F: 좋아요 취소 클릭 F->>A: DELETE /curriculums/{id}/like A->>D: 좋아요 레코드 삭제 D-->>A: 삭제 완료 A->>R: 좋아요 카운트 캐시 무효화 A-->>F: 204 No Content F-->>U: 좋아요 취소 완료 Note over U,R: 댓글 작성 U->>F: 댓글 내용 입력 (1-1000자) F->>A: POST /curriculums/{id}/comments A->>A: 내용 유효성 검증 A->>D: 커리큘럼 접근 권한 확인 D-->>A: 권한 확인 완료 A->>D: 댓글 저장 D-->>A: 저장 완료 (comment_id) A-->>F: 201 Created (댓글 생성) F-->>U: 댓글 목록에 추가 표시 Note over U,R: 댓글 수정 U->>F: 내 댓글 수정 F->>A: PUT /curriculums/comments/{comment_id} A->>D: 댓글 작성자 확인 D-->>A: 작성자 정보 alt 작성자 아님 A-->>F: 403 Forbidden F-->>U: "본인 댓글만 수정 가능합니다" else 작성자임 A->>D: 댓글 내용 업데이트 D-->>A: 업데이트 완료 A-->>F: 200 OK (수정 완료) F-->>U: 댓글 내용 업데이트 end Note over U,R: 북마크 기능 U->>F: 북마크 추가 F->>A: POST /curriculums/{id}/bookmark A->>D: 중복 북마크 확인 D-->>A: 북마크 존재 여부 alt 이미 북마크함 A-->>F: 409 Conflict F-->>U: "이미 북마크되었습니다" else 북마크 안함 A->>D: 북마크 레코드 생성 D-->>A: 생성 완료 A-->>F: 201 Created F-->>U: 북마크 완료 end
5. 피드 조회 및 캐시
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant R as Redis Cache participant D as Database Note over U,D: 공개 피드 조회 (캐시 우선) U->>F: 피드 페이지 접속 F->>A: GET /feed/public?page=1&items_per_page=20 A->>A: JWT 토큰 검증 A->>R: 캐시된 피드 데이터 확인 Note right of R: 캐시 키: feed:public_curriculums:page:{page}:size:{size}<br/>TTL: 5분 (300초) alt 캐시 HIT R-->>A: 캐시된 피드 데이터 반환 A-->>F: 200 OK (캐시된 데이터) F-->>U: 빠른 피드 표시 else 캐시 MISS A->>D: 공개 커리큘럼 목록 조회 Note right of D: SELECT * FROM curriculums<br/>WHERE visibility = 'PUBLIC'<br/>ORDER BY updated_at DESC<br/>LIMIT {size} OFFSET {offset} D-->>A: 커리큘럼 목록 A->>D: 각 커리큘럼의 소유자 정보 조회 D-->>A: 소유자 이름들 A->>D: 각 커리큘럼의 카테고리/태그 정보 조회 D-->>A: 카테고리/태그 데이터 A->>A: 피드 아이템 데이터 구성 Note right of A: - 커리큘럼 기본 정보<br/>- 소유자 이름<br/>- 총 주차/레슨 수<br/>- 카테고리 이름/색상<br/>- 태그 목록<br/>- 상대 시간 ("2시간 전") A->>R: 구성된 피드 데이터 캐시 저장 Note right of R: TTL 5분, 무작위 지연(±30초) 추가로<br/>캐시 스탬피드 방지 A-->>F: 200 OK (새로 구성된 데이터) F-->>U: 피드 표시 end Note over U,D: 필터링된 피드 조회 U->>F: 카테고리/태그 필터 적용 F->>A: GET /feed/public?category_id={id}&tags=Python,AI A->>R: 필터별 캐시 확인 Note right of R: 필터별 별도 캐시 키:<br/>feed:public:category:{id}:tags:{tags} alt 필터 캐시 HIT R-->>A: 필터된 캐시 데이터 A-->>F: 200 OK F-->>U: 필터된 피드 표시 else 필터 캐시 MISS A->>D: 필터 조건으로 커리큘럼 조회 Note right of D: 카테고리/태그 JOIN으로<br/>조건에 맞는 커리큘럼 검색 D-->>A: 필터된 커리큘럼 목록 A->>A: 피드 아이템 구성 A->>R: 필터별 캐시 저장 A-->>F: 200 OK F-->>U: 필터된 피드 표시 end Note over U,D: 캐시 무효화 (커리큘럼 수정 시) U->>F: 커리큘럼 수정/삭제 F->>A: PATCH/DELETE /curriculums/{id} A->>D: 커리큘럼 수정/삭제 D-->>A: 작업 완료 A->>R: 관련 피드 캐시 무효화 Note right of R: 무효화 대상:<br/>- feed:public_curriculums:*<br/>- feed:public:category:*<br/>- feed:public:tags:* A->>R: 특정 커리큘럼 피드 갱신 트리거 A-->>F: 200 OK / 204 No Content F-->>U: 작업 완료 Note over U,D: 관리자 전체 피드 캐시 갱신 participant Admin as Admin Admin->>F: 전체 피드 캐시 갱신 요청 F->>A: POST /feed/refresh (Admin 권한 필요) A->>A: 관리자 권한 확인 A->>R: 모든 피드 관련 캐시 삭제 A->>D: 최신 100개 커리큘럼 조회 D-->>A: 커리큘럼 데이터 A->>A: 피드 데이터 pre-warming A->>R: 새로운 캐시 데이터 저장 A-->>F: 204 No Content F-->>Admin: 캐시 갱신 완료
6. 태그 및 카테고리 관리
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database participant Admin as Admin User Note over U,D: 커리큘럼에 태그 추가 U->>F: 커리큘럼 상세 페이지에서 태그 추가 Note right of U: 최대 10개 태그 입력<br/>예: ["Python", "백엔드", "초급"] F->>A: POST /curriculums/{id}/tags A->>A: 권한 확인 (커리큘럼 소유자인지) A->>D: 현재 커리큘럼의 태그 수 확인 D-->>A: 현재 태그 개수 alt 태그 개수 초과 (10개 이상) A-->>F: 400 Bad Request (태그 개수 제한) F-->>U: "최대 10개까지만 추가 가능합니다" else 태그 추가 가능 loop 각 태그에 대해 A->>D: 태그 존재 여부 확인 D-->>A: 태그 존재 여부 alt 태그 없음 A->>D: 새 태그 생성 Note right of D: tags 테이블에 INSERT<br/>- name: 태그명 (소문자 변환)<br/>- created_by: user_id<br/>- usage_count: 0 D-->>A: 새 태그 생성 완료 else 태그 존재 A->>A: 기존 태그 사용 end A->>D: 커리큘럼-태그 연결 생성 Note right of D: curriculum_tags 테이블에 INSERT<br/>중복 방지 (UNIQUE 제약) D-->>A: 연결 완료 A->>D: 태그 사용 횟수 증가 Note right of D: UPDATE tags SET usage_count = usage_count + 1 D-->>A: 사용 횟수 업데이트 완료 end A-->>F: 201 Created (태그 추가 완료) F-->>U: 태그 목록 업데이트 표시 end Note over U,D: 태그 검색 (자동완성) U->>F: 태그 입력 필드에 타이핑 F->>A: GET /tags/search?q={검색어}&limit=10 A->>D: 태그 이름으로 LIKE 검색 Note right of D: SELECT * FROM tags<br/>WHERE name LIKE '%{검색어}%'<br/>ORDER BY usage_count DESC<br/>LIMIT 10 D-->>A: 매칭되는 태그 목록 A-->>F: 200 OK (태그 제안 목록) F-->>U: 드롭다운으로 태그 제안 표시 Note over Admin,D: 관리자 - 카테고리 생성 Admin->>F: 관리자 페이지에서 카테고리 생성 Note right of Admin: - 이름 (2-30자)<br/>- 설명<br/>- 색상 (#FFFFFF)<br/>- 아이콘<br/>- 정렬 순서 F->>A: POST /categories (Admin 권한 필요) A->>A: 관리자 권한 확인 A->>D: 카테고리 이름 중복 확인 D-->>A: 중복 여부 alt 이름 중복 A-->>F: 409 Conflict (이름 중복) F-->>Admin: "동일한 이름의 카테고리가 존재합니다" else 중복 없음 A->>A: 색상 형식 검증 (헥스 코드) A->>D: 카테고리 저장 Note right of D: categories 테이블에 INSERT<br/>- is_active: true (기본값)<br/>- sort_order: 자동 할당 D-->>A: 저장 완료 (category_id) A-->>F: 201 Created (카테고리 생성) F-->>Admin: 카테고리 목록에 추가 표시 end Note over U,D: 커리큘럼에 카테고리 할당 U->>F: 커리큘럼에 카테고리 선택 F->>A: POST /curriculums/{id}/category A->>A: 권한 확인 (커리큘럼 소유자) A->>D: 카테고리 활성 상태 확인 D-->>A: 카테고리 정보 (is_active) alt 비활성 카테고리 A-->>F: 400 Bad Request (비활성 카테고리) F-->>U: "비활성화된 카테고리는 할당할 수 없습니다" else 활성 카테고리 A->>D: 기존 카테고리 할당 해제 (1:1 관계) A->>D: 새 카테고리 할당 Note right of D: curriculum_categories 테이블<br/>UNIQUE(curriculum_id) 제약으로<br/>1:1 관계 보장 D-->>A: 할당 완료 A->>D: 카테고리 사용 횟수 증가 A-->>F: 201 Created (카테고리 할당) F-->>U: 카테고리 표시 업데이트 end Note over U,D: 태그로 커리큘럼 검색 U->>F: 태그 기반 검색 F->>A: GET /curriculums/search/by-tags?tag_names=Python,AI A->>D: 태그 교집합으로 커리큘럼 검색 Note right of D: SELECT curriculum_id FROM curriculum_tags ct<br/>JOIN tags t ON ct.tag_id = t.id<br/>WHERE t.name IN ('python', 'ai')<br/>GROUP BY curriculum_id<br/>HAVING COUNT(*) = 2 D-->>A: 매칭되는 커리큘럼 ID 목록 A-->>F: 200 OK (커리큘럼 ID 목록) F->>A: 커리큘럼 상세 정보 조회 (별도 요청) A->>D: 커리큘럼 상세 정보 D-->>A: 커리큘럼 데이터 A-->>F: 커리큘럼 정보 F-->>U: 검색 결과 표시
7. 학습 통계 및 진도 추적
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database Note over U,D: 학습 통계 대시보드 조회 U->>F: 마이페이지 → 학습 통계 탭 F->>A: GET /users/me/learning/stats?days=30 A->>A: JWT에서 user_id 추출 A->>D: 사용자의 모든 커리큘럼 조회 Note right of D: SELECT * FROM curriculums<br/>WHERE user_id = {user_id} D-->>A: 사용자 커리큘럼 목록 A->>D: 기간 내 작성한 요약 조회 Note right of D: SELECT * FROM summaries<br/>WHERE owner_id = {user_id}<br/>AND created_at >= {30일 전} D-->>A: 요약 목록 A->>D: 기간 내 받은 피드백 조회 Note right of D: SELECT f.* FROM feedbacks f<br/>JOIN summaries s ON f.summary_id = s.id<br/>WHERE s.owner_id = {user_id}<br/>AND f.created_at >= {30일 전} D-->>A: 피드백 목록 A->>A: 학습 통계 계산 Note right of A: 계산 항목:<br/>- 총 요약/피드백 수<br/>- 활성/완료 커리큘럼 수<br/>- 평균 점수, 최고/최저 점수<br/>- 등급별 분포 (A+, A, B+, B, C+, C, D)<br/>- 연속 학습 일수<br/>- 주간 목표 달성률 A->>A: 연속 학습 일수 계산 Note right of A: 요약 작성 날짜를 기준으로<br/>연속으로 학습한 일수 계산<br/>current_streak vs longest_streak A->>A: 커리큘럼별 진도 계산 Note right of A: 각 커리큘럼별로:<br/>- 전체 주차 수<br/>- 작성된 요약 수<br/>- 완료율 = (요약 수 / 주차 수) × 100 A-->>F: 200 OK (종합 학습 통계) F-->>U: 대시보드 표시 (차트 + 지표) Note over U,D: 학습 현황 간단 요약 U->>F: 메인 페이지 위젯 F->>A: GET /users/me/learning/overview A->>D: 최근 7일 활동 조회 D-->>A: 최근 활동 데이터 A->>A: 간단 요약 계산 Note right of A: - 이번 주 학습 일수<br/>- 최근 피드백 평균 점수<br/>- 진행 중인 커리큘럼 수<br/>- 다음 학습 예정 항목 A-->>F: 200 OK (간단 요약) F-->>U: 위젯 형태로 표시 Note over U,D: 커리큘럼별 상세 진도 U->>F: 특정 커리큘럼 진도 확인 F->>A: GET /users/me/learning/progress A->>D: 사용자 모든 커리큘럼과 진도 조회 Note right of D: 복잡한 JOIN 쿼리:<br/>- curriculums (기본 정보)<br/>- week_schedules (총 주차)<br/>- summaries (작성된 요약)<br/>- feedbacks (받은 피드백) D-->>A: 커리큘럼별 상세 데이터 A->>A: 각 커리큘럼별 진도 상세 계산 Note right of A: 커리큘럼별로:<br/>- 제목, 총 주차 수<br/>- 완료된 주차 목록<br/>- 다음 학습할 주차<br/>- 전체 진도율<br/>- 최근 학습 날짜<br/>- 예상 완료 날짜 A-->>F: 200 OK (커리큘럼별 진도) F-->>U: 진도바와 상세 정보 표시 Note over U,D: 학습 연속성 정보 U->>F: 학습 스트릭 확인 F->>A: GET /users/me/learning/streak A->>D: 사용자의 모든 요약 작성 날짜 조회 Note right of D: SELECT DATE(created_at) as learning_date<br/>FROM summaries<br/>WHERE owner_id = {user_id}<br/>GROUP BY DATE(created_at)<br/>ORDER BY learning_date DESC D-->>A: 학습한 날짜 목록 A->>A: 연속성 계산 알고리즘 Note right of A: 1. 오늘부터 역순으로 확인<br/>2. 연속된 날짜 카운트<br/>3. 최장 연속 기록도 계산<br/>4. 총 학습 일수 계산 A-->>F: 200 OK (연속성 정보) Note right of F: - current_streak: 7일<br/>- longest_streak: 21일<br/>- total_learning_days: 45일<br/>- 학습 캘린더 히트맵 데이터 F-->>U: 스트릭 정보와 캘린더 표시 Note over U,D: 월별 학습 진도 트렌드 U->>F: 월별 통계 차트 요청 F->>A: GET /users/me/learning/stats?days=365 A->>D: 1년간 월별 학습 데이터 조회 Note right of D: 월별 집계 쿼리:<br/>SELECT<br/> DATE_FORMAT(created_at, '%Y-%m') as month,<br/> COUNT(*) as summary_count,<br/> AVG(f.score) as avg_score<br/>FROM summaries s<br/>LEFT JOIN feedbacks f ON s.id = f.summary_id<br/>WHERE s.owner_id = {user_id}<br/>GROUP BY month<br/>ORDER BY month D-->>A: 월별 집계 데이터 A->>A: 트렌드 분석 Note right of A: - 월별 학습량 변화<br/>- 평균 점수 변화<br/>- 학습 패턴 분석<br/>- 목표 달성률 계산 A-->>F: 200 OK (월별 트렌드) F-->>U: 라인 차트로 트렌드 표시
8. 팔로우 시스템
sequenceDiagram participant U as User participant F as Frontend participant A as API Server participant D as Database participant O as Other User Note over U,D: 사용자 팔로우 U->>F: 다른 사용자 프로필에서 팔로우 버튼 클릭 F->>A: POST /social/follow Note right of F: Request Body:<br/>{"followee_id": "01HJWXZ..."} A->>A: JWT에서 follower_id (현재 사용자) 추출 A->>A: 자기 자신 팔로우 방지 체크 alt 자기 자신 팔로우 시도 A-->>F: 400 Bad Request F-->>U: "자기 자신은 팔로우할 수 없습니다" else 다른 사용자 팔로우 A->>D: 팔로우 대상 사용자 존재 확인 D-->>A: 사용자 존재 여부 alt 사용자 없음 A-->>F: 404 Not Found F-->>U: "존재하지 않는 사용자입니다" else 사용자 존재 A->>D: 이미 팔로우 중인지 확인 Note right of D: SELECT * FROM follows<br/>WHERE follower_id = {현재사용자}<br/>AND followee_id = {대상사용자} D-->>A: 팔로우 관계 존재 여부 alt 이미 팔로우 중 A-->>F: 409 Conflict F-->>U: "이미 팔로우 중입니다" else 팔로우 안함 A->>D: 팔로우 관계 생성 Note right of D: INSERT INTO follows<br/>(follower_id, followee_id, created_at) D-->>A: 팔로우 완료 A-->>F: 201 Created F->>F: 팔로우 버튼 → 언팔로우 버튼으로 변경 F-->>U: 팔로우 완료 end end end Note over U,D: 언팔로우 U->>F: 언팔로우 버튼 클릭 F->>A: DELETE /social/unfollow Note right of F: Request Body:<br/>{"followee_id": "01HJWXZ..."} A->>D: 팔로우 관계 삭제 Note right of D: DELETE FROM follows<br/>WHERE follower_id = {현재사용자}<br/>AND followee_id = {대상사용자} D-->>A: 삭제 완료 (영향받은 행 수) alt 팔로우 관계 없음 A-->>F: 404 Not Found F-->>U: "팔로우하지 않은 사용자입니다" else 언팔로우 성공 A-->>F: 204 No Content F->>F: 언팔로우 버튼 → 팔로우 버튼으로 변경 F-->>U: 언팔로우 완료 end Note over U,D: 팔로워 목록 조회 U->>F: 특정 사용자의 팔로워 목록 확인 F->>A: GET /social/users/{user_id}/followers?page=1 A->>D: 팔로워 목록과 상호 팔로우 상태 조회 Note right of D: 복잡한 JOIN 쿼리:<br/>SELECT u.*, <br/> EXISTS(팔로우 여부) as is_following,<br/> EXISTS(맞팔 여부) as is_followed_by<br/>FROM follows f<br/>JOIN users u ON f.follower_id = u.id<br/>WHERE f.followee_id = {대상사용자} D-->>A: 팔로워 목록 + 상호 관계 정보 A-->>F: 200 OK (팔로워 목록) F-->>U: 팔로워 리스트 표시 (팔로우 상태 포함) Note over U,D: 팔로잉 목록 조회 U->>F: 내가 팔로우하는 사용자 목록 F->>A: GET /social/me/following?page=1 A->>D: 팔로잉 목록과 상호 팔로우 상태 조회 Note right of D: SELECT u.*,<br/> true as is_following,<br/> EXISTS(맞팔 여부) as is_followed_by<br/>FROM follows f<br/>JOIN users u ON f.followee_id = u.id<br/>WHERE f.follower_id = {현재사용자} D-->>A: 팔로잉 목록 + 맞팔 정보 A-->>F: 200 OK (팔로잉 목록) F-->>U: 팔로잉 리스트 표시 Note over U,D: 팔로우 통계 조회 U->>F: 사용자 프로필 페이지 F->>A: GET /social/users/{user_id}/stats A->>D: 팔로워/팔로잉 수 조회 Note right of D: 두 개의 COUNT 쿼리:<br/>1. SELECT COUNT(*) FROM follows<br/> WHERE followee_id = {user_id}<br/>2. SELECT COUNT(*) FROM follows<br/> WHERE follower_id = {user_id} D-->>A: 팔로워 수, 팔로잉 수 A->>D: 현재 사용자와의 상호 팔로우 관계 확인 (선택) D-->>A: 상호 팔로우 정보 A-->>F: 200 OK (통계 정보) F-->>U: "팔로워 150명, 팔로잉 75명" 표시 Note over U,D: 팔로우 추천 시스템 U->>F: 추천 사용자 페이지 F->>A: GET /social/suggestions?limit=10 A->>D: 2차 연결 기반 추천 알고리즘 Note right of D: 복잡한 추천 쿼리:<br/>1. 내가 팔로우하는 사람들이 팔로우하는 사람<br/>2. 나와 같은 태그를 많이 사용하는 사람<br/>3. 최근 활발한 사용자<br/>4. 이미 팔로우한 사람 제외 D-->>A: 추천 사용자 목록 A-->>F: 200 OK (추천 목록) F-->>U: "회원님이 좋아할 만한 사용자" 섹션 표시 Note over U,D: 팔로우한 사용자의 커리큘럼 피드 U->>F: 팔로잉 피드 탭 F->>A: GET /curriculums/following?page=1 A->>D: 팔로우한 사용자들의 공개 커리큘럼 조회 Note right of D: SELECT c.* FROM curriculums c<br/>JOIN follows f ON c.user_id = f.followee_id<br/>WHERE f.follower_id = {현재사용자}<br/>AND c.visibility = 'PUBLIC'<br/>ORDER BY c.updated_at DESC D-->>A: 팔로잉 사용자들의 커리큘럼 A-->>F: 200 OK (팔로잉 피드) F-->>U: 팔로우한 사용자들의 최신 커리큘럼 표시
9. 관리자 기능
sequenceDiagram participant Admin as Admin User participant F as Frontend participant A as API Server participant D as Database participant R as Redis Cache Note over Admin,R: 관리자 사용자 관리 Admin->>F: 관리자 페이지 → 사용자 관리 F->>A: GET /admin/users?page=1&items_per_page=20 A->>A: JWT 토큰에서 사용자 역할 확인 alt 관리자 권한 없음 A-->>F: 403 Forbidden F-->>Admin: "관리자 권한이 필요합니다" else 관리자 권한 있음 A->>D: 사용자 목록 조회 (페이지네이션) Note right of D: SELECT id, email, name, role<br/>FROM users<br/>ORDER BY created_at DESC<br/>LIMIT {size} OFFSET {offset} D-->>A: 사용자 목록 + 총 개수 A-->>F: 200 OK (사용자 목록) F-->>Admin: 사용자 관리 테이블 표시 end Note over Admin,R: 사용자 역할 변경 Admin->>F: 특정 사용자의 역할 변경 (USER → ADMIN) F->>A: PATCH /admin/users/{user_id}/role Note right of F: Request Body:<br/>{"role": "ADMIN"} A->>A: 관리자 권한 재확인 A->>D: 대상 사용자 존재 확인 D-->>A: 사용자 정보 alt 사용자 없음 A-->>F: 404 Not Found F-->>Admin: "존재하지 않는 사용자입니다" else 사용자 존재 A->>A: 역할 값 유효성 검증 (USER/ADMIN) A->>D: 사용자 역할 업데이트 Note right of D: UPDATE users<br/>SET role = 'ADMIN', updated_at = NOW()<br/>WHERE id = {user_id} D-->>A: 업데이트 완료 A-->>F: 200 OK (변경된 사용자 정보) F-->>Admin: 역할 변경 완료 표시 end Note over Admin,R: 커리큘럼 관리 Admin->>F: 커리큘럼 관리 페이지 F->>A: GET /admin/curriculums?page=1 A->>D: 모든 커리큘럼 조회 (소유자 정보 포함) Note right of D: SELECT c.*, u.name as owner_name<br/>FROM curriculums c<br/>JOIN users u ON c.user_id = u.id<br/>ORDER BY c.created_at DESC D-->>A: 커리큘럼 목록 + 소유자 정보 A-->>F: 200 OK (커리큘럼 관리 목록)` F-->>Admin: 커리큘럼 관리 테이블 표시 Note over Admin,R: 커리큘럼 공개/비공개 변경 Admin->>F: 특정 커리큘럼 비공개 처리 F->>A: PATCH /admin/curriculums/{curriculum_id}/visibility Note right of F: Request Body:<br/>{"visibility": "PRIVATE"} A->>D: 커리큘럼 존재 확인 D-->>A: 커리큘럼 정보 A->>D: 공개 설정 업데이트 Note right of D: UPDATE curriculums<br/>SET visibility = 'PRIVATE'<br/>WHERE id = {curriculum_id} D-->>A: 업데이트 완료 A->>R: 관련 피드 캐시 무효화 Note right of R: 공개 피드에서 제거되므로<br/>feed:public:* 캐시 삭제 A-->>F: 200 OK (변경 완료) F-->>Admin: 공개 설정 변경 표시 Note over Admin,R: 커리큘럼 강제 삭제 Admin->>F: 부적절한 커리큘럼 삭제 F->>A: DELETE /admin/curriculums/{curriculum_id} A->>D: 커리큘럼과 연관된 모든 데이터 삭제 Note right of D: CASCADE DELETE로 연쇄 삭제:<br/>- week_schedules<br/>- summaries → feedbacks<br/>- likes, comments, bookmarks<br/>- curriculum_tags, curriculum_categories D-->>A: 삭제 완료 A->>R: 관련 캐시 전체 무효화 A-->>F: 204 No Content F-->>Admin: 삭제 완료 메시지 Note over Admin,R: 전체 피드 캐시 강제 갱신 Admin->>F: 시스템 관리 → 캐시 관리 F->>A: POST /feed/refresh (관리자 전용) A->>A: 관리자 권한 확인 A->>R: 모든 피드 관련 캐시 삭제 Note right of R: 삭제 대상 캐시:<br/>- feed:public:*<br/>- feed:category:*<br/>- feed:tags:*<br/>- social_stats:* A->>D: 최신 공개 커리큘럼 100개 조회 D-->>A: 최신 커리큘럼 데이터 A->>A: 피드 데이터 재구성 (pre-warming) A->>R: 새로운 캐시 데이터 저장 A-->>F: 204 No Content F-->>Admin: "피드 캐시가 갱신되었습니다" Note over Admin,R: 태그/카테고리 관리 Admin->>F: 태그 관리 페이지 F->>A: GET /tags/statistics A->>D: 태그 통계 조회 Note right of D: SELECT<br/> COUNT(*) as total_tags,<br/> COUNT(CASE WHEN usage_count >= 10 THEN 1 END) as popular_tags,<br/> COUNT(CASE WHEN usage_count = 0 THEN 1 END) as unused_tags<br/>FROM tags D-->>A: 태그 통계 데이터 A-->>F: 200 OK (태그 통계) F-->>Admin: 태그 통계 대시보드 표시 Admin->>F: 미사용 태그 일괄 삭제 F->>A: DELETE /tags/{tag_id} (여러 개 반복) A->>D: 태그 사용 횟수 확인 D-->>A: usage_count alt 사용 중인 태그 A-->>F: 409 Conflict F-->>Admin: "사용 중인 태그는 삭제할 수 없습니다" else 미사용 태그 A->>D: 태그 삭제 D-->>A: 삭제 완료 A-->>F: 204 No Content F-->>Admin: 삭제 완료 end Note over Admin,R: 시스템 모니터링 Admin->>F: 시스템 상태 대시보드 F->>A: GET /admin/system/health A->>D: 데이터베이스 연결 상태 확인 D-->>A: DB 상태 A->>R: Redis 연결 상태 확인 R-->>A: Redis 상태 A->>A: 시스템 리소스 확인 Note right of A: - API 응답 시간<br/>- 활성 사용자 수<br/>- LLM 사용량<br/>- 에러율 A-->>F: 200 OK (시스템 상태) F-->>Admin: 상태 대시보드 표시 Note over Admin,R: 사용자 활동 로그 조회 Admin->>F: 사용자 활동 분석 F->>A: GET /admin/users/{user_id}/activities A->>D: 사용자 활동 로그 조회 Note right of D: 다양한 테이블에서 활동 기록:<br/>- 커리큘럼 생성/수정<br/>- 요약 작성<br/>- 소셜 활동 (좋아요/댓글)<br/>- 로그인 기록 D-->>A: 활동 로그 데이터 A-->>F: 200 OK (활동 기록) F-->>Admin: 타임라인 형태로 활동 표시
기술 스택 및 아키텍처
핵심 기술 스택
Framework : FastAPI
Language : Python
Dependency : Poetry
Database : Mysql + SQLAlchemy
Cache : Redis
Migration : Alembic
LLM Framework : langchain
LLM Provider : OpenAI GPT-4o-mini
Observability : Langfuse
Pattern : Clean Architecture
DI Container : dependency-injector
IG Generation : ULID
Containerzation: Docker + Docker compose
Monitoring : Prometheus + Grafana
시스템 아키텍처
graph TD A[Frontend React] --> B[FastAPI Server] B --> C[Clean Architecture Modules] C --> D[User Module] C --> E[Curriculum Module] C --> F[Learning Module] C --> G[Social Module] C --> H[Feed Module] C --> I[Taxonomy Module] C --> J[Admin Module] B --> K[Infrastructure Layer] K --> L[MySQL Database] K --> M[Redis Cache] K --> N[OpenAI LLM] K --> O[Langfuse Monitoring]
Clean Architecture 구조
backend/app/
├── api/v1/ # API 라우터 (Interface Layer)
├── core/ # 설정, 인증, DI Container
├── common/ # 공통 서비스 (LLM, Cache, DB)
├── modules/ # 도메인별 모듈
│ ├── user/ # 사용자 관리
│ ├── curriculum/ # 커리큘럼 관리
│ ├── learning/ # 학습 및 피드백
│ ├── social/ # 소셜 기능
│ ├── taxonomy/ # 태그 및 카테고리
│ ├── feed/ # 피드 관리
│ └── admin/ # 관리자 기능
└── utils/ # 유틸리티
각 모듈 구조:
module/
├── domain/ # 엔티티, 도메인 서비스
├── application/ # 비즈니스 로직 (UseCase)
├── infrastructure/ # DB, 외부 서비스 연동
└── interface/ # API 컨트롤러
ERD
erDiagram users { string id PK string email UK string name string password enum role datetime created_at datetime updated_at } curriculums { string id PK string user_id FK string title string visibility datetime created_at datetime updated_at } week_schedules { int id PK string curriculum_id FK int week_number string title json lessons } summaries { string id PK string curriculum_id FK int week_number text content string owner_id datetime created_at datetime updated_at } feedbacks { string id PK string summary_id FK text comment float score datetime created_at datetime updated_at } tags { string id PK string name UK int usage_count string created_by FK datetime created_at datetime updated_at } categories { string id PK string name UK text description string color string icon int sort_order bool is_active datetime created_at datetime updated_at } curriculum_tags { string id PK string curriculum_id FK string tag_id FK string added_by FK datetime created_at } curriculum_categories { string id PK string curriculum_id FK string category_id FK string assigned_by FK datetime created_at } likes { string id PK string curriculum_id FK string user_id FK datetime created_at } comments { string id PK string curriculum_id FK string user_id FK text content datetime created_at datetime updated_at } bookmarks { string id PK string curriculum_id FK string user_id FK datetime created_at } follows { string id PK string follower_id FK string followee_id FK datetime created_at } %% Relationships users ||--o{ curriculums : "owns" users ||--o{ tags : "creates" users ||--o{ likes : "likes" users ||--o{ comments : "writes" users ||--o{ bookmarks : "bookmarks" users ||--o{ curriculum_tags : "adds" users ||--o{ curriculum_categories : "assigns" users ||--o{ follows : "follower" users ||--o{ follows : "followee" curriculums ||--o{ week_schedules : "has" curriculums ||--o{ summaries : "contains" curriculums ||--o{ likes : "receives" curriculums ||--o{ comments : "receives" curriculums ||--o{ bookmarks : "bookmarked" curriculums ||--o{ curriculum_tags : "tagged" curriculums ||--o{ curriculum_categories : "categorized" summaries ||--o{ feedbacks : "receives" tags ||--o{ curriculum_tags : "used_in" categories ||--o{ curriculum_categories : "applied_to"
서비스 Demo
주요 기술적 도전과 해결책
1. 확장 가능한 시스템 설계
도전과제
- 복잡한 도메인 의존성: AI 서비스, 소셜 기능, 관리자 도구 등 다양한 도메인의 복합적 연동
- 확장성 요구사항: 향후 B2B 시장 진출과 마이크로서비스 전환을 고려한 설계 필요
- 유지보수성 확보: 빠른 기능 추가와 변경에 대응할 수 있는 유연한 구조 필요
문제 해결 과정
- 4계층 Clean Architecture 도입
- Domain, Application, Infrastructure, Interface 계층으로 명확한 책임 분리
- 의존성 역전 원칙 적용
- 고수준 모듈이 저수준 모듈에 의존하지 않도록 추상화 인터페이스 활용
- 도메인별 모듈 독립성
- 7개 독립 모듈(User, Curriculum, Learning, Social, Feed, Taxonomy, Admin) 구성
- 의존성 주입 컨테이너
- dependency-injector를 활용한 느슨한 결합과 테스트 용이성 확보
전체 project module들을 clean architecture로 구성, 확장성 확보
2. LLM 통합 및 AI 서비스 안정성
도전과제
- 응답 일관성 문제: AI의 자유형식 응답을 구조화된 데이터로 안정적 변환 필요
- 파싱 오류 빈발: JSON 형식 응답에서 예상치 못한 형식으로 인한 파싱 실패
- 토큰 사용량 최적화: 비용 효율적인 프롬프트 설계와 응답 길이 관리
- 서비스 가용성: 외부 LLM 서비스 장애 시 대응 방안 필요
문제 해결 과정
- LangChain 추상화 레이어: 다양한 LLM 제공자 지원 및 확장성 확보
- 구조화된 프롬프트 엔지니어링: JSON 스키마 기반 일관된 응답 형식 유도
- Pydantic 기반 응답 검증: 런타임 스키마 검증으로 파싱 오류 방지
- Langfuse 관측성 도구: 실시간 성공률, 응답시간, 토큰 사용량 모니터링
- 재시도 및 폴백 메커니즘: API 실패 시 자동 재시도 및 기본값 제공
기본 Httpx 요청보다 Langchain과 langfuse를 사용하여
여러 LLM 모델 사용성 확보
3. 고성능 비동기 처리 및 캐싱 전략
도전과제
- 높은 읽기 성능 요구: 피드 조회, 좋아요 수 집계, 학습 통계 등에서 빠른 응답 필요
- AI 작업으로 인한 지연: 커리큘럼 생성과 피드백 생성의 긴 처리 시간
- 동시성 처리: 다수 사용자의 동시 요청 처리 및 데이터 일관성 보장
- 캐시 무효화 복잡성: 실시간 업데이트와 캐시 일관성 간의 균형
문제 해결 과정
- SQLAlchemy Async ORM: 비동기 데이터베이스 I/O로 동시성 크게 개선
- Redis 다층 캐싱 전략: 공개 피드(5분), 소셜 메트릭(실시간), 학습 통계(10분) 별도 관리
- 커넥션 풀 최적화: 데이터베이스 세션 라이프사이클과 트랜잭션 관리 최적화
- 비동기 작업 처리: AI 피드백 생성을 백그라운드 작업으로 분리하여 사용자 경험 개선
FastAPI의 특성인 비동기 처리 구조를 활용해 I/O Bound 사전 처리
4. 의존성 주입과 테스트 용이성
도전과제
- 복잡한 외부 의존성: LLM, Database, Cache 등 다양한 외부 서비스 의존성
- AI 서비스 모킹의 어려움: 예측 불가능한 LLM 응답의 테스트 환경 시뮬레이션
- 통합 테스트 복잡성: 전체 시스템의 통합 테스트 시나리오 관리
- 환경별 설정 관리: 개발, 테스트, 프로덕션 환경의 서로 다른 구성 요소
문제 해결 과정
- 컨테이너 기반 DI: dependency-injector로 환경별 다른 구현체 주입
- 인터페이스 기반 설계: 모든 외부 의존성을 추상화 인터페이스로 분리
- Mock 서비스 구현: 테스트용 LLM, Database, Cache Mock 구현체 제공
- 설정 기반 전환: 환경 변수를 통한 실제/Mock 서비스 자동 선택
- 단계별 테스트 전략: 단위 → 통합 → E2E 테스트로 점진적 검증
# 핵심 의존성 주입 구조 예시
class ApplicationContainer(DeclarativeContainer):
config = providers.Configuration()
# 환경별 LLM 서비스 주입
llm_service = providers.Singleton(
RealLLMService if config.environment == "production" else MockLLMService,
api_key=config.openai_api_key
)
핵심 기능 구현
1. AI 커리큘럼 자동 생성 시스템
사용자가 “Python 백엔드 개발을 8주 동안 중급 수준으로 학습하고 싶다” 고 입력하면, GPT-4o-mini가 주차별 상세 커리큘럼을 자동 생성합니다.
구조화된 프롬프트 설계를 통해 일관성 있는 JSON 응답을 유도하고, 응답 파싱 및 검증 시스템으로 오류를 방지합니다. 생성된 커리큘럼은 사용자가 추가 편집할 수 있으며, 주차별로 3-5개의 구체적인 학습 목표를 제시합니다.
2. AI 피드백 시스템
학습자가 주차별 학습 내용을 요약하면, AI가 정확성, 완성도, 오류 검토, 심화 질문, 확장 학습 5가지 관점에서 종합적으로 평가합니다.
점수는 0-10점 척도로 제공되며, A+부터 D까지의 등급으로 변환됩니다. 단순한 점수를 넘어 구체적인 개선 방향과 다음 단계 학습 제안을 포함한 맞춤형 코멘트를 생성합니다.
3. 소셜 학습 환경 구축
좋아요 시스템은 Redis 카운터를 활용해 실시간으로 집계되며, 댓글 시스템을 통해 학습자 간 지식 공유가 활발히 이루어집니다. 팔로우 기능으로 관심 있는 학습자의 진도를 추적할 수 있고, 북마크 기능으로 참고하고 싶은 커리큘럼을 저장할 수 있습니다.
공개 피드 시스템에서는 모든 공개 커리큘럼이 최신순으로 노출되며, 태그와 카테고리 기반 필터링이 가능합니다. 이를 통해 학습자들이 서로의 학습 방법을 발견하고 영감을 얻을 수 있습니다.
4. 학습 진도 관리 및 분석
개인 대시보드에서는 진행 중인 커리큘럼별 완료율, 평균 피드백 점수, 학습 연속성(스트릭) 등을 시각적으로 제공합니다. 월별/주별 학습 패턴 분석을 통해 학습 습관 개선 인사이트를 제공합니다.
관리자 통계 기능에서는 전체 플랫폼의 사용 현황, 인기 커리큘럼, AI 피드백 품질 지표 등을 모니터링할 수 있습니다.
비즈니스 임팩트 및 성과
기술적 성과
아키텍처 및 확장성
- 모듈화된 시스템: Clean Architecture 기반 7개 독립 모듈로 유지보수성 극대화
- 향후 MSA 전환 준비: 각 모듈의 독립성 확보로 마이크로서비스 아키텍처 전환 기반 마련
- 의존성 관리: DI Container 활용으로 테스트 용이성과 코드 품질 크게 향상
- 기술 부채 최소화: 초기 설계부터 확장성을 고려한 구조로 장기적 개발 효율성 확보
시스템 안정성
- 실시간 가용성: Prometheus + Grafana 모니터링으로 장애 예방 및 빠른 대응
- LLM 관측성: LLM 비용, API 성능, 데이터베이스 상태 등 종합 모니터링 체계
- 자동화된 배포: Docker 기반 컨테이너화로 일관된 배포 환경 구축
AI 서비스 통합
- 높은 성공률: LLM 호출 성공률 98% 이상 달성 및 안정적인 서비스 제공
- 비용 최적화: Langfuse 모니터링을 통한 토큰 사용량 20% 절감
- 응답 품질: 구조화된 프롬프트로 일관성 있는 AI 응답 품질 확보
- 확장 가능성: LangChain 추상화로 다양한 LLM 모델 유연한 적용 기반
사업적 가치
시장 차별화
- 개인화된 학습 경험: 기존 MOOC와 달리 개별 맞춤형 커리큘럼 및 피드백 제공
- 과학적 근거 기반: 인출 연습과 분산 학습 등 검증된 학습법 적용
- 소셜 학습 환경: 고립된 개인 학습을 커뮤니티 기반 협력 학습으로 전환
- AI 멘토링: 접근하기 어려운 개인 맞춤형 멘토링
확장 가능한 비즈니스 모델
- B2C → B2B 확장 경로: 개인 사용자에서 기업 교육으로 자연스러운 시장 확장
- 마켓플레이스 잠재력: 전문가 제작 커리큘럼 판매를 통한 생태계 구축
- 데이터 기반 서비스: 축적된 학습 데이터를 활용한 분석 및 컨설팅 서비스
- 글로벌 서비스: 언어와 문화에 관계없이 적용 가능한 범용적 학습 플랫폼
커뮤니티 및 네트워크 효과
- 자발적 콘텐츠 생성: 사용자들이 직접 고품질 커리큘럼 제작 및 공유
- 바이럴 확산: 소셜 기능을 통한 자연스러운 사용자 확산 및 성장
- 지식 공유 문화: 학습 성과 공유를 통한 집단 지성 및 학습 효과 증대
- 지속적 참여: 게이미피케이션 요소로 장기적 사용자 리텐션 확보
핵심 기술적 학습 및 성장
백엔드 아키텍처 및 설계
1. 확장성을 감안한 구조적 설계
Clean Architecture 실전 적용을 통해 대규모 애플리케이션의 구조 설계 능력을 크게 향상시켰습니다. 단순한 레이어 분리를 넘어 도메인 중심의 모듈 설계와 의존성 역전 원칙을 실무에서 적용해보며, 확장 가능하고 테스트 용이한 시스템 구축 방법을 체득했습니다.
2. 의존성 주입과 TDD
의존성 주입 컨테이너 활용으로 객체 간 결합도를 낮추고 테스트 용이성을 크게 개선했습니다. 특히 AI 서비스와 같이 외부 의존성이 큰 컴포넌트를 효과적으로 모킹하고 테스트하는 방법을 익혔습니다.
3. AI 서비스 통합 및 LLM 운영
LangChain을 활용한 LLM 추상화를 통해 다양한 AI 모델을 효율적으로 통합하는 방법을 학습했습니다. 프롬프트 엔지니어링부터 응답 파싱, 오류 처리까지 실제 프로덕션 환경에서 안정적으로 AI 서비스를 운영하는 전 과정을 경험했습니다.
또한 Langfuse 관측성 도구를 통해 LLM 성능 모니터링, 비용 최적화, 프롬프트 품질 관리 등 AI 서비스 운영에 필수적인 관측성 구축 방법을 습득했습니다.
4. 고성능 비동기 시스템 개발
FastAPI와 SQLAlchemy Async를 활용한 비동기 웹 애플리케이션 개발로 높은 동시성 처리 능력을 확보했습니다. 커넥션 풀 관리, 세션 라이프사이클, 트랜잭션 처리 등 실무에서 중요한 성능 최적화 기법들을 실전에서 적용해보았습니다. Redis 기반 캐싱 전략 설계를 통해 읽기 성능을 대폭 개선하고, 캐시 무효화와 데이터 일관성 관리의 복잡성을 경험했습니다.
5. DevOps 및 모니터링
Prometheus + Grafana 조합으로 종합적인 모니터링 시스템을 구축하며, 실제 서비스 운영에 필요한 메트릭 수집과 알림 체계를 설계했습니다. API 성능, 데이터베이스 상태, LLM 사용량 등 다양한 지표를 통합 관리하는 경험을 쌓았습니다. Docker 기반 컨테이너화를 통해 개발부터 배포까지 일관된 환경을 구축하고, 인프라스트럭처의 코드화(IaC) 개념을 실무에 적용했습니다.
6. 제품 사고 및 비즈니스 이해
기술적 구현뿐만 아니라 사용자 문제 정의부터 해결책 설계까지 전체 제품 개발 과정을 주도적으로 경험했습니다. MOOC 완료율 문제라는 실제 시장 페인포인트를 분석하고, AI 기술을 활용한 창의적 해결책을 도출하는 과정에서 제품 사고력을 크게 향상시켰습니다.
확장성을 고려한 설계를 통해 개인 사용자에서 기업 고객으로의 자연스러운 비즈니스 확장 가능성을 미리 준비하는 전략적 사고를 기를 수 있었습니다.
향후 발전 방향
기술적 확장
마이크로서비스 아키텍처로의 전환을 통해 각 도메인을 독립적인 서비스로 분리하고, 서비스 간 통신과 데이터 일관성 관리 방안을 구체화할 예정입니다. 현재의 모듈 구조가 MSA 전환의 좋은 기반이 될 것으로 생각합니다.
또한 실시간 기능 강화를 위해 WebSocket 기반 실시간 알림 시스템과 협업 학습 기능을 추가할 계획입니다. 학습 진도 공유, 실시간 토론, 그룹 스터디 기능 등으로 소셜 학습 경험을 한층 향상시킬 예정입니다.
추가로 AI 모델 고도화를 통해 자체 LLM 파인튜닝과 RAG(Retrieval-Augmented Generation) 시스템을 구축하여 더욱 정확하고 맥락화된 학습 지원을 제공할 계획입니다.
비즈니스 확장
B2B 시장 진출을 위한 기업 교육 특화 기능 개발에 집중할 예정입니다. 신입사원 온보딩 프로그램, 직무별 교육 커리큘럼, 학습 성과 분석 도구 등을 통해 기업 고객 시장에 진입할 계획입니다.
운영은 마켓플레이스 구축을 통해 전문가가 제작한 고품질 커리큘럼을 판매하는 생태계를 조성하고, 플랫폼의 콘텐츠 품질과 다양성을 크게 향상시킬 예정입니다.
추가로 글로벌 서비스 확장을 위한 다국어 지원과 지역별 커스터마이징을 준비하여 해외 시장 진출 기반을 마련할 계획입니다.
결론 및 시사점
기술적 가치
LLearn 프로젝트를 통해 현대적인 백엔드 아키텍처와 AI 기술을 통합하여 하나의 상품으로 개발하였습니다. Clean Architecture를 통한 확장 가능한 설계부터 LLM을 활용한 실질적인 비즈니스 가치를 창출하는 좋은 경험이였습니다. 또한 비동기 시스템 구축 등 실제 서비스에 적용 가능한 기술들을 경험했습니다.
특히 AI 서비스의 프로덕션 운영에 필요한 관측성, 안정성, 비용 최적화 등의 실무 노하우를 축적할 수 있었습니다. 이를 통해 AI 기반 서비스의 개발에 더욱 기여할 수 있을 것이라 생각합니다.
단순한 기술 데모를 넘어 실제 사용자 문제를 해결하겠다는 의미로 서비스를 구축해보았습니다. MOOC 완료율 문제라는 명확한 시장의 pain point를 분석하고, AI 기술을 활용한 창의적 해결책을 LLearn 서비스 개발로 제시할 수 있었습니다.
개인 학습자에서 기업 고객으로의 비즈니스 확장 가능성을 설계에 반영하여 향후 사업 확장 시 기술적 부채 없이 자연스럽게 개발, 확장 할 수 있는 기반까지 마련했던 좋은 기회였습니다.
개인적 성장
이 프로젝트를 통해 AI 서비스 기술을 종합적으로 역량을 크게 향상시킬 수 있었습니다. 백엔드 아키텍처 설계부터 AI 서비스 통합, 성능 최적화, 운영 모니터링까지 AI 서비스의 백엔드를 실무 단계와 비슷하게 경험을 쌓았으며 특히 제품 사고와 비즈니스 이해도를 한층 발전시킬 수 있었습니다.
LLearn은 AI 시대의 교육 혁신을 기술로 실현한 의미 있는 프로젝트로, 향후 더 많은 학습자들이 효과적으로 성장할 수 있는 플랫폼으로 발전시켜 나갈 계획입니다.