우리의 기도 앱의 백엔드 서버입니다.
- 운영 기간: 2025.02 ~ 운영 중
- MAU: 100+
- 주요 기술: AWS Serverless, Node.js 22, MySQL, SQS, Expo Push
- ios : https://apple.co/4qQupBh
- andorid : http://bit.ly/49RsfLu
모바일 앱의 핵심 사용자 흐름(인증, 플랜/강의 조회, 기도 기록, 질문/답변)을 안정적으로 제공하는 서버를 설계하고 운영했습니다.
서버 아키텍처는 AWS Serverless(API Gateway + Lambda + SQS)를 채택했습니다. 1인 개발 특성상 서버 증설, 런타임 운영, 장애 대응 같은 클라우드 인프라 관리 부담이 크기 때문에, 인프라 운영 포인트를 줄이고 기능 개발에 집중할 수 있는 구조를 우선 선택했습니다.
주요 기능:
- 사용자 인증 및 세션 관리
- 기도 플랜/강의/오디오 조회
- 기도 기록 저장 및 상세 조회
- 질문/답변 기능과 관리자 푸시 알림
- API Gateway:
ourprayer1개 - Lambda Function: 8개
user,bible,history,lecture,question,plan,appInfo,notificationTrigger
- Lambda Layer: 2개
jwt,mysql2
- Queue: SQS
notification1개 - Runtime:
nodejs22.x,arm64 - API 엔드포인트: 30개
관련 코드 위치:
template.yml
sequenceDiagram
participant U as User
participant API as API Gateway
participant Q as Lambda question
participant DB as MySQL
participant MQ as SQS notification
participant W as Lambda notificationTrigger
participant E as Expo Push
participant A as Admin Device
U->>API: POST /question or POST /question/reply
API->>Q: Invoke
Q->>DB: Insert question/reply
Q->>MQ: SendMessage(Type, Method, Body)
MQ->>W: Trigger by SQS event
W->>DB: Read admin expo_push_token
W->>E: Send push notification
E->>A: Deliver notification
현재 question/reply 워커 구현은 관리자(role = 'admin') 토큰 대상으로 동작합니다.
관련 코드 위치:
function/question/question.tsfunction/question/reply.tsfunction/notificationTrigger/handler.tsfunction/notificationTrigger/pushServer.ts
운영 비용을 줄이기 위해 인프라를 단계적으로 전환했습니다.
RDS -> EC2 + Docker + MySQL -> 온프레미스 (Raspberry Pi 5) + MySQL
- 1단계: RDS
- 2단계: EC2 + Docker + MySQL
- 3단계: 온프레미스 (Raspberry Pi 5) + MySQL
| 단계 | 월평균 비용($) | 직전 단계 대비 증감 | 전환 이유 | 블로그 |
|---|---|---|---|---|
| (AWS) RDS + Lambda + SQS + S3 | 26.67 | - | - | - |
| (AWS) EC2(MySQL) + Lambda + SQS + S3 | 16.12 | -10.55 USD(약 -39.6%) | DB 운영비 절감 시도 | 👉 AWS 클라우드 비용 36% 줄였던 경험 |
| (온프레미스 - Raspberry Pi 5) MySQL, (AWS) Lambda + SQS + S3 | 0.1 | -16.02 USD(약 -99%) | DB 운영비 절감 시도 | - |
핵심 동작:
- 회원 등록 시
user,user_state,refresh_token를 트랜잭션으로 생성 - Access Token 만료시간은
1h - 보호 API에서 Access Token 검증 실패 시 Refresh Token으로 재발급 시도
- 재발급 성공 시
401응답에 새accessToken포함
관련 코드 위치:
function/user/auth/register.tslayer/jwt/customJwt/index.tsfunction/user/user.ts
핵심 동작:
- 질문/답변 생성 후 SQS 메시지 발행
- 메시지 속성
Type(question|reply),Method(insert)사용 notificationTrigger가 SQS 이벤트를 소비- 관리자
expo_push_token조회 후 Expo Push 발송
관련 코드 위치:
function/question/question.tsfunction/question/reply.tsfunction/notificationTrigger/handler.tsfunction/notificationTrigger/question.tsfunction/notificationTrigger/reply.tsfunction/notificationTrigger/pushServer.ts
핵심 동작:
/plan에서 플랜 목록과 최근 기도 이력 기반currentPlan제공/lecture/audio에서 강의별 오디오를 그룹화해 반환/history,/history/detail에서 기도 기록 CRUD/상세 조회 제공
관련 코드 위치:
function/plan/plan.tsxfunction/lecture/lectureAudio.tsfunction/history/history.tsfunction/history/detail.ts
- 인프라/엔드포인트 정의:
template.yml - 배포/빌드 설정:
samconfig.toml - 인증 계층:
layer/jwt/customJwt/index.ts - DB 계층:
layer/mysql2/customMysql/index.ts - 질문/답변 + SQS 발행:
function/question/question.ts,function/question/reply.ts - SQS 소비 + Push 발송:
function/notificationTrigger/handler.ts,function/notificationTrigger/pushServer.ts - 플랜/강의/기록:
function/plan/plan.tsx,function/lecture/lectureAudio.ts,function/history/history.ts