본문으로 건너뛰기

Backend Architecture

개요

Backend는 브라우저에 Cognito 토큰을 노출하지 않는 BFF(Backend for Frontend) 구조입니다.

Browser
-> Cloudflare Pages /api/*
-> API Gateway HTTP API
-> API Lambda (Express)
-> Cognito / DynamoDB / Secrets Manager

Frontend는 Cloudflare Pages에서 제공됩니다. Pages Function이 동일 오리진의 /api/* 요청을 API Gateway로 전달하므로 OAuth callback과 HttpOnly 인증 쿠키가 동일한 Frontend 도메인을 사용합니다.

AWS 리소스

API Lambda

  • Runtime: Node.js 22
  • Architecture: ARM64
  • Memory: 512MB
  • Timeout: 29초
  • Reserved concurrency: 50
  • X-Ray tracing: 활성화
  • Entry point: src/lambda.ts

reservedConcurrentExecutions는 최대 동시 실행 제한이며 Provisioned Concurrency가 아닙니다. 유휴 상태에서 고정 Lambda 실행 비용을 만들지 않습니다.

API Gateway

  • HTTP API
  • $default stage
  • 모든 경로와 HTTP method를 API Lambda로 proxy
  • Steady-state rate: 초당 50 요청
  • Burst limit: 100 요청
  • CloudWatch access log 보관: 1개월
  • Route-level detailed metrics 활성화

Cognito

  • 이메일 기반 가입 및 로그인
  • 이메일 확인과 비밀번호 복구
  • Google OAuth authorization code + PKCE
  • TOTP MFA
  • Access/ID token 유효 기간: 15분
  • Refresh token 유효 기간: 30일
  • GitHub 전용 비밀 app client와 Custom Auth Lambda trigger

GitHub는 Cognito의 기본 소셜 IdP가 아니므로 GitHub OAuth API로 검증된 이메일을 확인한 후 Admin Custom Auth를 수행합니다.

DynamoDB

단일 테이블은 pk, sk 복합 키를 사용합니다.

PKSK용도
USER#{userId}PROFILE이름, 이메일, 소개, locale, timezone
USER#{userId}ACCESS구독 상태와 권한
AUTH_SESSION#{id}AUTH_SESSIONMFA challenge 단기 세션
OAUTH_STATE#{state}OAUTH_STATEOAuth CSRF state와 PKCE verifier
AUDIT#{userId}{timestamp}#{id}권한 변경 감사 기록

테이블은 on-demand billing, AWS 관리형 암호화, PITR, TTL을 사용합니다. OAuth state는 원자적 삭제 후 반환하여 재사용을 막습니다.

Secrets Manager

GitHub OAuth client secret을 저장합니다. Lambda execution role만 읽을 수 있습니다.

인증 쿠키

  • efk_access: Cognito access token
  • efk_id: Cognito ID token
  • efk_refresh: Cognito refresh token
  • efk_auth_source: 일반 또는 GitHub 로그인 구분
  • efk_auth_username: GitHub refresh에 필요한 Cognito username

모든 쿠키는 HttpOnly, SameSite=Lax, 운영 환경 Secure로 설정됩니다.

권한 모델

  • MODULE_UPLOAD
  • MODULE_VERIFY
  • MODULE_DELETE
  • MODULE_HIDE
  • PERMISSION_MANAGE

권한은 DynamoDB에서 조회하며 API route에서 별도로 검사합니다. Cognito group만으로 권한을 결정하지 않기 때문에 구독 정보와 세부 권한을 같은 사용자 access record에서 관리할 수 있습니다.