Skip to Content
DecisionsADR-0001: API 백엔드를 코어 API와 front-api BFF 둘로 나눈다

ADR-0001: API 백엔드를 코어 API와 front-api BFF 둘로 나눈다

  • Status: Accepted
  • Date: 2026-08-31 (소급 기록 — 결정 자체는 그 이전에 점진적으로 이루어짐)
  • 관련: packages/api/fetcher/fetch.ts, apps/api

이 ADR은 이미 내려진 결정을 사후에 기록한 것입니다. Context는 코드와 배선에서 재구성했으며, 당시 논의 원문이 아닙니다. 사실과 다른 부분이 있으면 고쳐 주세요.

Context

얼마집의 핵심 도메인 데이터(조합·조합원·투표·총회·설문·동의서)는 별도 레포의 Python/FastAPI 서버가 소유합니다. 이 모노레포는 그 위의 클라이언트입니다.

그런데 프론트에만 필요하고 코어 도메인과 무관한 서버 기능이 계속 생겼습니다.

  • 딥링크·단축링크 해석, OTA 매니페스트 제공, 앱 버전 판정(app/version/*)
  • 카페·뉴스·랜딩 콘텐츠 조립, OG 스크래핑
  • AI 세무상담(Anthropic 스트리밍), DM용 Supabase 토큰 발급
  • 외부 API 프록시 (예: APICK 신분증 검증 — HMH-8970)

이들을 코어 API에 넣으려면 레포·언어·배포 주기가 다른 팀 경계를 매번 넘어야 했습니다. 프론트 릴리즈 속도가 백엔드 릴리즈에 묶입니다.

검토한 대안

대안채택 안 한 이유
전부 코어 API(FastAPI)에 넣는다프론트 전용 기능까지 다른 레포·다른 언어·다른 배포 주기에 묶임. OTA 매니페스트처럼 프론트 배포와 원자적으로 맞아야 하는 것이 특히 곤란
클라이언트에서 외부 API를 직접 호출한다키 노출, CORS, 그리고 native의 경우 OTA로 못 고치는 실패 모드가 생김
별도 BFF 서버를 새 레포로 띄운다운영 대상이 하나 더 늘고, 프론트 코드와 타입 공유 이점을 잃음

Decision

Next.js Route Handlers 기반의 얇은 BFF(apps/api, 배포명 front-api)를 이 모노레포 안에 둔다. 클라이언트는 백엔드를 직접 고르지 않고, 엔드포인트 정의의 server 값으로 fetcher가 라우팅한다.

server: 'main' (기본값)server: 'front'
대상코어 API (FastAPI, 다른 레포)apps/api (이 레포)
prod 호스트api.howmuchhome.cofront-api.howmuchhome.co
URL 조합${host}/api/${path}${host}/${path}프리픽스 없음

배선: packages/api/fetcher/fetch.ts (props.meta.server ?? 'main'), 호스트는 HOWMUCHHOME_API_URL / HOWMUCHHOME_FRONT_API_URL. native는 process.env가 비므로 apps/native-app/src/config/env.ts에서 명시 주입한다.

경계 규칙: front-api는 프론트 전용 관심사만 갖는다. 핵심 도메인 데이터의 소유권은 코어 API에 남는다. front-api가 자체 소유하는 데이터는 Neon PostgreSQL(Drizzle)에 둔다.

Consequences

좋아지는 것

  • 프론트 전용 서버 기능을 프론트 배포 주기로 출시할 수 있다 (OTA 매니페스트처럼 원자성이 필요한 경우 결정적)
  • 타입·도메인 상수를 서버·클라이언트가 같은 패키지로 공유한다
  • 외부 API 키를 클라이언트에 노출하지 않고 프록시할 수 있다

감수하는 것

  • 호출 대상이 둘이라 디버깅 때 헷갈린다. 403 하나를 봐도 코어 API가 낸 것인지 front-api가 낸 것인지 먼저 구분해야 한다 (실측 사례: HMH-8841 — FORBIDDEN + detail: null 조합이면 front-api 자체 403)
  • 배포 대상과 관측 대상이 하나 늘었다
  • “이 기능은 어느 쪽에 넣지?”라는 판단이 매번 필요하다 — 위 경계 규칙이 그 답이어야 한다
  • Neon PG에 front-api·app·dashboard·short-link각각 직접 접근한다. BFF를 유일한 DB 게이트웨이로 두지 않은 상태다

이 결정을 다시 열어야 할 때

  • front-api가 핵심 도메인 로직을 갖기 시작할 때 (경계 침식 신호)
  • 코어 API가 GraphQL/BFF 성격 엔드포인트를 직접 제공하기 시작할 때
  • Neon PG 직접 접근처가 더 늘어, DB 스키마 변경의 영향 범위를 추적하기 어려워질 때
Last updated on