Skip to main content

POP 아키텍처 설계기 — MES+ERP+WMS를 하나의 SaaS로 만드는 기술적 도전

동남아시아 제조 기업의 현장을 보면 흥미로운 모순이 있다. 시스템은 존재하지만, 데이터는 연결되지 않는다. REINDEERS는 이 간극을 메우기 위해 POP(Production Operation Platform)를 설계했다. MES(제조실행), ERP(자원관리), WMS(창고관리)를 단일 SaaS로 통합하되, 독립 시스템이 아니라 기존 REINDEERS 생태계의 일부로 동작하게 만드는 것이 핵심이다.

하나 먼저 짚고 가자. POP의 아키텍처 선택은 단순히 "MES+ERP+WMS를 하나로 묶는다"는 수준이 아니다. 최종 목표는 회사 운영 자체가 AI로 전환될 수 있는 구조를 만드는 것이다. 사람은 전략과 방향을 결정하고, 실제 업무는 조직도에 등록된 AI Agent와 로봇이 실행한다. 이 글에서 설명하는 데이터 모델, 이벤트 구조, 모듈 경계, API-First 설계는 모두 그 AI 전환을 가능하게 하기 위한 기술적 전제 조건이다.

이 글은 POP의 설계 원칙과 논리 구조를 정리한 것이다. 왜 이 구조가 필요한지부터, 데이터 모델, 멀티테넌시, 모듈 통합, 기존 플랫폼과의 연결, AI Agent 통합 설계, 플랫폼 축까지 다룬다.

왜 POP가 필요한가

동남아 제조업의 현실: 시스템은 있지만, 흐름은 없다

태국의 중소 제조 공장을 예로 들어 보자. 생산 라인에서는 엑셀이나 구형 MES로 작업지시를 관리하고, 창고에서는 별도의 재고 장부나 WMS를 쓰며, 회계팀은 로컬 회계 패키지에서 매출과 원가를 관리한다. 각 시스템은 나름대로 동작하지만, 이들 사이에 실시간 데이터 흐름은 없다.

이 구조에서 다음 문제가 반복적으로 발생한다.

  • 이중 입력 -- 생산 완료 수량을 MES에 기록하고, 같은 숫자를 다시 재고 시스템에 수동 입력한다.
  • 데이터 지연 -- 원자재 소진이 회계에 반영되기까지 1~3일 걸린다. 그사이 발주 타이밍을 놓친다.
  • 가시성 부재 -- "지금 이 제품을 얼마나 만들 수 있는가"라는 단순한 질문에 답하려면 3개 부서에 확인해야 한다.
  • 크로스보더 복잡성 -- 태국에서 생산하고 한국에서 판매하는 B2B 구조에서, 생산 데이터와 수출 문서, 물류 추적이 별개 시스템에 존재한다.

$130B 이상 규모의 동남아 제조 시장에서 이 문제는 보편적이다. 대기업은 글로벌 엔터프라이즈 ERP를 도입하지만, 중소 제조업체(전체의 90% 이상)는 비용과 구현 복잡도 때문에 분리된 시스템을 유지할 수밖에 없다.

REINDEERS가 이미 해결한 것, 그리고 남은 간극

REINDEERS 플랫폼은 B2B 거래(Transaction)와 물류(DVRP)를 운영하고 있으며, 문서(Document AI)와 업무 자동화(Workflow AI)를 하나의 생태계에서 연결하는 구조를 구축 중이다. 4,300개 이상의 파트너가 등록되어 있으며, 발주와 포워딩을 수행한다. Document AI와 Workflow AI는 현재 구축 중이다.

하지만 핵심적인 간극이 남아 있었다. 거래 이전 단계인 "생산"과 "재고"다. 발주가 들어와도 "지금 생산 가능한가?", "원자재가 충분한가?", "이 물량을 언제까지 출고할 수 있는가?"에 대한 데이터가 플랫폼 안에 없었다. 이 간극은 곧 파트너의 비효율로 이어졌고, 플랫폼 전체 데이터 흐름의 완결성을 떨어뜨렸다.

POP는 이 간극을 메우기 위해 설계되었다. 생산(MES), 재고(WMS), 재무(ERP) 기능을 하나의 SaaS로 제공하되, 독립 시스템이 아니라 REINDEERS 생태계의 일부로 동작하게 만드는 것이 핵심이다.

Document AI Workflow AI Transaction DVRP POP (MES + ERP + WMS) Production Operation Platform Shared Data Layer -- Event + State + Log REINDEERS Platform Ecosystem

아키텍처 설계 원칙

POP의 아키텍처는 세 가지 설계 원칙 위에 세워졌다. 이 원칙들은 REINDEERS 플랫폼 전체에 일관되게 적용되며, POP가 독립된 제품이 아니라 생태계의 일부로 동작할 수 있는 기반이 된다.

Multi-Tenant SaaS -- 테넌트(회사) 단위로 데이터를 완전히 격리하면서, 인프라는 공유한다. 다수의 제조사를 수용할 수 있는 구조다. 테넌트별 설정(타임존, 통화, 언어, 활성 모듈)을 지원하여 다국적 환경에 대응한다.

Event + State + Log -- REINDEERS 전체 플랫폼의 데이터 모델과 동일한 패턴을 적용한다. 모든 엔티티는 현재 상태(State), 상태 변화 이벤트(Event), 변경 이력(Log)으로 구성된다. 이 구조는 추적 가능성, 감사, 시점 복원, AI 학습 데이터 축적을 동시에 가능하게 한다.

Modular Monolith -- MES, ERP, WMS는 독립적인 도메인 모듈로 설계하되, 하나의 배포 단위로 운영한다. 모듈 간 통신은 내부 이벤트 버스를 통해 느슨하게 결합한다. 처음부터 마이크로서비스로 분리하지 않고, 모듈 경계가 검증된 이후 필요에 따라 분리하는 전략이다.

Modular Monolith를 선택한 이유는 명확하다. 스타트업 단계에서 마이크로서비스는 운영 복잡도를 기하급수적으로 높인다. 모듈 간 경계가 확실하지 않은 상태에서 서비스를 분리하면 잘못된 경계에 묶이게 되고, 이를 나중에 수정하는 비용은 모놀리스에서 리팩터링하는 비용보다 훨씬 크다. 대신 모듈 경계를 코드 수준에서 엄격하게 유지하고, 모듈 간 직접 호출을 금지하며, 이벤트 기반 통신만 허용함으로써 언제든 분리할 수 있는 상태를 유지한다.

이 접근은 대규모 트래픽을 모듈형 모놀리스로 처리해 온 선행 기업들의 경험과 같은 맥락이다. 중요한 것은 아키텍처 패턴의 이름이 아니라, 모듈 경계를 유지하는 규율이다.

데이터 모델 설계

POP의 데이터 모델은 세 개의 도메인(MES, WMS, ERP)과 공유 마스터 데이터로 구성된다. 모든 엔티티는 Event+State+Log 패턴을 따르며, 도메인 간에는 이벤트를 통해 연결된다. 테이블의 세부 컬럼을 나열하는 대신, 각 모듈이 어떤 질문에 답해야 하는가를 중심으로 설계를 정리한다.

공유 마스터 데이터 (Shared Master)

도메인 모듈이 공통으로 참조하는 데이터는 Core 모듈에서 관리한다. 제품(SKU), 거래처(Partner), 창고(Warehouse), 단위(UOM) 등이 여기에 해당한다. 마스터 데이터의 변경은 이벤트로 전파되어 각 모듈이 자신의 캐시를 갱신한다.

핵심 설계 결정은 세 가지다. 첫째, 모든 마스터 엔티티에 테넌트 식별자를 반드시 포함해 멀티테넌트 격리의 기준을 단일 컬럼으로 강제한다. 둘째, 제품명처럼 국가별 표현이 다른 필드는 구조화된 다국어 필드(예: 한국어/태국어/영어 키 혼재)로 저장해, 렌더 시점에 언어를 선택한다. 셋째, 테넌트 범위 안에서 유일해야 하는 값(예: SKU 코드)은 복합 유니크 제약으로 묶어, 테넌트 간 충돌이 원천적으로 생기지 않게 한다.

// 공유 마스터의 핵심 엔티티 (개념)
products {
    id, tenant_id, sku, name(multi-lang),
    category, uom, status, metadata, timestamps
    unique(tenant_id, sku)
}

partners {
    id, tenant_id, code, name,
    type(supplier|customer|both), country, tax_id, status
    unique(tenant_id, code)
}

warehouses {
    id, tenant_id, code, name, timezone, status
    unique(tenant_id, code)
}

생산 도메인 (MES Module)

MES 모듈은 작업지시(Work Order), BOM(Bill of Materials), 생산 스케줄, 품질 검사를 관리한다. 핵심 설계 포인트는 BOM의 다단계 구조 지원과, 작업지시의 상태 전이를 이벤트로 추적하는 것이다.

BOM을 "헤더 + 라인"으로 쪼갠 이유는 버전 관리를 위해서다. 엔지니어링 변경이 일어나면 새 버전을 만들고, 이전 버전은 유효 기간만 닫아 둔다. 과거 작업지시가 참조한 BOM 버전은 영구히 보존되어야 하기 때문에, BOM을 덮어쓰는 구조는 쓰지 않는다. 작업지시는 계획/실적 수량을 함께 들고 있어서, "얼마 만들기로 했고, 얼마 만들었는가"를 한 행에서 알 수 있게 했다. 상태 전이는 열거형으로 제한되며, planned → released → in_progress → completed → closed 경로를 벗어난 갱신은 거부된다.

// MES 핵심 엔티티 (개념)
bom {
    id, tenant_id, product_id, version,
    status(draft|active|obsolete), effective_from, effective_to
    unique(tenant_id, product_id, version)
}

bom_lines {
    id, bom_id, material_id, quantity, uom,
    scrap_rate, sort_order
}

work_orders {
    id, tenant_id, wo_number, product_id, bom_id,
    planned_qty, produced_qty, defect_qty,
    status(planned|released|in_progress|completed|closed),
    scheduled_start/end, actual_start/end,
    source_po_id   // REINDEERS PO reference
    unique(tenant_id, wo_number)
}

quality_inspections {
    id, tenant_id, work_order_id,
    inspector, inspected_qty, passed_qty, defect_qty,
    defect_type, result(pass|fail|conditional),
    notes, inspected_at
}

재고 도메인 (WMS Module)

WMS 모듈은 SKU 관리, 로트 추적, 존/빈 위치 관리, FEFO(First Expired First Out) 출고 전략, ASN(입고예정통보)/OSN(출고예정통보)을 다룬다. 식품, 화장품 등 유통기한이 중요한 동남아 제조업 특성을 반영하여 FEFO를 기본 출고 전략으로 설계했다.

설계 핵심은 재고 행 자체가 로트 단위라는 점이다. 같은 제품이라도 로트 번호·입고일·만료일이 다르면 각각 별도 행으로 쌓인다. "가용 수량 = 총 수량 - 예약 수량"이 파생값으로 저장되어, 조회 시 계산 비용 없이 바로 읽을 수 있다. 재고 변동은 항상 이벤트 테이블에 append-only로 기록되어, "누가 언제 왜 이 로트에서 얼마를 꺼냈는가"를 역추적할 수 있다.

// WMS 핵심 엔티티 (개념)
warehouse_zones {
    id, warehouse_id, code, name,
    zone_type(raw|finished|quarantine|shipping),
    temperature(ambient|cold|frozen)
}

warehouse_bins {
    id, zone_id, code, max_capacity, current_load
}

inventory {
    id, tenant_id, product_id, warehouse_id, bin_id,
    lot_number, quantity, reserved_qty,
    available_qty = quantity - reserved_qty,  // 파생값
    expiry_date,       // FEFO 정렬 기준
    manufactured_date, unit_cost,
    status(available|reserved|quarantine|expired),
    updated_at
    unique(tenant_id, product_id, warehouse_id, bin_id, lot_number)
}

inventory_transactions {  // append-only 이벤트 로그
    id, tenant_id, inventory_id,
    tx_type(receive|issue|transfer|adjust|
            production_in|production_out),
    quantity,
    reference_type(work_order|po|asn|osn), reference_id,
    performed_by, performed_at, notes
}

재무 도메인 (ERP Module)

ERP 모듈은 발주(Purchase Order), 인보이스, 매입/매출 관리, 원가 추적을 담당한다. 핵심은 생산 데이터와 재고 데이터가 실시간으로 재무에 반영되는 것이다. 작업지시 완료 시 원자재 원가가 자동 계산되고, 재고 변동이 매출원가에 즉시 연동된다.

인보이스는 매입(payable)과 매출(receivable)을 같은 테이블에서 direction 필드로만 구분한다. 한 거래처에 대해 "우리가 줄 돈 / 받을 돈"을 한 뷰에서 보기 위해서다. 제조 원가는 작업지시 단위로 쪼개서 material / labor / overhead / quality_loss 네 종류의 비용 버킷에 누적한다. 품질 불량으로 인한 손실을 별도 버킷으로 두는 것은, 생산 효율 개선 ROI를 나중에 정량화하기 위해서다.

// ERP 핵심 엔티티 (개념)
purchase_orders {
    id, tenant_id, po_number, supplier_id,
    currency, total_amount,
    status(draft|approved|partially_received|received|closed),
    source_reindeers_id,  // REINDEERS Transaction ref
    ordered_at
    unique(tenant_id, po_number)
}

purchase_order_lines {
    id, po_id, product_id, quantity, unit_price,
    received_qty,
    line_total = quantity * unit_price  // 파생값
}

invoices {
    id, tenant_id, invoice_number, partner_id,
    direction(payable|receivable),
    currency, subtotal, tax_amount, total_amount,
    status(draft|sent|partially_paid|paid|cancelled),
    due_date, issued_at
    unique(tenant_id, invoice_number)
}

production_costs {
    id, tenant_id, work_order_id,
    cost_type(material|labor|overhead|quality_loss),
    amount, currency, calculated_at
}

Event+State+Log 패턴 적용

위 엔티티들은 State를 보여주지만, 실제로는 모든 상태 변화가 이벤트 테이블에 기록된다. 이 이벤트는 세 가지 역할을 동시에 수행한다.

// 도메인 이벤트 로그 (모든 도메인 공유)
domain_events {
    id, tenant_id,
    entity_type,   // work_order | inventory | purchase_order | invoice ...
    entity_id,
    event_type,    // created | status_changed | qty_updated | cost_calculated ...
    previous_state, new_state,  // 구조화된 스냅샷
    metadata,
    performed_by, occurred_at
}

// 역할 1: 감사 추적 — 누가, 언제, 무엇을 변경했는가
// 역할 2: 이벤트 전파 — 메시지 큐를 통해 다른 모듈에 변경 통지
// 역할 3: AI 학습 데이터 — 시계열 패턴으로 축적

// 조회 최적화를 위한 인덱스
//   (tenant_id, entity_type, entity_id)
//   (tenant_id, occurred_at desc)

멀티테넌시 구조

POP는 하나의 인스턴스에서 다수의 제조사를 격리된 환경으로 서비스할 수 있도록 설계되었다. 멀티테넌시 설계의 핵심 결정 사항과 구현 방식을 정리한다.

Row-Level Security (RLS)

테넌트 격리는 Row-Level Security로 구현한다. 모든 테이블에 tenant_id 컬럼이 존재하며, 데이터베이스의 행 단위 정책을 통해 애플리케이션 레벨과 DB 레벨 모두에서 데이터 격리를 보장한다.

// 요청 진입 시 세션 변수로 테넌트 식별자를 설정
session.current_tenant = 'tenant-uuid-here'

// 테이블별 RLS 정책 (개념)
policy tenant_isolation on work_orders:
    rows where tenant_id == session.current_tenant

// 애플리케이션 레이어에서
//   JWT → tenant_id 추출 → 세션 변수 설정
// 이 구조 덕분에 WHERE tenant_id = ? 를 빠뜨려도 DB가 차단한다

별도 스키마(schema-per-tenant)나 별도 데이터베이스(database-per-tenant) 방식도 검토했으나, 테넌트가 증가할 때의 운영 복잡도와 마이그레이션 비용을 고려하여 RLS 기반의 공유 스키마 방식을 선택했다. 대신 RLS를 애플리케이션 레벨 필터링의 "안전망"으로 사용하여 이중 보호를 적용한다.

테넌트 설정과 모듈 활성화

각 테넌트는 자체 설정을 가진다. 타임존, 기본 통화, 언어, 활성 모듈 등을 테넌트별로 구성할 수 있어 동일한 인프라에서 다양한 국가와 업종의 제조사를 수용한다.

tenants {
    id, code, name,
    timezone,       // 예: 'Asia/Bangkok'
    currency,       // 예: 'THB'
    locale,         // 예: 'th'
    modules_enabled,  // ["mes","wms","erp"] — 선택적 활성화
    config,           // FEFO/FIFO, 세금, 넘버링 규칙 등
    reindeers_org_id, // REINDEERS 조직 ID
    status
}
격리 방식 테넌트 확장성 마이그레이션 비용 격리 강도 POP 선택
Database per Tenant 낮음 매우 높음 최고 -
Schema per Tenant 중간 높음 높음 -
Shared Schema + RLS 높음 낮음 중간 (RLS 보완) 선택

Connection Pooling

멀티테넌트 환경에서 커넥션 풀 관리는 성능과 직결된다. POP는 외부 커넥션 풀러를 통해 커넥션 풀링을 처리하며, 요청별로 테넌트 세션 변수를 설정하는 방식을 사용한다. 트랜잭션 모드에서 세션 변수는 트랜잭션 범위 내에서만 유효하므로 테넌트 간 세션 오염이 발생하지 않는다.

고부하 테넌트(대규모 제조사)의 경우 전용 커넥션 풀을 할당할 수 있는 구조도 마련해 두었다. 테넌트 설정의 config.pool_size 값으로 제어하며, 기본값은 공유 풀을 사용한다.

모듈 분리와 통합

POP의 모듈 아키텍처에서 가장 중요한 규칙은 "모듈 간 직접 함수 호출 금지"다. MES 모듈이 WMS 모듈의 재고를 직접 조회하거나, ERP 모듈이 MES의 작업지시를 직접 수정하는 것을 허용하지 않는다. 대신 모든 모듈 간 통신은 이벤트 버스를 통한다.

이벤트 기반 모듈 통신

모듈 간 이벤트 흐름 (생산 완료 시나리오)
MES Module
작업지시 상태 → completed
work_order.completed
Event Bus
Topic Exchange · fan-out
WMS Module
완제품 입고 + 원자재 차감
inventory_updated
ERP Module
제조원가 계산
cost_calculated
domain_events
Event Store — 모든 이벤트 영구 기록
MES가 발행한 이벤트 하나가 WMS·ERP에 병렬로 소비되고, 모든 이벤트는 Event Store에 남는다.

위 다이어그램은 가장 빈번한 시나리오인 "생산 완료"를 보여준다. 실제 이벤트 흐름은 다음과 같다.

  1. MES 모듈에서 작업지시(Work Order) 상태가 completed로 변경된다.
  2. work_order.completed 이벤트가 이벤트 버스에 발행된다.
  3. WMS 모듈이 이벤트를 소비하여 완제품을 입고 처리하고, BOM 기준으로 원자재를 차감한다.
  4. ERP 모듈이 같은 이벤트를 소비하여 소비된 원자재의 가중평균 원가를 기반으로 제조원가를 계산한다.
  5. WMS와 ERP 각각의 처리 결과도 이벤트로 기록되어 후속 처리에 사용된다.

공유 서비스

도메인 모듈과 별개로, 횡단 관심사(cross-cutting concerns)는 공유 서비스로 분리한다.

공유 서비스 역할 소비 모듈
Auth Service 토큰 발급, RBAC, 테넌트 식별 전체
Notification Service 이메일, Telegram, Push 알림 전체
File Storage 첨부 파일, 보고서 PDF, 이미지 전체
Audit Log domain_events 기반 감사 추적 전체
Number Generator 테넌트별 WO/PO/INV 번호 채번 MES, ERP
Report Engine 생산/재고/재무 리포트 생성 전체

모듈 독립성 보장 규칙

모듈 간 경계를 유지하기 위해 다음 규칙을 코드 레벨에서 강제한다.

  • Import 제한 -- MES 모듈은 WMS/ERP 모듈의 내부 함수를 참조할 수 없다. 공유할 타입 정의는 Core 모듈에 둔다.
  • DB 접근 제한 -- 각 모듈은 자기 도메인 테이블에만 쿼리한다. 다른 모듈의 데이터가 필요하면 이벤트 페이로드에 포함하거나, Read Model(뷰)을 사용한다.
  • 트랜잭션 경계 -- 모듈 간 트랜잭션은 허용하지 않는다. 모듈 A의 트랜잭션이 완료된 후 이벤트가 발행되고, 모듈 B는 별도 트랜잭션에서 처리한다. 실패 시 보상 이벤트(compensation event)로 처리하는 Saga 패턴을 따른다.

REINDEERS 플랫폼과의 연결

