티스토리 뷰

DOWNLOAD

뻥이야 다운로드

 

0123456

 

Android iOS


SUMMARY

뻥이야 백엔드 - 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 개별 번들링)



CONCLUSION

결론

AWS CDK v2를 활용하여 완전한 서버리스 백엔드를 구축했습니다. TypeScript로 인프라와 비즈니스 로직을 동일하게 관리할 수 있어 개발 생산성이 크게 향상되었습니다.

특히 DynamoDB Single Table Design + 6 GSI로 7가지 엔티티의 다양한 접근 패턴을 효율적으로 처리하면서도 핫 파티션 없이 안정적으로 운영할 수 있었습니다.

OpenAI GPT API 연동 시 Temperature보다 Frequency/Presence Penalty가 창의적 다양성에 더 큰 영향을 미친다는 것을 발견했고, Structured Output을 활용해 포맷 일관성도 확보했습니다.

이 프로젝트를 통해 서버리스 아키텍처의 장점과 DynamoDB 설계의 중요성을 깊이 이해할 수 있었습니다.


DOWNLOAD

뻥이야 다운로드

 

0123456

 

Android iOS


긴 글을 읽어주셔서 감사합니다!

처음 서버리스 아키텍처를 설계할 때는 DynamoDB의 Single Table Design이 가장 큰 도전이었습니다.

관계형 DB에서는 테이블을 나누고 JOIN하면 되지만, DynamoDB에서는 모든 접근 패턴을 미리 파악하고 GSI를 설계해야 합니다. 6개의 GSI를 설계하면서 "이 쿼리는 어떤 인덱스를 탈까?"를 수십 번 고민했습니다.

또한 OpenAI GPT API를 실제 서비스에 연동하면서 프롬프트 엔지니어링의 중요성을 깨달았습니다. 특히 한국어 콘텐츠 생성에서는 영어와 다른 파라미터 튜닝이 필요하다는 것을 알게 되었습니다.

이 경험이 서버리스 아키텍처나 AI 서비스 개발을 고민하시는 분들께 도움이 되었으면 합니다!