👋 개요
앞에서 GCP에 적용하기로 한 뉴스 요약 앱을 만들기 위한 여정을 두 단계로 나누어 정리한다.
- 1단계는 Google Cloud 기반의 백엔드 구축과 자동화에 중점을 두었고,
- 2단계는 Firebase 인증과 React Native Expo 앱을 개발하여 실제 사용자 경험을 다듬은 단계입니다.
✅ 1단계: Cloud 기반 백엔드 + 뉴스 요약 자동화
🎯 목표
- Google News에서 원하는 키워드로 뉴스 수집
- Gemini API를 활용한 요약 처리
- 사용자별 요약 결과 저장
- 자동 실행 및 확장 가능한 구조로 구축
🧱 주요 기술 스택
구성 요소 |
기술/서비스 |
설명 |
뉴스 수집 |
Python (requests , bs4 ) |
Google News 크롤링 |
요약 처리 |
Gemini Flash API |
텍스트 요약 모델 호출 |
API 서버 |
FastAPI + Cloud Run |
RESTful API 제공 |
데이터 저장 |
Firestore (NoSQL) |
사용자별 키워드 및 요약 결과 저장 |
인증 |
Firebase Authentication |
Google 로그인 기반 사용자 인증 |
예약 실행 |
Cloud Scheduler + Functions |
키워드별 뉴스 수집/요약 자동 실행 |
배포 |
GitHub Actions + Cloud Build |
CI/CD 파이프라인 |
🔄 동작 흐름 요약
- 사용자가 관심 키워드를 등록
- Cloud Scheduler가 주기적으로 트리거 발행
- Cloud Function이 사용자별 Keyword를 취합하고 Pub/Sub을 통해서 FastAPI의
/summary
API 호출
- 결과를 Firestore에 사용자별로 저장
📁 예시 Firestore 스키마
{
"users": {
"userId123": {
"keywords": {
"AI": {
"2025-07-06": {
"title": "OpenAI launches GPT-5",
"summary": "OpenAI unveiled GPT-5 today with multimodal capabilities..."
}
}
}
}
}
}
특이 사항
이 때, 특이 사항으로는 사용자 Id에서도 document를 만들지 않으면 접근이 되지 않는 부분이 있어서 debugging에 어려움이 있었다. 문제는 아래의 코드에서 를 통해서 keywords_ref = db.collection("users").document(uid).collection("keywords")
를 통해서 Firebase에 접근하려고 할 때, 데이터가 읽히지 않는 것이었다. 이는 uid
수준에 document가 없기 때문이었다.
def fetch_all_user_keywords():
db = firestore.Client()
users = db.collection("users").stream()
users_list = list(users)
result = []
for user in users_list:
uid = user.id
keywords_ref = db.collection("users").document(uid).collection("keywords")
keywords = [doc.to_dict()["keyword"] for doc in keywords_ref.stream()]
if keywords:
result.append({"user_id": uid, "keywords": keywords})
print(f"result {result}")
return result
여러가지 실험들이 있었고, 그 실험을 통해서 문제점에 대해서 이해하고 Database에 keyword를 추가할 때, 상위 user document가 없다면 빈 document를 만드는 코드를 추가하여, 문제가 해결되는 것을 확인하였다.
def add_keyword(user_id: str, keyword: str) -> str:
# ✅ 상위 user 문서가 없다면 빈 문서라도 생성 (merge=True)
db.collection("users").document(user_id).set({}, merge=True)
keyword_ref = db.collection("users").document(user_id).collection("keywords")
existing = keyword_ref.where("keyword", "==", keyword).limit(1).stream()
if any(existing):
raise ValueError("Keyword already exists")
doc_ref = keyword_ref.document()
doc_ref.set({
"keyword": keyword,
"created_at": datetime.utcnow().isoformat()
})
return doc_ref.id
✅ 2단계: React Native 앱으로 사용자 경험 구현
🎯 목표
- 사용자 로그인
- 키워드 등록 및 요약 리스트 보기
- 앱 내에서 요약 결과 확인
- 다크/라이트 모드 지원
🧱 주요 기술 스택
구성 요소 |
기술/서비스 |
설명 |
프레임워크 |
React Native (Expo) |
크로스 플랫폼 앱 개발 |
인증 |
Firebase Authentication |
Google 로그인 연동 |
데이터 통신 |
REST API (FastAPI) |
백엔드와 데이터 연동 |
앱 배포 |
EAS Build + Expo Go |
Android/iOS 앱 테스트 및 배포 |
디자인 |
React Native Paper |
테마 기반 다크/라이트 모드 지원 |
📱 주요 UI 기능
- 🔑 로그인 화면: Firebase 인증 기반
- 📝 키워드 입력: 관심 주제 등록
- 📄 요약 리스트: 날짜별 요약 보기
- 🎨 다크/라이트 모드: 시스템 설정 연동
- 🚫 백버튼 제어: 앱 종료 버튼으로 대체
💡 화면 예시 흐름
- 로그인 화면
- → 요약 리스트 화면
- → 키워드 등록 화면
특이 사항
Frontend 개발 시 특이 사항은 React Native Expo였다. Web 기반 React를 다룰 때도 그랬지만, 가이드가 최신 버전과 충돌이 있는 부분이 있었다. Web에서 Tailwindcss의 초기 설정이 달라져서 적절한 설정을 찾는데 어려움이 있었던 것과 같이 Expo의 SDK 최신이 53이었는데 Firebase 연동에 문제가 있다는 것을 알았다(1). 그래서, SDK 버전을 52로 낮추고 Expo Go 앱도 낮은 버전 찾아서 설치하면서 문제를 해결했다.
React Native Expo의 중간 테스트는 Expo Go라는 앱으로 로컬에서 실행하는 내용을 가져와서 테스트하기 때문에 로컬 서버가 항상 동작하고 있어야했다. 이것은 중간 테스트하는 결과물이고 최종 결과물은 Android 혹은 iOS에서 동작하는 결과물을 만들어야 하는 것이다. 이 결과물을 만드는 과정을 EAS(Expo Application Service) build라고 불렀다. 실재로 코드가 github에 있어야했고, 서버에서 빌드하는 과정이 필요하다 그리고, Free 모델에서는 Queue에 2시간 대기 하고 나서 빌드하는데 Fail이 발생하면 결과를 최소 2시간 이후에 알 수 있어서 동작하는 버전을 처음 얻는데 까지 이틀 가까이 걸렸다.
🔚 마무리: 확장 가능성과 다음 단계
이 프로젝트는 다음과 같은 방향으로 확장 가능하고 고민해보고 있다:
- 🔐 다른 사용자 인증 지원: Google account와 같은 OAuth 2.0 연동. 이를 통한 가입의 유연성 증대
- 📈 요약 품질 개선: Selenium으로 News를 가져오고 Gemini Pro 또는 LLM fine-tuning 도입
- 🔊 TTS 기능: 요약 내용을 음성으로 읽어주는 기능
- 📡 푸시 알림: 새로운 뉴스 요약이 도착했을 때 알림 제공
✨ 느낀 점
Cloud 기반 자동화와 모바일 내이티브 앱을 한 프로젝트 안에서 다뤄본 덕분에, 서비스 기획부터 운영까지 전 과정을 경험할 수 있었다. 특히 Pub/Sub, Cloud Function, Firestore를 연결하는 구조가 매우 유연하면서도 확장성 있게 느껴졌다. 나에게도 유용한 기능이어서 나만의 서비스로 활용하고 있다. 조금 더 확장하면 실재로 타인들에게도 공개해서 피드백 받을 수 있는 기능으로 확장도 가능하겠다.
참고 문헌
[1] https://www.inflearn.com/community/questions/1581981/expo-%EA%B0%80-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EB%90%98%EB%A9%B4%EC%84%9C-%EB%AC%B8%EC%A0%9C%EA%B0%80-%EB%B0%9C%EC%83%9D%ED%95%9C%EA%B1%B0%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?srsltid=AfmBOopaM9vHkoH-TpxDm6dFG6jVK585QCe4zMDbJ_LatRew-t_iiVP1
[2] https://github.com/blcktgr73/GCPNewsPortal