POP가 독립 제품이 아닌 REINDEERS 생태계의 일부로 동작하도록 설계했다는 것은, 기존 플랫폼(Transaction, DVRP)과 구축 중인 서비스(Document AI, Workflow AI)에 데이터가 자연스럽게 흐르도록 한다는 뜻이다. 이 연결이 POP의 가장 큰 차별점이다.

Transaction -> POP MES: REINDEERS에서 발주(PO)가 확정되면 po.confirmed 이벤트가 POP으로 전달된다. POP MES는 이 이벤트를 수신하여 해당 제품의 BOM을 조회하고, 작업지시(Work Order)를 자동 생성한다. 발주 수량, 납기일, 제품 사양이 작업지시에 그대로 반영되어 수동 입력 없이 생산 계획이 시작된다.

POP WMS -> DVRP: POP WMS에서 출고 처리가 완료되면 shipment.ready 이벤트가 DVRP(Delivery Vehicle Routing Platform)로 전달된다. DVRP는 출고 제품의 수량, 무게, 목적지 정보를 받아 배송 경로를 최적화하고 차량을 배정한다.

Transaction -> POP ERP: REINDEERS 거래에서 발생하는 정산 데이터(결제 완료, 매출 확정)가 POP ERP로 흘러 매출채권/매입채무에 반영된다. 역방향으로는 POP ERP의 발주 데이터가 REINDEERS Transaction에 연동되어 거래-생산-재무가 하나의 데이터 루프를 형성한다.

POP -> Document AI: POP의 생산 실적, 품질 검사 데이터, 재고 현황이 Document AI의 데이터 소스로 활용되도록 설계했다. 월간 생산 보고서, 품질 분석 리포트, 재고 실사 보고서를 POP 데이터 기반으로 자동 생성할 수 있을 것으로 기대한다.

이 연결의 기술적 기반은 REINDEERS 전체 플랫폼이 동일한 이벤트 버스와 동일한 이벤트 포맷을 사용한다는 점이다. 플랫폼 간 이벤트는 라우팅 키 규칙 {platform}.{entity}.{event_type}으로 구분되며, 각 플랫폼은 필요한 이벤트만 구독한다.

이 구조의 핵심 가치는 "하나의 입력이 모든 시스템을 업데이트한다"는 것이다. 현재 동남아 제조사가 겪는 이중 입력 문제가 아키텍처 수준에서 해결된다. 발주 하나가 들어오면 작업지시가 생성되고, 생산이 완료되면 재고가 갱신되며, 출고되면 물류가 추적되고, 정산되면 재무에 반영된다. 사람은 각 단계에서 확인하고 승인만 하면 된다.

AI Agent 통합 설계 — 조직도 안으로 들어오는 AI

POP의 Event+State+Log 구조는 단순히 AI 학습 데이터를 축적하기 위한 것이 아니다. AI Agent가 조직도 안의 직원으로 등록되어 실제 업무를 실행할 수 있는 기반을 만들기 위한 것이다. 모든 상태 변화가 이벤트로 기록되고, 모든 업무가 API로 호출 가능하고, 모든 권한이 결재라인에 연결되어 있기 때문에, AI Agent가 사람 직원과 완전히 동일한 방식으로 POP를 사용할 수 있다.

직원 유형: 사람 / AI Agent / 로봇

POP의 직원 테이블에는 employee_type 컬럼이 존재한다. 값은 human, ai_agent, robot 세 가지다. 세 유형은 동일한 조직도, 동일한 결재라인, 동일한 RBAC 권한 체계를 공유한다. 구매팀에 사람 팀장 1명, AI Agent 3명, 협력사 담당자(사람) 2명이 함께 소속될 수 있다. 생산팀에서는 로봇이 Work Order를 직접 수신하고 완료 이벤트를 발행한다.

// 조직 구성원 (사람·AI Agent·로봇을 같은 테이블에서 관리)
employees {
    id, tenant_id, department_id,
    employee_type(human | ai_agent | robot),
    display_name, role(manager | staff | operator | ...),
    agent_profile,    // Agent 전용: 모델, 도구, 예산 한도
    robot_profile,    // 로봇 전용: 기계 ID, 센서, 허용 작업
    monthly_budget,   // 월 예산 한도 (초과 시 사람 승인)
    status
}

Agent나 로봇이 조직의 "직원"이기 때문에, 이들이 수행한 작업은 사람 직원의 작업과 완전히 같은 방식으로 domain_events에 기록된다. performed_by 필드로 누가 수행했는지 구분할 수 있지만, 이벤트의 효력과 권한 체크는 동일하다. 사람이 발주한 PO도, AI Agent가 발주한 PO도, 같은 테이블의 같은 스키마에 들어간다.

CEO Agent + 부서별 Agent 구조

POP 위에서 AI 법인 구조는 단순한 상하 관계를 갖는다. 사용자(사람)가 전략과 목표를 CEO Agent에게 전달하면, CEO Agent는 이를 구매·생산·영업·물류·재무·통관 같은 부서 Agent에게 분해해서 넘긴다. 부서 Agent는 자기 도메인의 API를 직접 호출하여 실제 업무를 실행한다. 이 구조가 동작하기 위해 POP는 모든 기능을 API-First로 설계했다. AI Agent도 결국 POP API의 클라이언트다.

API-First 설계가 AI Agent 통합의 조건인 이유가 여기 있다. 웹 UI를 먼저 만들고 나중에 API를 추가하는 구조에서는 Agent가 사용할 수 있는 기능이 절반도 안 된다. POP는 반대다. 모든 비즈니스 로직이 REST API에 먼저 구현되고, 웹 UI·모바일·AI Agent가 같은 API를 소비한다. Agent가 "공급사 A에게 원자재 X 500kg를 발주"하는 것은, 사람이 웹에서 같은 작업을 하는 것과 같은 API 콜이다.

안전장치: 예산 한도 · 감사 로그 · 에스컬레이션

Agent가 실제 업무를 실행할 수 있다는 것은 실수하거나 악용될 수도 있다는 뜻이다. POP는 세 가지 안전장치를 기본 탑재한다.

  • 월 예산 한도 -- Agent별로 월 집행 가능 금액 상한이 설정된다. 발주·정산·계약 Action이 한도를 초과하면 자동으로 사람 승인 단계로 라우팅된다.
  • 감사 로그(domain_events) -- AI Agent가 실행한 모든 Action은 사람이 실행한 Action과 동일한 이벤트 로그에 기록된다. performed_bymetadata를 보면 어떤 Agent가, 어떤 컨텍스트에서, 어떤 RAG 근거로 판단했는지를 역추적할 수 있다.
  • 에스컬레이션 룰 -- Agent가 불확실하다고 판단한 상황(신뢰도 임계치 이하, 과거 유사 케이스 부족, 조건 충돌)은 자동으로 사람 담당자에게 넘어간다. 사람은 전체 업무를 보는 게 아니라 Agent가 넘긴 예외만 본다.

Agent가 사용하는 AI 능력

부서 Agent 안에서는 여러 AI 능력이 내부 도구로 사용된다. 수요 예측, 재고 최적화, 생산 스케줄링, 품질 예측 같은 기능들이 독립적인 "AI 기능"이 아니라, Agent가 판단 과정에서 호출하는 도구(tool)로 구성된다.

수요 예측 -- 과거 발주 데이터(REINDEERS Transaction) + 생산 실적(POP MES) + 계절성 패턴을 결합하여 향후 수요를 추정한다. 구매 Agent가 "이번 달 원자재 X 발주량을 정할" 때 참조한다.

재고 최적화 -- 수요 예측 결과와 리드타임 분포를 기반으로 적정 재주문점과 안전재고를 계산한다. 구매 Agent가 소모품 자동 재주문을 집행하기 전 최종 수량을 결정할 때 사용한다.

생산 스케줄 최적화 -- 복수의 작업지시를 생산 라인 용량, 원자재 가용량, 납기 제약을 고려하여 최적 순서로 배치한다. 생산 Agent가 일일 작업 배분을 할 때 참조한다.

품질 예측 -- 과거 품질 검사 기록과 공정 파라미터의 상관관계를 학습하여 불량 발생 확률을 미리 계산한다. 생산 Agent가 고위험 로트를 감지하면 사람 품질 담당자에게 에스컬레이션한다.

RAG 파이프라인: POP + REINDEERS 데이터 활용

AI 기능의 공통 기반은 RAG(Retrieval-Augmented Generation) 파이프라인이다. POP 단독 데이터뿐 아니라, REINDEERS 거래 이력, 물류 실적, 문서 데이터까지 통합하여 더 풍부한 컨텍스트를 AI에 제공한다.

예를 들어 "이 제품의 적정 안전재고는 얼마인가?"라는 질문에 답하려면, POP의 재고 변동 이력만으로는 부족하다. REINDEERS의 거래처별 주문 패턴, 계절별 수요 변동, 물류 리드타임 실측값까지 필요하다. 5개 플랫폼의 데이터가 하나의 이벤트 로그 위에 모이도록 설계했기 때문에 이 통합 분석이 가능해질 것으로 기대한다. 이것이 독립 MES/ERP/WMS 솔루션과 POP의 결정적 차이다.

플랫폼 축

POP는 REINDEERS 생태계의 기존 인프라를 그대로 활용한다. 새로운 기술을 도입하는 대신, 검증된 스택을 재사용하여 운영 복잡도를 최소화한다. 구체적인 제품명보다, 각 축에서 어떤 성질을 충족해야 하는지가 중요하다.

레이어 요구 성질 선택 이유
관계형 DB 행 단위 보안, 구조화 필드, 파생 컬럼, 파티셔닝 멀티테넌트 격리와 감사 로그 대량 저장 요구
캐시 / 실시간 인메모리 키-값, TTL, 분산 동기화 세션, 실시간 재고 상태, 레이트 리밋
메시지 큐 Topic Exchange, durable queue, DLQ 이벤트 팬아웃과 느슨한 모듈 결합
API REST + 스키마 기반 명세(API-First) 모바일/웹/외부 연동/AI Agent 통일 인터페이스
인증 서명 검증형 토큰 + RBAC + ABAC 테넌트·역할·속성 기반 접근제어
파일 저장 오브젝트 스토리지 + 수명 정책 생산 보고서, 품질 사진, 첨부 문서
모니터링 실시간 알림 + 구조화 로깅 Telegram 채널 + 대시보드 (기존 패턴)
배포 컨테이너 + CI/CD 무중단 배포, 테넌트 영향 최소화

API-First 설계

