티스토리 뷰
[AWS] AI 핑계 생성 서비스 서버리스 백엔드 - CDK v2 + Lambda + DynamoDB 6 GSI + GPT
권퓨터: Kwonputer 2026. 2. 2. 12:43SUMMARY
뻥이야 백엔드 - AWS Serverless 아키텍처
AI 핑계/변명 생성 서비스의 서버리스 백엔드 개발기입니다.
AWS CDK v2로 인프라를 코드로 관리하고, 6개 Lambda 함수가 각각의 도메인을 처리합니다.
DynamoDB Single Table Design + 6 GSI로 7가지 엔티티의 다양한 접근 패턴을 지원합니다.
주요 기술적 도전: Single Table Design 6 GSI 설계, Lambda Cold Start 최적화, AI 파이프라인 구축
TABLE OF CONTENTS
목차
왜 서버리스를 선택했나? AWS 아키텍처 AI 파이프라인 주요 기능 기술적 도전과 해결
WHY
왜 서버리스를 선택했나?
뻥이야는 AI 기반 핑계/변명 생성 서비스입니다. OpenAI GPT API를 활용하여 상황에 맞는 창의적인 핑계를 생성하고, 캐릭터 페르소나와 말투를 적용해 개성 있는 결과물을 만들어냅니다.
이 서비스의 특성상 트래픽 변동이 크고, API 호출 당 비용이 발생하며, 인프라 관리에 리소스를 쓰고 싶지 않았습니다. 서버리스 아키텍처는 이 세 가지 요구사항을 완벽히 충족했습니다.
특히 AWS CDK v2를 선택한 이유는 인프라를 TypeScript 코드로 관리할 수 있어, 백엔드 코드와 동일한 언어로 전체 스택을 유지할 수 있기 때문입니다.
결과적으로 6개 Lambda 함수, API Gateway, DynamoDB Single Table, EventBridge 스케줄러로 구성된 완전한 서버리스 아키텍처를 구축했습니다.
ARCHITECTURE
AWS 아키텍처
[Flutter App]
|
v
[API Gateway REST]
rate: 20/s, burst: 40
stage: dev
|
+---------+-------+-------+---------+---------+
| | | | | |
[excuse] [user] [character] [tone] [announce] [popularity]
512MB 512MB 512MB 256MB 256MB 512MB
30s 45s 30s 30s 30s 120s
| | | | | |
+----+----+---+---+---+---+---------+ |
| | |
v v |
[DynamoDB] [Secrets Manager] |
Single Table OpenAI API Key |
PK/SK + 6 GSI Kakao Admin Key |
TTL enabled |
^ |
| |
+----------------------------------------+
|
[EventBridge]
cron(0 0 * * ? *)
매일 자정 인기도 캐시 갱신
6개 Lambda 함수
excuse (512MB, 30s) - 핑계 생성/목록/좋아요/운세/썰뻥튀기
user (512MB, 45s) - Kakao/Apple OAuth 인증, 프로필, 포인트, 출석
character (512MB, 30s) - 캐릭터 CRUD, AI 성격 생성, 커스텀 핑계
tone (256MB, 30s) - 말투 CRUD
announcement (256MB, 30s) - 공지사항, 앱 상태, 강제 업데이트
popularity-updater (512MB, 120s) - EventBridge 트리거, 인기도 캐시 갱신
DynamoDB Single Table Design
7가지 엔티티 - USER# / EXCUSE# / CHAR# / TONE# / POINT# / ANNOUNCEMENT# / POPULAR_CACHE
GSI1 - 사용자별 조회
GSI2 - 글로벌 뻥 조회 (10개 샤드)
GSI3 - 인기 뻥 조회 (10개 샤드)
GSI4 - 시간대별 인기 캐시
GSI5 - 사용자별 뻥 전용 인덱스
GSI6 - 캐릭터별 필터링
AI PIPELINE
AI 파이프라인
뻥이야는 3가지 독립적인 AI 생성 파이프라인을 가지고 있습니다. 모두 OpenAIService를 공유하며, 각각 다른 목적의 콘텐츠를 생성합니다.
[사용자]
|
| situation + characterId? + toneId?
v
[API Gateway] ─── POST /excuses ──> [excuse Lambda]
|
+--------------+---------------+
| |
1. CategoryClassifier 2. CreativeTransformer
GPT-4o-mini (분류) GPT-4.1-mini (생성)
| |
| type: excuse/reason | 기본 모드 (temp 0.8)
| category: 16개 | 캐릭터 모드 (temp 0.7)
| shouldTransform | + Personality 4축
v | + Tone 말투
v
[구조화 JSON 응답]
content + emotion + tags
|
v
[DynamoDB 저장]
+ 포인트 차감(-10pt)
+ 감정 이미지 매핑
|
v
[사용자 응답]
파이프라인 A: 핑계/이유 생성
1단계 - CategoryClassifier: GPT-4o-mini로 입력 분석 (16개 카테고리 분류, excuse/reason 타입 판별)
2단계 - CreativeTransformer: GPT-4.1-mini로 창의적 핑계 생성 (캐릭터 성격 4축 + Tone 말투 적용)
포인트 차감: -10pt (실패 시 자동 환불)
파이프라인 B: 오늘의 운세 생성
사전 계산: 육십갑자, 타로카드(22장), 별자리(12개), 12지신
GPT-4.1-mini: 한국/서양 점술 융합 운세 생성
포인트 차감: -40pt
파이프라인 C: 썰 뻥튀기기
장르 선택: 10개 웹소설 장르 중 자동 선택 (게임판타지, 회귀, 빙의, 환생, 로판 등)
GPT-4.1-mini: 오프닝 → 캐릭터 상태 → 갈등/전환점 → 행동/반응 → 클리프행어 구조
포인트 차감: -30pt
FEATURES
주요 기능
캐릭터 페르소나 + 말투(Tone) 커스터마이징
캐릭터 성격 4축: intensityLevel(긴장/강도), chaosLevel(논리적 무작위성), formalityLevel(한국어 격식), imaginationLevel(현실초월)
AI 자동 분석: 캐릭터 이름과 설명만 입력하면 GPT-4o-mini가 4축 성격 수치를 자동 생성
Tone 적용: 사용자 정의 말투를 핑계 생성 프롬프트에 주입하여 문체 변환
포인트 이코노미 시스템
획득 (+)
가입 보너스 +200pt | 출석체크 +50pt | 좋아요 +7pt
사용 (-)
핑계 생성 -10pt | 운세 생성 -40pt | 썰 뻥튀기 -30pt
인기 랭킹 시스템 (EventBridge 스케줄러)
매일 자정 UTC: popularity-updater Lambda가 인기도 캐시 갱신
3개 기간: daily(24시간), weekly(7일), monthly(30일) 병렬 처리
샤드 분산 쿼리: GSI3로 10개 샤드 병렬 조회 → 상위 100개 캐싱 (TTL 24시간)
TROUBLESHOOTING
기술적 도전과 해결
PROBLEM 01
DynamoDB Single Table Design에서 다양한 접근 패턴 지원
7가지 엔티티(User/Excuse/Character/Tone/Point/Announcement/PopularityCache)가 사용자별, 글로벌, 시간 기반, 캐릭터별 등 다양한 쿼리 패턴을 필요로 하면서 단일 테이블로 통합 관리해야 했습니다. DynamoDB는 관계형 DB와 달리 설계 시점에 접근 패턴을 결정해야 하며, 잘못된 GSI 설계는 핫 파티션과 스로틀링을 유발합니다.
SOLUTION - PK/SK 패턴 + 6개 GSI 설계
// PK/SK 패턴 (엔티티별 프리픽스)
PK: USER#{userId} / EXCUSE#{id} / CHAR#{id} / TONE#{id} / POINT#{userId} / ANNOUNCEMENT#{id} / POPULAR_CACHE
// 6개 GSI
GSI1: 사용자별 조회 (GSI1PK / GSI1SK)
GSI2: 글로벌 뻥 (ALL_EXCUSES#SHARD#{0-9}) - 10개 샤드로 핫 파티션 방지
GSI3: 인기 뻥 (POPULAR_EXCUSES#SHARD#{0-9}) - 샤드 분산 쿼리
GSI4: 시간대별 인기 캐시
GSI5: 사용자별 뻥 전용
GSI6: 캐릭터별 필터링
// TTL 자동 캐시 정리
ttl 속성 활성화 → 24시간 후 자동 삭제
PROBLEM 02
Lambda Cold Start + OpenAI GPT API 응답 지연
OpenAI GPT API 호출이 5-30초 소요되며, Lambda Cold Start(2-5초)와 결합하면 최대 35초 지연으로 사용자 경험이 저하되었습니다. Lambda 함수 초기화 시 AWS SDK, Secrets Manager 조회, 외부 라이브러리 로드에 Cold Start 시간이 추가되는 문제가 있었습니다.
SOLUTION - 다각도 최적화
Lambda Layer 분리
공통 의존성을 Lambda Layer로 분리 (layer-package.json) → Cold Start 시간 감소
Webpack 5 번들링
멀티 엔트리 번들링으로 코드 크기 최소화 → Lambda 패키지 경량화
메모리 차등 할당
256-512MB 함수별 차등 설정 → CPU 성능 비례 향상
Secrets Manager 캐싱
최초 조회 후 메모리 캐싱 (this.apiKey) → 런타임 중 재조회 최소화
PROBLEM 03
GPT 응답의 창의성 + 일관성 균형
핑계 생성 시 창의적이면서도 포맷이 일관된 응답이 필요했습니다. Temperature만 조절하면 창의성은 올라가지만 포맷이 깨지고, 낮추면 반복적인 결과가 나오는 문제가 있었습니다.
SOLUTION - Frequency/Presence Penalty 튜닝
// openai-params.config.ts
// 설계 원칙 (코드 주석에서 확인)
// - Temperature는 창의성과 약한 상관관계만 있음
// - Frequency/Presence penalty가 창의적 다양성의 핵심
// - 한국어는 영어 대비 높은 penalty 값이 효과적
// - top_p 제거 (temperature와 중복 효과)
창의적 변형 (일반 핑계): temp=0.8, freq_penalty=1.0, pres_penalty=0.75
캐릭터 핑계: temp=0.7, freq_penalty=0.8, pres_penalty=0.6
운세 생성: temp=0.75, freq_penalty=0.6, pres_penalty=0.65
웹소설 (일반): temp=0.9, freq_penalty=0.4, pres_penalty=0.7
// Structured Output으로 포맷 강제
response_format: { type: "json_schema", json_schema: {...} }
TECH STACK
기술 스택
언어: TypeScript 5.3.3
IaC: AWS CDK v2 (aws-cdk-lib 2.203.1)
런타임: Node.js 18.x (AWS Lambda)
API: AWS API Gateway REST API (20 req/sec rate, 40 burst)
DB: AWS DynamoDB (Single Table Design, 6 GSI, TTL, PAY_PER_REQUEST)
AI: OpenAI GPT API (gpt-4o-mini, gpt-4.1-mini)
인증: Kakao/Apple OAuth + JWT (jsonwebtoken 9.0.2)
스케줄러: AWS EventBridge (cron 매일 자정)
보안: AWS Secrets Manager (OpenAI API Key, Kakao Admin Key)
빌드: Webpack 5 (멀티 엔트리, Lambda 개별 번들링)
REFERENCE
AWS CDK v2 Guide DynamoDB Single Table Design OpenAI Structured Outputs AWS Lambda Runtimes
CONCLUSION
결론
AWS CDK v2를 활용하여 완전한 서버리스 백엔드를 구축했습니다. TypeScript로 인프라와 비즈니스 로직을 동일하게 관리할 수 있어 개발 생산성이 크게 향상되었습니다.
특히 DynamoDB Single Table Design + 6 GSI로 7가지 엔티티의 다양한 접근 패턴을 효율적으로 처리하면서도 핫 파티션 없이 안정적으로 운영할 수 있었습니다.
OpenAI GPT API 연동 시 Temperature보다 Frequency/Presence Penalty가 창의적 다양성에 더 큰 영향을 미친다는 것을 발견했고, Structured Output을 활용해 포맷 일관성도 확보했습니다.
이 프로젝트를 통해 서버리스 아키텍처의 장점과 DynamoDB 설계의 중요성을 깊이 이해할 수 있었습니다.
긴 글을 읽어주셔서 감사합니다!
처음 서버리스 아키텍처를 설계할 때는 DynamoDB의 Single Table Design이 가장 큰 도전이었습니다.
관계형 DB에서는 테이블을 나누고 JOIN하면 되지만, DynamoDB에서는 모든 접근 패턴을 미리 파악하고 GSI를 설계해야 합니다. 6개의 GSI를 설계하면서 "이 쿼리는 어떤 인덱스를 탈까?"를 수십 번 고민했습니다.
또한 OpenAI GPT API를 실제 서비스에 연동하면서 프롬프트 엔지니어링의 중요성을 깨달았습니다. 특히 한국어 콘텐츠 생성에서는 영어와 다른 파라미터 튜닝이 필요하다는 것을 알게 되었습니다.
이 경험이 서버리스 아키텍처나 AI 서비스 개발을 고민하시는 분들께 도움이 되었으면 합니다!
'Flutter Project > 뻥이야' 카테고리의 다른 글
| [Flutter] AI 핑계 생성기 '뻥이야' 앱 개발기 - Clean Architecture + Riverpod 116,000줄 규모 (0) | 2026.02.02 |
|---|
- Total
- Today
- Yesterday
- Prompt Engineering
- riverpod
- python
- 상태관리
- injectable
- python 기초
- Compose
- https://www.kwonputer.shop/
- 개발자
- 서버리스 아키텍처
- 파이썬
- 크로스플랫폼
- kotlin
- TypeScript
- 클린 아키텍처
- aws lambda
- OpenAI GPT
- 자막 생성기
- https://github.com/kwongeneral/kortfolio.git
- 파이썬 기초
- KE-T5
- flutter 면접 질문
- AWS CDK
- dynamodb
- 내러티브 게임
- Clean Architecture
- ai 게임 개발
- Single Table Design
- flutter 개발자
- flutter
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |













