2025 Asia Impact Hackathon : 디지털 기술과 AI 기술을 활용하여 공공 과제를 해결하는 것에 주 목적을 둔다.
"동일한 사건이더라도, 각국의 이해관계에 따라 기사들은 다르게 작성된다."
(1) 정보 편향 (격차), (2) 정보 접근성, (3) 관점의 다양성
![]() 컴퓨터공학과 김온유 |
![]() 소프트웨어학과 김주영 |
|---|
개발 기간 : 2025 3/17 ~ 4/13
전 세계 다양한 국가의 뉴스 데이터를 자동으로 수집하고,
이를 기반으로 AI가 요약 및 질의응답 기능을 제공하는 글로벌 뉴스 플랫폼입니다.
| 분류 | 기술 |
|---|---|
| Backend | Spring Boot (Java 17), JPA, Lombok |
| Infra (CI / CD) | GitHub Actions, Docker, DockerHub, EC2 |
| Database | MySQL, Redis |
| 인증 | Google OAuth2, JWT (jjwt) |
| AI / API | Google Gemini API, Google RSS & Cloud Translation, News API |
| Etc. | Jsoup (crawling), Swagger |
해커톤 제출 버전 기준 커밋:
43639bf
- GitHub Actions를 이용해 빌드 → Docker 이미지 생성 → DockerHub Push 자동화
- EC2 서버에서
docker pull을 통해 최신 버전으로 자동 배포
-
초기에는
Google RSS로 국가별 트렌드 키워드 수집에만 활용 -
News API 무료 플랜의 한계 (미국(
us) 단일 국가만 실질적 데이터 반환)로 인해, 다국어·다국가 수집을 RSS 파이프라인으로 전환·확장 -
6시간 주기 스케줄링으로 자동 수집 및 DB 적재
수집 대상 언론사 및 국가
| 국가 | 언론사 | 언어 | 제공 카테고리 |
|---|---|---|---|
| 🇬🇧 영국 | BBC | 영어 | 일반, 경제, 기술, 과학, 건강, 문화, 스포츠 |
| 🇰🇷 한국 | 연합뉴스 | 한국어 | 일반, 정치, 기술, 건강, 문화, 스포츠 |
| 🇯🇵 일본 | NHK | 일본어 | 일반, 경제, 과학, 스포츠 |
| 🇫🇷 프랑스 | France24 | 프랑스어 | 일반, 경제, 스포츠 |
| 🇩🇪 독일 | Deutsche Welle | 독일어/영어 | 일반, 경제, 과학, 스포츠, 문화 |
| 🇸🇦 중동 | BBC Arabic | 아랍어 | 일반, 경제, 스포츠, 기술 |
| 🇨🇳 중국 | South China Morning Post | 영어 | 일반, 경제, 기술, 스포츠 |
| 🇪🇸 스페인어권 | BBC Mundo | 스페인어 | 일반, 경제, 과학, 스포츠 |
⚠️ 근본적 한계
본 서비스의 핵심 의의는 "동일한 사건을 각국의 시선으로 비교" 하는 것이었으나,
각 RSS 피드는 갱신 주기·기사 선택 기준이 언론사마다 상이하여
동일 이슈에 대한 국가별 기사를 정확히 매핑하는 것이 구조적으로 어렵다는 한계가 존재.
국가·카테고리별 데이터셋을 최대한 폭넓게 수집하여 제공하도록 수정정.
NewsAPI.org를 사용해 실시간 헤드라인 및 키워드 기반 기사 수집- 키워드 기반 검색 및 필터링 지원
무료 플랜 한계로 인한 운영 전략
News API 무료 플랜은us단일 국가만 실질적인 데이터를 반환하므로,
다국가 수집은 RSS 파이프라인으로 위임하고 News API는 미국 기사 수집에 집중.
top-headlines엔드포인트: 미국(us) 기준 카테고리별 헤드라인 수집 (general, business, entertainment, health, science, sports, technology)everything엔드포인트: 미국만 유지, 타 국가는 대표 도메인을 직접 지정하여 심층 기사 수집 (RSS 로 전환 -> NEWS.API 는 Free Plan 기반 타 국가 데이터 제공 X)
| 도메인 | 언론사 |
|---|---|
wsj.com |
Wall Street Journal (미국) |
bbc.co.uk |
BBC (영국) |
techcrunch.com |
TechCrunch (미국) |
theguardian.com |
The Guardian (영국) |
reuters.com |
Reuters (글로벌) |
aljazeera.com |
Al Jazeera (중동) |
서비스의 핵심 의의: "동일한 사건이더라도, 각국의 이해관계에 따라 기사들은 다르게 작성된다."
특정 기사를 읽을 때, 같은 이슈를 다루는 다른 나라 언론사의 기사를 나란히 보여주는 기능.
** 구현된 동작 방식 (키워드 기반 FULLTEXT 매칭)**
- 기사 제목을 공백·구두점 기준으로 단어 분리
- 2글자 이하 단어 제거
- 사전 정의된 영어 Stop Words 제거 (
the,is,for,and등 70여 개) - 중복 제거 후 앞에서 최대 4개 키워드 추출
- 앞 2개는 필수(
+keyword), 나머지는 선택 조건으로 MySQLFULLTEXT BOOLEAN MODE검색 - 비영어 기사는 Google Translation API로 제목을 영어로 번역 후 키워드 재추출 → 영어권 기사까지 탐색
- 국가별로 그룹핑하여 최대 3개 기사 반환, 결과는 Redis에 1시간 캐싱
⚠️ 구조적 한계1. 다국어 키워드 매칭 문제
현재 RSS 파이프라인 확장으로 한국어·일본어·프랑스어·아랍어 등 다국어 기사가 DB에 적재되어 있으나,
FULLTEXT 매칭은 동일 언어의 동일 단어가 등장해야 히트됨.
완전한 해결을 위해서는 추출한 키워드를 DB에 저장된 모든 국가의 언어(8개 언어)로 각각 번역해 탐색해야 하지만,
번역 API 비용·응답 속도 문제로 현실적으로 어렵다.
→ 현재 구현: 비영어 기사의 제목을 영어로 1회 번역하여 영미권 기사까지만 크로스 탐색.
한국어 기사에서 perspectives를 조회하면 영어 기사는 찾아주지만, 일본어·아랍어 기사는 여전히 탐색되지 않는다.2. 해커톤 제출 / 리팩토링 현황 비교
해커톤 제출 버전(43639bf)에서는 News API 무료 플랜 한계로 사실상 영어 데이터만 수집되어 있었기 때문에
다국어 매칭 문제 자체가 존재하지 않음. (당시, 단일 언어였기에 근본적인 관점 비교가 불가능) RSS 파이프라인 확장 -> 다국어 데이터셋을 보유하며 이슈가 생기게 됨.3. 이슈 단위 매핑의 어려움
표현이 다르거나 국내 한정 이슈일 경우 perspectives가 비어있는 것은 자연스러운 동작.
오히려 글로벌 이슈일수록 더 풍부한 비교가 가능한 것이 서비스 특성.
진정한 "이슈 단위" 매핑은 의미적 유사도 기반 검색 엔진 도입이 필요.
➕ 향후 개선 가능
- Elasticsearch 도입 시 의미적 유사도 기반 검색으로 커버리지 확대
- 벡터 DB 기반 유사 기사 탐색: 기사 본문을 임베딩 벡터로 변환 후 코사인 유사도로 매칭
→pgvector(PostgreSQL 확장),Weaviate,Pinecone등 벡터 DB 활용 가능 - MSA 분리 고려: 기사 수집·저장 / AI 처리 / 검색을 독립 마이크로서비스로 분리하면
각 서비스별 언어·프레임워크 최적화 가능 (예: 검색 서비스는 Python + LangChain / FastAPI 조합)
- 전역적으로 언어 상태를 관리하는 시스템 구축
- 사용자 요청에 따라 번역 또는 해당 언어 기사만 반환
- (언어 상태 관리는 FE 전역 상태에서 처리)
이하 기능은 해커톤 이후 리팩토링 및 확장 작업 (2026.03 ~)
Jsoup을 통해 기사 본문, 이미지, 설명, 제목 등 메타데이터 추출- AI 모델 OpenAI GPT → Google Gemini (
gemini-2.5-flash) 로 마이그레이션 - 최초 요약 후 DB 영속 저장 (이후 재요청 시 캐싱된 결과 반환)
- 기사 내용을 기반으로 Gemini API에 전달하여 실시간 스트리밍 질의응답 제공
- AI 모델 OpenAI GPT → Google Gemini 로 마이그레이션
- 로그인 유저: 이전 대화 내역을 슬라이딩 윈도우(최근 10턴) 방식으로 누적 전달 → 맥락 기반 대화
- 비로그인 유저: 단일 질의로 처리
- Google 소셜 로그인으로 간편 인증 (글로벌 서비스 특성에 맞게 Google 단일 제공)
- 로그인 성공 시 JWT 발급 → 이후 모든 인증 필요 API에 Bearer 토큰으로 활용
- 로그인 유저의 질의/응답을 기사별로 DB에 저장
- 기사별 마지막 대화 미리보기 목록 조회 API 제공 (팝업 리스트용)
- 특정 기사의 전체 대화 내역 조회 API 제공 (기사 상세 페이지용)
- 비로그인: 기존 브라우저 localStorage 기반 스크랩 유지
- 로그인 유저: 스크랩 데이터를 서버 DB에 영속 저장, 기기 간 동기화 가능
- 스크랩 토글(추가/취소), 내 스크랩 목록 조회, 스크랩 여부 확인 API 제공
기능 추가 과정에서 잠재적 장애 요소 개선.
-
RestTemplate 타임아웃 설정
기본RestTemplate은 타임아웃 없이 외부 API 무한 대기 가능
→connectTimeout 3s / readTimeout 5s설정 추가 -
news-fetch 플래그 도입
로컬 개발 중 서버 기동 시마다 News API / RSS 수집이 실행되어 API 할당량 낭비
→news-fetch.enabled: false플래그로 로컬에서 수집 비활성화 가능 -
중복 기사 사전 필터링
RSS 수집 시 건별SELECT로 중복 확인하던 방식
→ URL 목록 일괄 조회(findExistingUrls) 후 메모리에서 필터링, DB 쿼리 수 감소 -
Perspectives Redis 캐싱
FULLTEXT 검색 + 번역 API 호출이 매 요청마다 발생
→ 결과를 Redis에 1시간 캐싱하여 응답 속도 개선 및 외부 API 호출 절감
프로젝트 루트에 .env 파일을 생성하고, .env.example을 복사/수정해서 사용.
# DB
MYSQL_ROOT_PASSWORD=localpw
MYSQL_DATABASE=globaltimes
LOCAL_MYSQL_DATABASE=globaltimes
LOCAL_MYSQL_USER=root
LOCAL_MYSQL_PASSWORD=localpw
# API Keys
NEWS_API_KEY=your_news_api_key
GEMINI_API_KEY=your_gemini_api_key
GOOGLE_API_KEY=your_google_api_key
# OAuth2 (Google)
GOOGLE_OAUTH_CLIENT_ID=your_google_client_id
GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret
OAUTH2_REDIRECT_URI=http://localhost:5173/oauth/callback
# JWT
JWT_SECRET=minimum-32-characters-random-stringdocker compose -f docker-compose.dev.yml up -d
docker compose -f docker-compose.dev.yml ps # 상태 확인
docker compose -f docker-compose.dev.yml down # 종료데이터 완전 초기화:
docker compose -f docker-compose.dev.yml down -v
.\gradlew.bat bootRun- Swagger UI:
http://localhost:8080/swagger-ui/index.html - OAuth2 로그인 테스트:
http://localhost:8080/oauth2/authorization/google
main ← 배포용 (직접 push 금지)
└── develop ← 통합 브랜치 (PR merge 대상)
└── feat/#이슈번호-작업명 ← 기능 단위 브랜치
git switch develop
git pull
git switch -c feat/#이슈번호-작업명
# 첫 push 시 upstream 설정
git push -u origin HEAD
# 이후
git push