POP는 웹 UI만을 위한 시스템이 아니다. 모든 기능이 REST API로 먼저 설계되고, 웹과 모바일은 이 API를 소비하는 클라이언트일 뿐이다. 이 접근의 장점은 세 가지다.

  • 모바일 대응 -- 공장 현장에서 태블릿이나 스마트폰으로 작업지시 확인, 품질 검사 입력, 재고 확인이 가능하다. 동남아 제조 현장에서 데스크탑 기반 시스템은 현실적이지 않다.
  • 외부 연동 -- 파트너사의 기존 시스템(ERP, SCM)과 API 수준에서 연동할 수 있다. CSV 파일을 주고받는 것이 아니라, 실시간 API 연동으로 데이터를 동기화한다.
  • 자동화 -- Workflow AI에서 POP API를 직접 호출하여 생산/재고/재무 업무를 자동화할 수 있다. "매일 오전 9시에 재고 부족 품목을 확인하고 자동 발주"와 같은 시나리오가 코드 없이 가능하다.

이벤트 테이블 파티셔닝

domain_events 테이블은 시간이 지나면서 가장 빠르게 증가하는 테이블이다. 제조사당 하루 수천~수만 건의 이벤트가 발생할 수 있으므로, 시계열 파티셔닝을 적용한다.

// 월 단위 파티셔닝 (개념)
domain_events partitioned by RANGE(occurred_at)

// 파티션 자동 생성
partition domain_events_2026_04
  for values [2026-04-01, 2026-05-01)

// 오래된 파티션은 분리 → 콜드 스토리지 이동

파티셔닝의 이점은 쿼리 성능뿐 아니라 운영에서도 나타난다. 최근 데이터를 자주 조회하는 실시간 대시보드는 최신 파티션만 스캔하고, AI 학습을 위한 과거 데이터 조회는 해당 기간 파티션에만 접근한다. 오래된 파티션은 콜드 스토리지로 이동하여 스토리지 비용을 최적화할 수 있다.

마무리: 왜 이 아키텍처가 중요한가

POP의 기술적 도전은 MES, ERP, WMS를 각각 만드는 것이 아니다. 이 셋을 하나의 데이터 모델, 하나의 이벤트 버스, 하나의 멀티테넌트 인프라 위에서 동작하게 만드는 것이다. 그리고 그 위에 REINDEERS의 기존 4개 플랫폼 데이터를 연결하는 것이다.

동남아시아 중소 제조업체에게 엔터프라이즈 수준의 통합 시스템을 SaaS로 제공한다는 것은, 기존에는 대기업만 가능했던 디지털 전환을 민주화하겠다는 뜻이다. POP는 2026년 4~5월 베타를 앞두고 있으며, 선정된 B2B 파트너에게 우선 적용할 예정이다.

기술적으로 가장 중요하게 지키려는 것은 "처음부터 완벽한 시스템을 만들지 않겠다"는 원칙이다. Modular Monolith 구조를 선택한 이유도, 이벤트 기반 통신을 강제한 이유도, 모듈별 독립 트랜잭션을 적용한 이유도 모두 같다. 지금은 하나의 배포 단위로 빠르게 움직이되, 모듈 경계가 실전에서 검증된 이후에 필요한 만큼만 분리하겠다는 것이다.

REINDEERS의 모든 플랫폼은 같은 철학 위에 만들어졌다. 문서, 워크플로우, 거래, 물류, 그리고 이제 생산까지. 하나의 데이터 흐름, 하나의 이벤트 모델, 하나의 AI 파이프라인. 이 연결이 쌓일수록 플랫폼은 강해지고, 대체하기 어려워진다.

그리고 이 모든 연결의 위에 AI Agent가 직원으로 등록된다. 사람이 전략을 결정하고, CEO Agent가 부서별 Agent에게 목표를 분해해 넘기고, 부서 Agent가 POP API를 통해 실제 업무를 실행하는 구조. Tool(2026) → Assistant(2027) → Agent Team(2028~29) → Autonomous Operator(2030) 로드맵을 따라, POP는 ERP가 아니라 AI 법인을 운영하는 운영 체제로 성장한다. 그것이 POP를 만드는 진짜 이유이고, 이 아키텍처가 중요한 이유다.

관련 글

Popular posts from this blog

Reindeers Workflow: B2B 파트너 업무 효율과 자동화를 위한 워크플로우 플랫폼

B2B 국제 무역에서 하나의 거래가 완료되기까지 관여하는 시스템과 사람의 수는 예상보다 훨씬 많다. 견적 요청에서 시작해 공급사 선정, 발주, 포워딩 비딩, 통관 서류 준비, 출하, 배송, 정산까지 — 각 단계마다 서로 다른 담당자가 서로 다른 도구에서 수작업을 반복한다. 이 현장에서 반복적으로 발생하는 비효율은 분명하다. 바이어가 견적을 확정하면 공급사에게 이메일이나 메신저로 직접 통보해야 하고, 결제가 완료되면 수동으로 정산 시트에 옮기면서 1~3일이 소요된다. 출하 후에는 선적 정보를 기반으로 CI, PL, CO를 수동 생성하며 누락이 발생하고, 배송 완료 후 공급사/포워더 정산을 수작업으로 대조하면서 오차가 누적된다. ERP, 이메일, 스프레드시트, CRM에 같은 데이터를 반복 입력하는 것도 일상이다. 이 문제들의 공통점은 명확하다. "이벤트가 발생했을 때 후속 작업이 자동으로 실행되지 않는다" 는 것이다. 견적이 확정되었다는 '사실'은 시스템에 기록되지만, 그 사실이 다음 단계의 업무를 자동으로 트리거하지는 않는다. Reindeers Workflow는 이 문제를 해결하기 위해 만들어졌다. 단순히 "자동화 도구를 제공한다"가 아니라, REINDEERS 플랫폼에서 발생하는 실제 거래 이벤트를 기반으로 후속 업무가 자동 실행되는 구조를 만드는 것이다. REINDEERS 플랫폼과의 연결: 거래 이벤트가 워크플로우를 트리거한다 Reindeers Workflow의 가장 중요한 차별점은 범용 자동화 도구가 아니라 REINDEERS 본 플랫폼의 거래 이벤트에 직접 연결 된다는 것이다. REINDEERS에서 발생하는 핵심 거래 이벤트가 MQ(Message Queue)를 통해 워크플로우의 트리거가 된다. 거래 이벤트 트리거되는 워크플로우 실행 내용 quote.confirmed 공...

