React + Firebase: 프로덕션 ERP를 위한 아키텍처 결정

발행: (2026년 4월 3일 PM 07:00 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

I’m happy to translate the article for you, but I need the full text of the post (or the portions you’d like translated). Could you please paste the content here? Once I have the text, I’ll provide a Korean translation while preserving the original formatting, markdown, and code blocks.

Source:

ERP 구축은 부수 프로젝트가 아니다

실제 금전, 실제 세금 의무, 그리고 실제 비즈니스 데이터를 다룹니다. 모든 아키텍처 결정은 몇 개월에 걸쳐 복합적인 영향을 미칩니다.

아래는 Frihet에 선택한 스택과 각 결정에 대한 이유입니다.

스택

Frontend:  React 18 + TypeScript + Vite 5
Styling:   Tailwind CSS + shadcn/ui + Radix
Backend:   Firebase (Auth, Firestore, Cloud Functions, Storage)
AI:        Google Gemini (2.5 Flash + Pro)
Payments:  Stripe Billing + Connect
Hosting:   Vercel (frontend) + GCP europe‑west1 (backend)
Mobile:    Capacitor (iOS + Android from same codebase)

전통적인 백엔드 대신 Firebase를 선택한 이유

수십억 달러 규모의 기업과 경쟁하는 제품을 혼자 개발하고 있습니다. 데이터베이스 클러스터를 운영하고, 마이그레이션을 관리하고, 커넥션 풀링을 처리하면서 동시에 기능을 만들 수는 없습니다.

Firebase가 제공하는 것:

  • Auth – 이메일, Google, GitHub, Microsoft (커스텀 코드 전혀 필요 없음)
  • Firestore – 실시간 구독; 데이터 변경이 즉시 모든 연결된 클라이언트에 전파
  • Cloud Functions – 서버‑사이드 로직; 0으로 스케일링, 유휴 비용 없음
  • Security Rules – 데이터 격리를 데이터베이스 레벨에서 강제, 애플리케이션 코드가 아니라

대가로는 벤더 락인과 NoSQL 데이터 모델이 있습니다. 빠르게 출시해야 하는 솔로 창업자에게는 이 트레이드‑오프가 합리적입니다.

NoSQL 도전 과제

ERP는 전통적으로 관계형 데이터베이스를 사용합니다. Firestore를 활용하려면 엄격한 데이터 모델링 규율이 필요했습니다:

  • 데이터베이스 레벨에서 워크스페이스 격리 – 각 비즈니스 테넌트는 자체 데이터 파티션을 가집니다. 애플리케이션 코드에 버그가 있더라도 보안 규칙이 이를 강제하므로 테넌트 간 데이터 유출은 불가능합니다.
  • 읽기를 위한 비정규화, 쓰기를 위한 참조 – 인보이스 리스트 뷰는 추가 쿼리 없이 클라이언트 이름을 표시하지만, 변형은 항상 정규화된 클라이언트 레코드를 통해 이루어집니다.
  • 복잡한 집계를 위한 Cloud Functions – SQL JOIN이나 GROUP BY에 해당하는 작업은 클라이언트가 아니라 서버‑사이드에서 실행됩니다.

이 접근법은 약 80 %의 사용 사례에 잘 맞습니다. 남은 약 20 % (복잡한 보고, 엔티티 간 쿼리)는 PostgreSQL을 사용할 때보다 더 많은 엔지니어링 노력이 필요합니다.

상태 관리 라이브러리 없이 상태 관리

Redux도, Zustand도, MobX도 없습니다.

Firebase가 바로 상태 저장소입니다. 데이터 흐름은 다음과 같습니다:

User action → hook → Firestore write → onSnapshot → React re‑render

Firestore가 진실의 원천이므로 동기화할 로컬 상태가 없습니다. 낙관적 업데이트가 지연을 메워 주며, 쓰기가 확정되면 스냅샷 리스너가 트리거되고 React가 영구 저장된 데이터로 다시 렌더링됩니다.

이렇게 하면 구식 상태, 동기화 충돌, 캐시 무효화와 같은 버그 카테고리를 완전히 없앨 수 있습니다. 데이터베이스가 언제나 옳습니다.

재무 계산: 단일 진실 원천

스페인은 부가가치세(VAT) 21 / 10 / 4 %가 있고, 카나리아 제도는 IGIC 7 / 3 / 0 %가 있으며, 프리랜서는 IRPF 원천징수(‑15 %)가 있습니다. 하나의 잘못된 반올림 연산이 세무 신고 오류를 초래합니다.

모든 세금 계산, 총액 산출, 반올림 연산은 중앙 집중식으로 처리합니다. 컴포넌트 안에 수식을 직접 넣지 마세요. 세금 버그를 고치면 모든 인보이스, 견적, 비용, 보고서에 동시에 적용됩니다.

// 모든 재무 연산은 동일한 엔진을 통과합니다
import { calculateTotal } from '@/lib/calculations';

// 인보이스든, 견적이든, 비용이든
const result = calculateTotal(lineItems, { taxType, withholding });

AI를 부가 기능이 아닌 일급 시민으로

AI 코파일럿은 UI 위에 얹은 챗봇이 아닙니다. 프론트엔드가 사용하는 동일한 API를 통해 실제 사용자 데이터를 다루는 타입이 지정된 함수 정의를 가지고 있습니다.

핵심 아키텍처 결정

  1. 함수 호출, RAG가 아니라 – AI는 구조화된 함수를 타입이 지정된 파라미터와 함께 호출합니다.
    create_invoice({ clientId, items, taxRate })
    이는 모호함이 없으며, 자연어 검색과는 다릅니다.
  2. 지연 로딩 – AI 모듈은 용량이 크기 때문에 사용자가 필요로 할 때만 로드됩니다.

(이하 내용은 다음 파트에 이어집니다)

rst는 채팅과 상호작용합니다. 채팅 버튼에 마우스를 올리면 사전 로딩이 시작되어, 사용자가 클릭할 때 모듈이 준비됩니다.
3. Context injection – 시스템 프롬프트에 사용자의 실제 비즈니스 컨텍스트(활성 클라이언트, 최근 청구서, 세금 의무)가 포함됩니다. AI는 추측이 아닌 실제 데이터를 기반으로 작동합니다.
4. Security boundaries – AI는 UI와 동일한 권한 모델을 사용합니다. 사용자가 접근할 수 없는 데이터에 접근할 수 없습니다. 함수 호출은 동일한 보안 규칙을 거칩니다.

대규모 i18n: 17개 언어

  • 기계 번역이 아닌 라벨 – 재무 용어를 포함한 전체 현지화.
  • 번역 파이프라인: 먼저 240 K 항목의 번역 메모리(매치율 97.8 %)를 사용하고, 이후에 AI를 활용해 누락된 부분만 번역합니다.
  • 전체 번역 실행당 비용이 $3.36에서 $0.30으로 감소했으며, 이는 91 % 절감에 해당합니다.
  • 17개 언어 모두 동등하게 유지됩니다. CI 검사에서 번역 키가 누락된 커밋을 차단합니다.

성능 결과

지표결과
Lighthouse (데스크톱)100 / 100 / 100 / 100
First Contentful Paint배포 가능한 아키텍처가 아직 구축 중인 아키텍처보다 더 뛰어납니다.

“AI‑Native ERP 구축” 시리즈의 Part 3. 이전 글: 55‑Tool MCP Server · Why I Built It Solo.

다음: 전통적인 ERP가 사라진 이유

Frihet — 무료, AI 기반 ERP.
Try it · Docs · npm

0 조회
Back to Blog

관련 글

더 보기 »