RSS 피드를 한눈에 관리하고 조회할 수 있는 웹 애플리케이션입니다.
PREVIEW_260120.1.mp4
FeedHub/
├── feed-hub-common/ # 공통 모듈 (도메인, Command/Event)
├── feed-hub-api/ # Spring Boot REST API 서버
├── feed-hub-collector/ # RSS 수집 및 블로그 크롤링 (Kafka Consumer)
├── feed-hub-scheduler/ # 스케줄러 (정기 동기화)
└── feed-hub-ui/ # React 프론트엔드
Java 21
Spring Boot 4.0.1
공유 도메인 모델 및 Kafka 메시지 정의
Java 21
Spring Boot 4.0.1
Spring Security + JWT
Spring Data JPA
QueryDSL 5.1.0
PostgreSQL
Flyway (DB 마이그레이션)
Apache Kafka (Producer)
Spring Cloud AWS (Parameter Store)
Lombok
Collector (feed-hub-collector)
Java 21
Spring Boot 4.0.1
Spring Kafka (Consumer/Producer)
Spring Data JPA
Rome RSS Parser
Jsoup (HTML 파싱)
OkHttp3
Resilience4j (Circuit Breaker)
Spring Cloud AWS (Parameter Store)
Scheduler (feed-hub-scheduler)
Java 21
Spring Boot 4.0.1
Spring Kafka (Producer)
Spring Scheduling
React 19 + TypeScript
React Router DOM
Vite
Axios
이메일/비밀번호 기반 회원가입
JWT 토큰 기반 로그인
로그인 상태 유지
역할 기반 권한 (USER/ADMIN)
2. RSS 소스 관리
RSS 소스 등록/수정/삭제/조회
OPML 파일 가져오기/내보내기
개별/전체 RSS 동기화
블로그 타입 자동 감지 (Tistory, Medium, Velog, GitHub Blog 등)
크롤링 URL 별도 지정 가능
전체 피드 목록 조회
RSS 소스별 필터링
태그별 필터링 (OR 조건)
제목/내용 텍스트 검색
커서 기반 페이지네이션 (무한 스크롤)
피드 카드에서 바로 미리보기
플로팅 모달로 description 표시
ESC 키 또는 X 버튼으로 닫기
모달 내 원문보기 버튼
로그인 사용자별 개인 태그
피드에 태그 추가/삭제
태그 클릭으로 필터링
피드별 읽음 상태 표시 (로그인 시)
제목/미리보기/원문보기 클릭 시 읽음 처리
조회수 카운팅 (중복 방지)
피드별 좋아요 토글
집계된 좋아요 수 표시
하트 아이콘 버튼 (피드 카드 우측)
문의 유형: 일반문의 / 기능요청 / 버그신고 / RSS추가요청
비밀글 지원 (작성자와 관리자만 열람)
관리자 답변 기능
내 QnA 목록 조회
? 버튼을 통한 빠른 문의 작성
플로팅 버튼을 통한 관리자 모달
RSS 소스 추가/수정/삭제
태그 추가/삭제
OPML 가져오기/내보내기
크롤링 요청
전체 QnA 관리
Kafka 기반 비동기 크롤링
블로그 타입별 전용 크롤러 (Tistory, Velog, Medium, GitHub Blog)
Rate limiting 및 재시도 로직
크롤링 이력 관리 (sync_history)
사용자별 RSS 소스 구독 관리
구독한 소스의 피드만 조회 가능
개인화된 피드 제공
정기적인 RSS 동기화 (매 시간)
전체 크롤링 (매일 새벽 2시)
Kafka 기반 비동기 작업 분산
Method
Path
설명
POST
/api/v1/auth/signup
회원가입
POST
/api/v1/auth/signin
로그인
GET
/api/v1/auth/check-email
이메일 중복 확인
GET
/api/v1/auth/me
현재 사용자 정보
RSS 소스 관리
Method
Path
설명
POST
/api/v1/rss-sources
RSS 소스 등록
GET
/api/v1/rss-sources
전체 RSS 소스 조회
PUT
/api/v1/rss-sources/{id}
RSS 소스 수정
DELETE
/api/v1/rss-sources/{id}
RSS 소스 삭제
POST
/api/v1/rss-sources/{id}/sync
개별 동기화
POST
/api/v1/rss-sources/sync-all
전체 동기화
POST
/api/v1/rss-sources/{id}/crawl
개별 크롤링 요청
POST
/api/v1/rss-sources/crawl-all
전체 크롤링 요청
POST
/api/v1/rss-sources/import/opml
OPML 가져오기
GET
/api/v1/rss-sources/export/opml
OPML 내보내기
Method
Path
설명
POST
/api/v1/tags
태그 생성
GET
/api/v1/tags
전체 태그 조회 (사용자별)
DELETE
/api/v1/tags/{id}
태그 삭제
Method
Path
설명
GET
/api/v1/feeds
피드 검색 (rssSourceIds, tagIds, query, lastId, lastPublishedAt, size)
PUT
/api/v1/feeds/{id}/tags
피드 태그 업데이트
POST
/api/v1/feeds/{id}/view
읽음 처리 및 조회수 증가
POST
/api/v1/feeds/{id}/like
좋아요 토글
Method
Path
설명
POST
/api/v1/qna
질문 등록
GET
/api/v1/qna
내 QnA 목록
GET
/api/v1/qna/all
전체 QnA 목록 (관리자)
GET
/api/v1/qna/{id}
QnA 상세
DELETE
/api/v1/qna/{id}
QnA 삭제
POST
/api/v1/qna/{id}/answer
답변 등록 (관리자)
-- 회원
member (id, email, password, nickname, role, created_at, updated_at)
-- RSS 소스 정보
rss_info (id, blog_name, author, rss_url, site_url, crawl_url, language, blog_type, created_at, last_sync_at)
-- 구독 (사용자별 RSS 소스 구독)
subscription (id, member_id, rss_info_id, subscribed_at)
-- 태그 (사용자별)
tag (id, member_id, name, created_at)
-- RSS 소스-태그 연결 (다대다)
rss_info_tag (rss_info_id, tag_id)
-- 피드 엔트리
feed_entry (id, rss_info_id, title, link, description, author, published_at, guid, created_at, view_count)
-- 피드 엔트리-태그 연결 (다대다)
feed_entry_tag (feed_entry_id, tag_id)
-- 회원 피드 읽음 기록
member_feed_read (id, member_id, feed_entry_id, read_at)
-- 피드 좋아요
feed_like (id, member_id, feed_entry_id, created_at)
-- 동기화 이력
sync_history (id, rss_info_id, sync_type, status, started_at, completed_at, error_message, feed_count)
-- QnA
qna (id, member_id, type, title, content, is_secret, status, created_at, updated_at)
-- QnA 답변
qna_answer (id, qna_id, member_id, content, created_at)
Java 21+
Node.js 18+
PostgreSQL
Apache Kafka
# 프로젝트 빌드
./gradlew :feed-hub-api:build
# 애플리케이션 실행
./gradlew :feed-hub-api:bootRun
Note : application.yml에서 데이터베이스 연결 정보와 JWT 시크릿 키를 설정하세요.
# 빌드
./gradlew :feed-hub-collector:build
# 실행
./gradlew :feed-hub-collector:bootRun
# 빌드
./gradlew :feed-hub-scheduler:build
# 실행
./gradlew :feed-hub-scheduler:bootRun
다음 파라미터를 AWS Parameter Store에 등록:
/feedhub/postgresql/username: PostgreSQL 사용자명
/feedhub/postgresql/password: PostgreSQL 비밀번호
/feedhub/jwt/key: JWT Secret Key
export AWS_REGION=ap-northeast-2
export DB_URL=jdbc:postgresql://your-db:5432/feed_hub
export KAFKA_BOOTSTRAP_SERVERS=your-kafka:9092
# API 서버
java -jar feed-hub-api.jar --spring.profiles.active=prod
# Collector
java -jar feed-hub-collector.jar --spring.profiles.active=prod
# Scheduler
java -jar feed-hub-scheduler.jar --spring.profiles.active=prod
cd feed-hub-ui
# 의존성 설치
npm install
# 개발 서버 실행 (port 3000)
npm run dev
# 프로덕션 빌드
npm run build
feed-hub-ui/src/
├── api/
│ └── client.ts # API 클라이언트 (axios, 토큰 관리)
├── types/
│ └── index.ts # TypeScript 타입 정의
├── components/
│ ├── FeedCard.tsx # 피드 카드 컴포넌트
│ ├── FeedList.tsx # 피드 목록 컴포넌트
│ ├── FilterBar.tsx # 필터 바 (RSS 소스, 태그, 검색)
│ ├── ContentPreviewModal.tsx # 컨텐츠 미리보기 모달
│ ├── TagSelectModal.tsx # 태그 선택 모달
│ ├── AuthModal.tsx # 로그인/회원가입 모달
│ ├── AdminModal.tsx # 관리자 모달
│ ├── AdminButton.tsx # 플로팅 관리 버튼
│ ├── QnaButton.tsx # 플로팅 QnA 버튼
│ └── UserMenu.tsx # 사용자 햄버거 메뉴
├── pages/
│ ├── HomePage.tsx # 메인 피드 목록 페이지
│ ├── QnaListPage.tsx # QnA 목록 페이지
│ ├── QnaWritePage.tsx # QnA 작성 페이지
│ └── QnaDetailPage.tsx # QnA 상세 페이지
├── App.tsx # 메인 앱 (라우터)
└── App.css # 앱 스타일
feed-hub-api/src/main/java/world/jerry/feedhub/api/
├── domain/ # 도메인 레이어
│ ├── rss/ # RssInfo 엔티티, 리포지토리
│ ├── tag/ # Tag 엔티티, 리포지토리
│ ├── feed/ # FeedEntry, FeedLike, MemberFeedRead 엔티티, 리포지토리
│ ├── member/ # Member 엔티티, 리포지토리
│ └── qna/ # Qna, QnaAnswer 엔티티, 리포지토리
├── application/ # 애플리케이션 레이어
│ ├── rss/ # RssInfoService, DTO
│ ├── tag/ # TagService, DTO
│ ├── feed/ # FeedQueryService, FeedEntryService, DTO
│ ├── auth/ # AuthService, DTO
│ └── qna/ # QnaService, DTO
├── infrastructure/ # 인프라 레이어
│ ├── persistence/ # JPA 구현체, QueryDSL
│ ├── security/ # JWT, Spring Security 설정
│ ├── kafka/ # Kafka Producer
│ └── config/ # QueryDSL 설정
└── interfaces/ # 인터페이스 레이어
├── rest/ # REST 컨트롤러
└── common/ # 공통 (GlobalExceptionHandler)
feed-hub-collector/src/main/java/world/jerry/feedhub/collector/
├── domain/ # 도메인 모델
├── application/ # 서비스 레이어
├── infrastructure/ # Kafka Consumer, JPA 리포지토리
├── crawler/ # 블로그 타입별 크롤러
│ ├── BlogCrawler.java # 크롤러 인터페이스
│ ├── TistoryCrawler.java # 티스토리 크롤러
│ ├── VelogCrawler.java # Velog 크롤러
│ ├── MediumCrawler.java # Medium 크롤러
│ └── GithubBlogCrawler.java # GitHub Blog 크롤러
└── config/ # 설정
feed-hub-scheduler/src/main/java/world/jerry/feedhub/scheduler/
├── scheduler/ # 스케줄러
│ └── FeedSyncScheduler.java # RSS 동기화/크롤링 스케줄러
└── config/ # Kafka 설정
EDA (Event-Driven Architecture) 기반 MSA
Kafka를 통한 모듈 간 느슨한 결합
Command/Event 패턴으로 비동기 처리
Fan-out 구조로 확장 가능한 크롤링
MIT License