팀과 기술의 리빌드 — 다시 일하는 법을 정비하다

1. 리빌드의 시작 — 사람부터 바꿨다 2025년 4월 초, REINDEERS는 중대한 결정을 내렸다. 시스템을 새로 만드는 일보다 먼저, 사람을 바꾸기로 한 것이다. 플랫폼은 기술로 움직이지만, 운영의 일관성을 무너뜨리는 것은 언제나 사람이다. 결국 기존 직원들은 모두 퇴사했다. 이전 팀은 실험적이었지만, 운영 가능한 구조를 만들기엔 역부족이었다. 남은 것은 코드 일부와 배포 스크립트뿐이었다. 우리는 그 위에 새로운 문화를 세우기보다, 완전히 새 팀을 만드는 길을 선택했다. 이것이 네 번째 팀 교체였다. 2015년 IMARKET Thailand 창업 이후 10년 동안 팀이 네 번 바뀌었다는 사실은 글로벌 스타트업이 겪는 현실을 그대로 보여준다. 2. 새 팀의 탄생 — 기술 커트라인부터 통과해야 했다 신규 채용의 기준은 단순했다. " 운영 가능한 기술을 이해하는가 ." 단순히 코드를 작성할 줄 아는 개발자가 아니라, 시스템이 어떻게 동작하고 복제되며, 장애를 어떻게 복구해야 하는지를 아는 엔지니어만이 합류할 수 있었다. 기술 커트라인 (필수 항목) Nuxt 3 / Vue3 + SSR 구조 이해 API 서버 설계 경험 CI/CD 파이프라인 구축 및 유지 경험 COS/CDN 배포 자동화 경험 Redis TTL 관리, MQ(AMQP) 이벤트 설계 경험 Git 브랜치 전략 및 Pull Request 프로세스 숙지 테스트 주도 개발(TDD) 환경 설정 경험 신규 구성원들은 모두 위 기준을 통과해야 했으며, 각자 DevOps, Front, API, Data, AI 셀로 배치되었다. 시스템 설계...

레인디어스, Buybly로 동남아시아 산업자재 시장 혁신

B2B 오픈마켓 REINDEERS, 한국 기업의 글로벌 진출을 돕다 레인디어스, 머신러닝 기반의 산업자재 매칭 솔루션으로 경쟁력 강화 김명훈 레인디어스 대표 산업자재 시장의 복잡성과 유통장벽은 많은 기업들에게 큰 도전 과제가 되어왔다. 특히 동남아시아 시장 진출을 원하는 한국의 산업자재 제조사들은 현지의 불투명한 거래 환경과 물류 문제로 어려움을 겪어왔다. 이러한 상황에서 레인디어스의 REINDEERS 플랫폼은 새로운 기회를 제시하고 있다. REINDEERS는 B2B 오픈마켓으로, 한국 기업들이 손쉽게 동남아시아 시장에 진출할 수 있도록 지원하며, 유통의 복잡성을 해결하는 혁신적인 솔루션으로 주목받고 있다. 이러한 변화의 중심에는 레인디어스 대표가 있다. 그는 지난 9년간 태국에서의 경험을 바탕으로 고객의 pain point를 해결하기 위해 REINDEERS를 개발했다. 이번 인터뷰를 통해 그의 비전과 경영 철학, 그리고 REINDEERS가 어떻게 산업자재 시장을 변화시키고 있는지에 대해 깊이 있는 이야기를 나누게 되었다. 김명훈 레인디어스 대표 -.소개 레인디어스는 국내 산업자재 제조사들이 동남아시아 시장에 쉽게 진출할 수 있도록 돕는 B2B 오픈마켓인 REINDEERS를 운영하고 있다. 해외 시장 진출에서 가장 큰 장애물인 유통, 물류, 무역의 장벽을 해결해주는 것이 이 플랫폼의 핵심이다. REINDEERS는 단순한 거래 플랫폼이 아니라, 산업자재 구매와 공급 과정을 간소화하고 최적화하는 One-Stop 솔루션으로 자리 잡았다. 레인디어스의 서비스는 REINDEERS와 Enterprise Solution(ERP, POP, WMS)으로 구성되어 있다. 이 솔루션은 동남아시아 현지의 고객사와 공급사에 맞춤형으로 제공되며, 산업현장의 선진화를 이끌어낸다. 기업 운영과 생산 관리, 재고 관리를 전산화해 이익을 극대화하는 데 기여하고 있다. REINDEERS는 산업현장에서 획득한 Raw data를 활용해 인공지능 분석을 통해 발주 ...