프로덕션 앱 (Production App)
아이디어
모든 대기업은 결국 동일한 형태로 수렴합니다: 앞에는 엣지(Edge), 배포 가능한 프론트엔드(Frontend), 게이트웨이(Gateway) 뒤에 분리된 백엔드(Backend), 큐(Queue)에서 작업을 가져오는 작업자(Worker), 하나의 관계형 시스템 오브 레코드(System of Record), 캐시(Cache), 이벤트 또는 작업 백본(Event/Job Backbone), 객체 스토리지(Object Storage), 그리고 이 모든 것을 둘러싼 관측 가능성(Observability)입니다. Shopify, Notion, Figma, Instacart, Airbnb는 언어와 공급업체에서 차이가 있을 뿐, 형태는 다르지 않습니다.
주말 MVP(Minimum Viable Product)와 플랫폼 팀을 둔 회사 사이에서도 형태는 변하지 않습니다. 변하는 것은 각 상자 뒤에 있는 제공업체(Provider)뿐입니다. 따라서 이 스킬은 첫날부터 저렴한 관리형 제공업체를 사용하여 전체 형태를 구축하고, 소수의 이식성 규칙(Portability Rules)을 적용하며, 측정 가능한 트리거(Trigger)가 발생했을 때 제공업체를 교체하기 위한 각 레이어별 플레이북(Playbook)을 유지합니다. 이렇게 하면 Vercel과 Supabase에서 Kubernetes와 RDS로 전환하는 것은 일련의 구성 변경과 데이터 복사일 뿐, 재작성(rewrite)이 필요하지 않습니다.
이 스킬 사용 방법
- 프로젝트 설명을 읽습니다. 설명에서 빠진 내용에 대해서만 아래 인테이크(Intake) 질문을 합니다.
references/providers-and-tiers.md를 참고하여 각 레이어별 제공업체를 선택합니다. 선택기 규칙(Picker Rule)이 달리 명시하지 않는 한 Tier 1부터 시작합니다.- 아래 템플릿을 사용하여
docs/PLAN.md를 작성합니다.references/architecture.md에서 가져온 다이어그램을 포함시키고, 스캐폴딩(Scaffolding) 전에 이를 보여줍니다. - 아래 순서대로 스캐폴딩 및 빌드합니다.
- 출시 전에
references/launch-checklist.md를 실행하고 수정이 필요한 실패 사항만 보고합니다. - 나중에 트리거가 발생하면
references/migrations.md를 열고 해당 레이어를 이동합니다. 같은 주에 두 개의 레이어를 이동하지 마십시오.
기존 앱의 경우: 먼저 감사를 수행합니다. 리포지토리(Repo)를 위 형태에 매핑하고, 위험 순서(데이터 유출, 중단, 남용, 종속, 비용)대로 격차(Gap)를 나열한 후 중단합니다. 소유자가 목록에서 선택한 후에 변경 사항이 적용됩니다.
인테이크 (Intake)
설명에서 답하지 않은 내용에 대해서만 한 번의 메시지로 질문합니다.
- 사용자는 누구이며, 테넌트(Tenant)는 무엇인가요? (데이터를 소유하는 단위: 회사, 건물, 딜러, 개인?)
- 무엇이 무거운가요? (피드, 메시지, 업로드, 비디오, 이벤트, 검색?) 대략적인 일별 행(Row) 또는 파일 수와 성장률.
- 웹, iOS, Android 또는 혼합인가요? 어떤 것이 먼저 출시되나요?
- 실시간 요구사항: 채팅, 실시간 프레즌스(Presence), 협업 편집? 아니면 폴링(Polling)으로 충분한가요?
- 수익: 구독, 일회성 결제, 마켓플레이스 지불, 없음?
- 규제 또는 민감한 사항: 저장된 결제 정보, 건강 정보, 미성년자, 위치, SOC 2를 요구할 정부 또는 엔터프라이즈 구매자?
- 사용자 지리: 한 국가 또는 글로벌?
- 제약 조건: 기존 클라우드 크레딧, 기존 제공업체, 필수 언어.
답변은 references/providers-and-tiers.md의 선택기 규칙을 결정합니다.
형태 (The Shape)
각 레이어에는 역할, 대기업 참조, 그리고 이식성을 유지하는 하나의 규칙이 있습니다. 각 Tier 별 공급업체는 references/providers-and-tiers.md에 있습니다.
- 엣지 (Edge): 모든 호스트 앞에서 DNS, TLS, CDN, DDoS, WAF, 속도 제한, 봇 필터링을 담당합니다. 대기업: Cloudflare, Akamai, Fastly, AWS WAF가 포함된 CloudFront. 규칙: DNS 영역을 소유합니다. 모든 제공업체는 CNAME 뒤에 위치하므로 제공업체 교체는 DNS 변경입니다.
- 프론트엔드 (Frontend): 별도로 배포 가능하며, 정적이거나 서버에서 렌더링되며 비즈니스 로직이나 데이터베이스 접근을 보유하지 않습니다. 대기업: 컨테이너로 빌드되어 CDN을 통해 제공되는 React 또는 Next.js 앱. 규칙: 프론트엔드는 표준 Node 컨테이너 또는 정적 번들로 빌드되며 공개 API와만 통신합니다.
- 게이트웨이 (Gateway): 엣지로부터 TLS를 종료하고, 경로별로 라우팅하며, 대략적인 제한을 적용하는 로드 밸런서 또는 API 게이트웨이입니다. 대기업: ALB, Envoy, NGINX 인그레스, Kong. 규칙: API는 자체 미들웨어에서 재현할 수 없는 게이트웨이 기능에 절대 의존하지 않습니다.
- 백엔드 (Backend): 게이트웨이 뒤에 있는 하나의 모놀리식 서비스로, 팀이 충돌할 때만 서비스로 분할됩니다. 대기업: Shopify와 GitHub의 Rails, Instagram의 Django, Notion의 Node, 내부는 gRPC, 외부는 GraphQL 또는 REST. 규칙: 헬스 엔드포인트가 있는 Docker 컨테이너, 환경 변수에서 가져오는 설정, 비즈니스 로직에는 공급업체 SDK가 없어야 합니다.
- 작업자와 큐 (Workers and Queue): 작업을 소비하는 별도의 장기 실행 프로세스입니다. 작업에 여러 단계나 사람의 대기가 필요한 경우 워크플로우 엔진을 사용합니다. 대기업: Shopify의 Sidekiq 및 Kafka 소비자, Netflix와 Duolingo의 Temporal, Notion의 Kafka. 규칙: 작업은 멱등성(Idempotent)을 가지며, ID를 전달하고 Blob은 전달하지 않으며, 큐는 표준 Redis 또는 Kafka 프로토콜입니다.
- 관계형 데이터베이스 (Relational Database): 시스템 오브 레코드로서 하나의 Postgres (또는 MySQL) 프라이머리(Primary), 읽기용 복제본(Replica), 단일 시스템 한계를 넘을 때만 샤딩(Sharding)을 사용합니다. 대기업: Notion과 Figma의 PgBouncer가 포함된 RDS Postgres, Shopify의 100개 이상 MySQL 샤드. 규칙: Postgres 와이어 프로토콜(Wire Protocol)만 사용하고, SQL 마이그레이션은 리포지토리에 있으며, 역할과 RLS는 SQL에 있으며, 특정 제공업체의 API에서만 작동하는 것은 없습니다.
- 캐시 (Cache): Redis 또는 Memcached를 핫 리드(Hot Reads), 속도 제한 카운터, 락(Locks), 세션(Sessions)에 사용합니다. 규칙: 표준 Redis 프로토콜, 키는 테넌트 범위(Tenant Scoped) 및 버전 관리(Versioned)되며, 앱은 캐시가 비어 있어도 실행되어야 합니다.
- 객체 스토리지 (Object Storage): 모든 파일에 대해 S3 또는 S3 호환 버킷을 사용합니다. 절대 데이터베이스를 사용하지 않습니다. 규칙: S3 API만 사용하고, 키는 테넌트별로 접두사(Prefix)가 붙으며, 서명된 URL(Pre-signed URLs) 또는 CDN을 통해 제공됩니다.
- 아이덴티티 (Identity): JWT를 발행하는 아이덴티티 제공업체(Identity Provider)와 앱이 소유하는
users테이블입니다. 대기업: 자체 구축 + 엔터프라이즈 SSO를 위한 Okta 또는 Auth0. 규칙: API는 JWKS를 통해 자체적으로 토큰을 검증하고users테이블을 소유하므로 발급자를 변경할 수 있습니다. - 이벤트 및 분석 (Events and Analytics): 제품 분석 도구와, 나중에 CDC(Change Data Capture)로 공급되는 데이터 웨어하우스(Data Warehouse)입니다. 대기업: Snowflake 또는 BigQuery로 들어가는 Kafka. 규칙: 데이터 웨어하우스는 데이터베이스에서 읽으며, 앱에서 이중 쓰기(Dual Writes)를 하지 않습니다.
- 관측 가능성 (Observability): 구조화된 로그, 오류, 메트릭, 트레이스, 가동 시간, 런북(Runbook)에 연결된 알람입니다. 대기업: Datadog, Grafana, Honeycomb, Sentry, OpenTelemetry. 규칙: 앱은 OpenTelemetry와 JSON 로그를 내보내므로 백엔드는 내보내기(Exporter) 설정 문제입니다.
- 전달 (Delivery): 모든 푸시(Push)에 대한 CI, 코드형 인프라(Infrastructure as Code), 카나리(Canary) 또는 블루-그린(Blue-Green) 배포, 기능 플래그(Feature Flags), 빠른 롤백(Rollback). 대기업: Terraform, Buildkite 또는 GitHub Actions, ArgoCD 또는 Spinnaker, LaunchDarkly. 규칙: 대시보드에서 클릭한 모든 것은 같은 날
infra/에 기록되어야 하며, Tier 2부터는 Terraform을 사용합니다.
이식성 규칙 (Portability Rules)
이 규칙들이 나중에 저렴한 전환을 가능하게 합니다. MVP 규모에서는 거의 비용이 들지 않으며, 주말 마이그레이션과 분기 전체 재작성의 차이를 만듭니다.
- 프론트엔드와 백엔드는 첫 번째 커밋부터 별도의 리포지토리와 별도의 배포 단위입니다. 공유 스키마를 가진 버전 관리된 HTTP API를 통해 통신합니다.
- 백엔드와 작업자는 컨테이너가 실행되는 모든 곳에서 실행될 수 있는 Docker 이미지입니다. API에 서버리스 함수는 사용하지 않습니다. Vercel Functions, Lambda 핸들러 및 에지 함수(Edge Functions)는 나중에 재작성 없이 컨테이너로 옮길 수 없는 유일한 것입니다.
- 표준을 통해서만 인프라와 통신합니다: Postgres 와이어 프로토콜, Redis 프로토콜, S3 API, 인터페이스 뒤의 SMTP 또는 HTTP 이메일 API, 토큰용 JWKS, 텔레메트리용 OpenTelemetry. 제공업체의 자체 클라이언트 라이브러리는 교체 가능한 얇은 어댑터 모듈에서만 허용됩니다.
- 비즈니스 로직에 제공업체 기능을 사용하지 않습니다: PostgREST 호출 금지, 백엔드에서 Supabase 또는 Firebase 클라이언트 금지, Vercel 특정 캐싱 API 금지, Workers KV 금지. 프론트엔드는 로그인 용도로만 제공업체의 인증 SDK를 사용할 수 있습니다.
- 앱은 자체 스키마를 소유합니다: 리포지토리의 SQL 마이그레이션, 마이그레이션 도구로 적용되며, 대시보드로는 절대 적용하지 않습니다. 역할, RLS 및 함수는 리포지토리가 모든 Postgres에서 재생할 수 있는 SQL 파일입니다.
- 앱은 자체 사용자를 소유합니다: 첫 로그인 시 아이덴티티 제공업체에서 미러링된
users테이블이며, 공급업체 ID는 열(Column)로 저장됩니다. 권한 데이터는 앱의 테이블에 있습니다. - 설정은 부팅 시 검증되는 환경 변수입니다. 비밀(Secrets)은 플랫폼의 비밀 저장소에 있지만, 앱에는 환경 변수로 전달되므로 저장소를 변경할 수 있습니다.
- DNS 영역을 소유합니다(Cloudflare). 모든 제공업체는 CNAME 대상입니다. 어떤 것도 제공업체의 네임서버를 가리키지 않습니다.
- 객체 스토리지 키와 버킷 레이아웃은 R2와 S3에서 동일합니다. 코드는 엔드포인트 설정이 있는 S3 SDK를 사용합니다.
- 모든 레이어에는 문서화된 내보내기가 있습니다: 데이터베이스용
pg_dump및 논리적 복제, 객체용rclone, Redis 덤프는 캐시가 폐기 가능하고 큐가 소진되므로 절대 필요하지 않습니다. - 헬스 엔드포인트, SIGTERM 시 정상 종료(Graceful Shutdown), 수평적 상태 비저장(Horizontal Statelessness)이 첫날부터 존재합니다. Railway에서 Kubernetes까지 모든 플랫폼이 이에 의존하기 때문입니다.
- 텔레메트리와 로그는 첫날부터 OpenTelemetry와 JSON입니다. 공급업체 에이전트는 코드에 설치되지 않습니다.
등급 (Tiers)
레이어당 세 가지 등급. 트리거는 측정 가능합니다. 공급업체, 비용 및 선택기 규칙이 포함된 전체 테이블은 references/providers-and-tiers.md에 있습니다.
- Tier 1, MVP: 설정에 몇 분 밖에 걸리지 않고 총 월 약 $150 미만의 비용이 드는 관리형 제공업체입니다. 프론트엔드는 Vercel, 백엔드 컨테이너는 Railway, Postgres는 Supabase, Redis는 Railway, 객체는 R2, 엣지는 Cloudflare, Sentry 및 Better Stack을 사용합니다. 가동 시간에 대해 묻는 유료 고객이 있거나 아래 수치에 도달할 때까지 사용합니다.
- Tier 2, 성장: 중요한 부분은 자체 클라우드 계정에서 동일한 형태를 사용합니다: PgBouncer 또는 RDS Proxy가 포함된 RDS 또는 Aurora Multi AZ의 Postgres, ECS Fargate 또는 소규모 EKS의 컨테이너, ElastiCache, S3 또는 R2, 모든 것을 위한 Terraform, 읽기 복제본, 워크플로우를 위한 Temporal. 트리거: 유료 고객이 SLA 또는 SOC 2를 요구하거나, 지속적으로 월간 활성 사용자 5,000명과 데이터베이스 CPU가 60%를 초과하거나, PaaS 청구서가 월 $500를 초과하거나, 두 번째 엔지니어가 합류하는 경우.
- Tier 3, 규모 확장: Shopify와 Notion이 운영하는 방식입니다. 자동 확장(Autoscaling)이 포함된 Kubernetes, 샤딩 또는 파티셔닝된 프라이머리, 이벤트 백본으로서의 Kafka, CDC를 통한 데이터 웨어하우스, 다중 리전 읽기, Datadog 또는 Grafana, 플랫폼 팀. 트리거: 지속적으로 초당 1,000개의 요청, 단일 프라이머리가 거의 1TB에 가깝거나 복제본 및 캐싱 후에도 쓰기 바운드(Write Bound) 상태, 다중 리전 요구 사항, 또는 이를 운영할 운영 팀이 존재하는 경우.
등급 이동은 한 번에 모든 레이어가 아닌 레이어별로 이루어집니다. 일반적으로 데이터베이스가 먼저 이동하고, 그 다음 백엔드, 마지막으로 프론트엔드가 이동합니다. 프론트엔드는 현재 위치에 두는 것이 가장 저렴하기 때문입니다.
빌드 순서
- 스키마, 마이그레이션, 역할, RLS (
references/database.md,references/security.md) - 아이덴티티 검증 및 테넌트 컨텍스트 미들웨어
- 검증(Validation) 및 쓰기에 대한 멱등성(Idempotency)을 갖춘 핵심 API 라우트
- 속도 제한 및 캐싱 미들웨어 (
references/rate-limiting.md,references/caching.md) - 작업자 및 큐; 느리거나 외부적인 모든 것은 요청 경로에서 벗어납니다 (
references/jobs-and-queues.md) - API에 대응하는 프론트엔드
- 동일한 API에 대응하는 모바일
- 로그, 메트릭, 트레이스, 헬스 체크, 알람 (
references/observability-and-reliability.md) - 출시 게이트, 예상 최대치의 세 배 부하 테스트, 한 번의 복원 테스트 (
references/launch-checklist.md)
PLAN.md 템플릿
# <프로젝트> 계획
## 세 문장으로 요약한 제품
## 사용자, 테넌트, 역할
## 레이어별 제공업체 (레이어별 등급, 이유, 이동 트리거, providers-and-tiers.md 참조)
## 데이터 모델 (테이블, tenant_id 표시, 인덱스, 파티션 테이블)
## API 표면 (리소스별 라우트, 인증 수준, 속도 제한 등급)
## 백그라운드 작업 (큐, 트리거, 멱등성 키, 재시도 정책)
## 서드파티 (서비스, 목적, 비밀 이름, 제한, 실패 모드)
## 캐싱 맵 (무엇, 키, TTL, 어떤 쓰기가 이를 무효화하는지)
## 위협 모델 (상위 5개 남용 사례와 각각에 대한 통제)
## 규모 가정 (출시 시 및 10배 성장 시 사용자, 행, 분당 요청 수)
## 출시 시 비용 (제공업체별, 월별)
## 제공업체별 탈출 계획 (해당하는 migrations.md 플레이북, 각각 한 줄로)
## 다이어그램
절대적 규칙 (Non-Negotiable Rules)
- 모든 테넌트 소유 테이블에는
tenant_id가 있습니다. RLS가 활성화되고 강제됩니다. API는 검증된 멤버십에서 트랜잭션별로 테넌트를 설정하며, 요청 입력에서 절대 가져오지 않습니다. - 클라이언트는 절대 데이터베이스에 접근하거나 권한이 있는 키를 보유하지 않습니다. 모든 것은 API를 통해 전달됩니다.
- 모든 입력은 경계에서 검증되며, 알 수 없는 키는 거부됩니다. 모든 쿼리는 매개변수화(Parameterized)됩니다.
- API와 작업자는 작은 풀을 가진 풀러(Pooler)를 통해 연결됩니다. 역할별로 명령문 시간 제한(Statement Timeout)이 설정됩니다.
- 엣지와 API에서 속도 제한이 적용되며, 사용자, 테넌트 및 IP별로 키가 지정됩니다. 캐시 키는 테넌트 범위로 지정되고 버전 관리됩니다.
- 비밀은 플랫폼 저장소에 있으며, 환경별로 한 세트씩 있고, 절대 Git이나 모바일 번들에 포함되지 않습니다. 프로덕션과 스테이징은 별도의 프로젝트 및 계정입니다.
- PITR(Point-in-Time Recovery)이 켜져 있고, 복원 테스트가 한 번 수행되었습니다.
- 웹훅 서명이 검증되고, 재생 공격이 방지되며, 멱등성을 가지며, 2초 이내에 응답합니다.
- 모든 아웃바운드 호출에 타임아웃이 있습니다. 멱등성 작업에만 지터(Jitter)가 있는 재시도를 합니다. 실패한 작업은 사람이 볼 수 있습니다.
- 모든 로그 라인에 요청 ID와 테넌트 ID가 있습니다. 오류율, p95 지연 시간, 5xx 개수, 큐 에이징(Aging), 실패한 작업, 데이터베이스 연결에 대한 알림이 설정됩니다.
모바일 (Mobile)
- 기존 React Native 또는 Expo 앱: 그대로 유지합니다.
- 새 앱, iOS 전용 또는 iOS 우선: 네이티브 Swift 및 SwiftUI를 사용합니다. 대기업은 2026년에 네이티브로 돌아갔습니다(Shopify는 Swift 및 Kotlin, Notion은 SwiftUI). 코딩 에이전트(Coding Agents)가 두 번째 코드베이스의 비용을 제거했기 때문입니다. 소규모 팀에도 동일하게 적용됩니다. Android가 실제로 구축될 때만 Kotlin을 사용합니다.
- 한두 명의 인원으로 같은 날 iOS와 Android를 출시해야 하는 새 앱: Expo를 사용합니다.
- 어느 쪽이든 앱은 API와만 통신하고, 토큰을 안전한 저장소에 보관하며, 번들에 비밀 정보를 포함하지 않습니다.
참조 파일 (Reference Files)
references/providers-and-tiers.md: 레이어별 테이블(대기업 사례, Tier 1, 2, 3 공급업체, 트리거, 비용) 및 프로젝트 설명을 선택 사항으로 변환하는 선택기 규칙.references/migrations.md: 각 레이어를 상위 등급으로 이동하기 위한 단계별 플레이북.references/architecture.md: 등급 레이블, 세 가지 요청 경로, 리포지토리 레이아웃, 환경, 엣지 및 플랫폼 구성을 포함한 다이어그램.references/security.md: 테넌시(Tenancy) 및 RLS, 아이덴티티, 비밀, 헤더, 입력, 업로드, 웹훅, 암호화, 삭제 및 내보내기, 모바일, 감사 로그, 인시던트.references/rate-limiting.md: 숫자가 포함된 네 가지 레이어와 미들웨어.references/caching.md: 모든 캐시 레이어, 키 스키마, TTL, 무효화, 스탬피드 방지(Stampede Protection).references/database.md: 스키마 규칙, 역할, 풀링(Pooling), 마이그레이션, RLS 템플릿.references/jobs-and-queues.md: 작업 패턴, 재시도, 데드 레터 큐(Dead Letter Queue), 워크플로우 오케스트레이션.references/observability-and-reliability.md: 로그 구조, 메트릭, 트레이싱(Tracing), 상태 확인, 게이트(Gate), 부하 테스트, 복원 테스트, 사고 대응(Incident Response).references/launch-checklist.md: 출시 전 검증 목록.references/mobile.md: 클라이언트 아키텍처, 오프라인 우선(Offline First), 푸시, 배포.references/storage.md: 객체 스토리지 구성, 버킷 구조, 프리사인드 URL, CDN 통합.references/cost-estimation.md: 레이어별 예상 비용과 규모에 따른 비용 증가 분석.