Tag: ERP

  • B2B SaaS 멀티테넌트 구조 설계 가이드 | 실제 개발 사례 기반

    B2B SaaS 멀티테넌트 구조 설계 가이드 | 실제 개발 사례 기반

    인베스트리 투자조합 관리 ERP, Lotus Soft 창업사관학교 플랫폼, Athena 정보보호관리 시스템 — 세 프로젝트 모두 “여러 기업이 하나의 플랫폼을 각자의 공간으로 사용”하는 멀티테넌트 구조입니다. 실제 개발 경험으로 멀티테넌트 설계의 핵심을 정리합니다.


    멀티테넌트(Multi-tenant)란?

    하나의 소프트웨어 인스턴스를 여러 고객(테넌트)이 공유하는 구조입니다. 각 테넌트는 자신의 데이터만 보고 관리하며, 다른 테넌트의 데이터는 볼 수 없습니다.

    대표적인 예: Slack, Notion, Salesforce. 같은 소프트웨어인데 삼성 직원은 삼성 워크스페이스만, LG 직원은 LG 워크스페이스만 보입니다.


    멀티테넌트 DB 설계 3가지 방식

    방식 1 — 데이터베이스 완전 분리

    테넌트마다 별도의 데이터베이스를 생성합니다.

    tenant_a_db
      ├── users
      ├── projects
      └── invoices
    
    tenant_b_db
      ├── users
      ├── projects
      └── invoices
    

    장점: 완벽한 데이터 격리, 테넌트별 독립적 백업/복원 가능, 성능 예측 가능

    단점: 테넌트 수가 늘면 DB 수도 늘어 관리 복잡도 증가, 비용 높음

    Athena처럼 정보보호 데이터를 다루거나 금융 데이터가 포함된 경우 이 방식이 적합합니다.


    방식 2 — 스키마 분리

    같은 DB, 테넌트별 스키마(네임스페이스)를 분리합니다. PostgreSQL에서 주로 사용합니다.

    -- tenant_a 스키마
    CREATE SCHEMA tenant_a;
    CREATE TABLE tenant_a.users (...);
    
    -- tenant_b 스키마
    CREATE SCHEMA tenant_b;
    CREATE TABLE tenant_b.users (...);
    

    장점: DB는 하나, 논리적 분리 가능

    단점: 스키마 수가 많아지면 마이그레이션 관리가 복잡


    방식 3 — 행 수준 분리 (Row-Level Security)

    같은 테이블에 tenant_id 컬럼으로 구분합니다.

    CREATE TABLE users (
      id UUID PRIMARY KEY,
      tenant_id UUID NOT NULL,  -- 테넌트 구분자
      name VARCHAR(100),
      email VARCHAR(255)
    );
    
    -- 조회 시 반드시 tenant_id 필터 적용
    SELECT * FROM users WHERE tenant_id = 'tenant_a_uuid';
    

    장점: 구조 단순, 비용 낮음, 테넌트 추가 쉬움

    단점: 실수로 tenant_id 필터를 빠뜨리면 데이터 노출 위험

    인베스트리, Lotus Soft처럼 중간 규모의 B2B SaaS에 적합합니다. 단, 모든 쿼리에 tenant_id 필터를 강제하는 미들웨어 레이어가 필수입니다.


    권한 관리 (RBAC) 설계

    멀티테넌트 SaaS에서 권한 관리는 두 축으로 나뉩니다.

    축 1 — 플랫폼 레벨: 슈퍼 어드민(플랫폼 전체 관리), 테넌트 어드민(자사 관리), 일반 사용자

    축 2 — 기능 레벨: 읽기, 쓰기, 삭제, 관리

    Lotus Soft의 경우:

    • 슈퍼 어드민: 전체 창업사관학교와 스타트업 데이터 열람, 시스템 설정
    • 서브 어드민(창업사관학교): 자기 소속 스타트업만 관리, 프로그램 등록
    • 테넌트(스타트업): 자사 정보와 신청한 프로그램만 확인

    이 구조를 DB로 표현하면:

    CREATE TABLE roles (
      id UUID PRIMARY KEY,
      name VARCHAR(50),         -- 'super_admin', 'tenant_admin', 'user'
      tenant_id UUID,           -- NULL이면 플랫폼 레벨 역할
      permissions JSONB         -- {"read": true, "write": true, "delete": false}
    );
    

    빌링(과금) 구조 설계

    SaaS의 과금은 테넌트 단위로 이루어집니다. Lotus Soft에서 계정 유료화 버전에 따라 접근 가능한 기능이 달라지는 구조를 구현했습니다.

    플랜 테이블:

    CREATE TABLE plans (
      id UUID PRIMARY KEY,
      name VARCHAR(50),         -- 'free', 'pro', 'enterprise'
      features JSONB,           -- 플랜별 가능 기능 목록
      price_monthly DECIMAL
    );
    
    CREATE TABLE tenant_subscriptions (
      tenant_id UUID REFERENCES tenants(id),
      plan_id UUID REFERENCES plans(id),
      started_at TIMESTAMP,
      expires_at TIMESTAMP
    );
    

    기능 제한 체크:

    // 미들웨어에서 플랜 기능 확인
    const canUseFeature = async (tenantId, feature) => {
      const subscription = await getTenantSubscription(tenantId);
      return subscription.plan.features[feature] === true;
    };
    

    테넌트 온보딩 자동화

    새 고객(테넌트)이 가입했을 때 자동으로 설정이 완료되어야 합니다.

    온보딩 프로세스:

    1. 테넌트 레코드 생성
    2. 어드민 계정 생성 및 이메일 발송
    3. 기본 플랜 적용
    4. 초기 데이터 세팅 (샘플 데이터 또는 빈 상태)
    5. 웰컴 이메일 발송

    이 과정을 수동으로 하면 실수가 생기고 시간이 걸립니다. 가입 즉시 자동화되는 파이프라인을 처음부터 설계해야 합니다.


    실제 개발 시 자주 발생하는 버그

    버그 1 — tenant_id 필터 누락: 쿼리에서 tenant_id를 빠뜨려 다른 테넌트 데이터가 노출. 반드시 모든 쿼리에 자동으로 tenant_id를 주입하는 미들웨어 레이어를 만들어야 합니다.

    버그 2 — 공유 리소스 캐시 충돌: 레디스 캐시 키에 tenant_id를 포함하지 않으면 A 테넌트 캐시가 B 테넌트에 노출됩니다. 캐시 키는 반드시 {tenant_id}:{resource_type}:{id} 형식으로.

    버그 3 — 파일 저장소 분리 미흡: S3처럼 파일을 저장할 때 테넌트별 폴더 구조를 만들지 않으면 파일이 섞입니다. s3://bucket/{tenant_id}/files/{filename} 구조를 처음부터 적용하세요.


    마치며

    멀티테넌트 SaaS는 처음부터 올바르게 설계하지 않으면 나중에 수정하는 비용이 막대합니다. 특히 데이터 격리와 권한 관리는 보안 사고로 이어질 수 있어 더욱 중요합니다.

    인베스트리, Lotus Soft, Athena 세 프로젝트를 통해 확인한 것은, “완벽한 멀티테넌트 설계는 없지만, 처음에 어떤 방식을 선택할지 팀 전체가 합의하고 일관되게 지키는 것”이 가장 중요하다는 점입니다.

  • SaaS B2B 플랫폼 개발 전략 — 투자 조합 관리 ERP부터 정보보호 솔루션까지

    SaaS B2B 플랫폼 개발 전략 — 투자 조합 관리 ERP부터 정보보호 솔루션까지

    인베스트리 투자조합 관리 ERP, Athena 정보보호관리 시스템, Lotus Soft 창업사관학교 지원 플랫폼. 세 가지 모두 B2B SaaS 프로젝트입니다. B2B SaaS를 개발하면서 반복적으로 마주치는 공통 과제들을 정리합니다.

    B2B SaaS가 B2C 앱과 다른 점

    B2C 앱은 “일반 사용자 한 명”을 위한 서비스입니다. 회원가입하면 바로 쓸 수 있고, 데이터는 내 것입니다.

    B2B SaaS는 다릅니다. “기업 조직”이 사용하고, 조직 내에 여러 역할의 사용자가 있으며, 기업마다 데이터가 철저히 분리되어야 합니다.

    이 차이가 설계의 핵심 복잡성을 만듭니다.

    핵심 설계 1 — 멀티테넌트 아키텍처

    SaaS의 가장 중요한 설계 개념입니다. 하나의 플랫폼을 여러 기업(테넌트)이 공유하되, 각 기업의 데이터는 완전히 분리되어야 합니다.

    Lotus Soft의 경우: 슈퍼 어드민(플랫폼 전체 관리), 서브 어드민(창업사관학교), 테넌트(입주 스타트업) 3계층으로 나뉩니다. 각 레이어가 볼 수 있는 데이터와 할 수 있는 작업이 다릅니다.

    인베스트리의 경우: GP(업무집행조합원)별로 독립적인 ERP 공간을 가집니다. A GP의 데이터는 B GP가 절대 볼 수 없어야 합니다.

    멀티테넌트 구현 방식은 크게 세 가지입니다:

    • 데이터베이스 분리: 테넌트별로 별도 DB. 격리성 최고, 비용 높음.
    • 스키마 분리: 같은 DB, 테넌트별 스키마. 중간 수준.
    • 행 수준 분리: 같은 테이블, 테넌트 컬럼으로 필터. 비용 낮음, 격리 구현 주의 필요.

    규모와 보안 요구사항에 따라 방식을 선택해야 합니다.

    핵심 설계 2 — 권한 관리 시스템 (RBAC)

    Role-Based Access Control. 역할에 따라 접근 권한을 부여하는 방식입니다.

    예를 들어 Athena 정보보호관리 시스템에서:

    • 슈퍼 어드민: 모든 기업 데이터 접근, 시스템 설정 변경
    • 기업 어드민: 자사 데이터만 접근, 부서원 계정 관리
    • 일반 사용자: 자신의 업무 영역만 접근, 입력 가능

    권한 시스템을 처음부터 잘 설계하지 않으면, 나중에 “이 메뉴는 이 사람만 봐야 하는데…”라는 요청이 올 때마다 전체 코드를 손봐야 합니다.

    핵심 설계 3 — 복잡한 데이터 구조 시각화

    B2B SaaS는 복잡한 데이터를 다룹니다. 인베스트리의 경우 투자조합 → 피투자조합 → 투자 내역 → 관련 서류로 이어지는 계층 구조가 있습니다.

    이 복잡성을 사용자가 쉽게 이해하고 작업할 수 있도록 UI/UX를 설계하는 것이 가장 큰 도전이었습니다.

    핵심 원칙:

    • 현재 어디 있는지 항상 알 수 있도록 (브레드크럼, 사이드바 강조)
    • 가장 자주 하는 작업을 가장 적은 클릭으로
    • 대용량 데이터를 페이지 속도 저하 없이 표시

    핵심 설계 4 — 기존 업무 방식 디지털화

    Athena는 윈도우 설치 프로그램으로 운영되던 것을 웹으로 전환한 프로젝트입니다. 엑셀 형식의 데이터를 웹에 연동하고, 입력값을 자동으로 문서화·시각화합니다.

    “기존에 엑셀로 하던 걸 그대로 웹으로”라는 요청은 생각보다 많습니다. 이때 주의할 점은 엑셀의 유연성을 과도하게 따라가려 하면 안 된다는 것입니다. 웹 서비스는 엑셀이 아닙니다. 엑셀보다 편리한 특정 작업 흐름을 설계하고, 데이터 시각화로 부가가치를 더하는 것이 맞습니다.

    핵심 설계 5 — 온보딩과 사용 지원

    B2B SaaS는 “쓰기 어렵다”는 평가를 받으면 바로 이탈입니다. 특히 기존 방식(엑셀, 설치 프로그램)을 쓰던 사람들에게 새로운 시스템은 거부감을 줍니다.

    설계 포인트:

    • 첫 로그인 후 단계별 가이드 (온보딩 투어)
    • 자주 하는 작업에 대한 툴팁
    • 도움말 문서 또는 인앱 가이드
    • 이전 방식 대비 어떻게 편리해졌는지 명확히 보여주기

    수익화 모델 설계

    SaaS의 과금 모델은 크게 세 가지입니다.

    사용자 수 기반: 월 활성 사용자(MAU) 또는 시트 수에 따라 과금. 가장 일반적.

    기능 티어 기반: Free/Pro/Enterprise로 나눠 기능 범위로 과금. Lotus Soft처럼 계정 유료화 버전에 따라 기능이 달라지는 구조.

    사용량 기반: API 호출 수, 처리량 등에 따라 과금. AI 기능이 있는 서비스에 적합.

    마치며

    B2B SaaS의 성공 요건은 단순합니다. “담당자가 매일 열게 되는 도구” 가 되어야 합니다. 매일 쓰게 되면 전환 비용이 높아지고, 전환 비용이 높아지면 장기 계약이 됩니다.

    그러려면 기술적 완성도보다 업무 플로우에 얼마나 잘 맞아떨어지는가가 더 중요합니다. 개발 전에 “이 서비스를 쓸 사람이 하루에 어떻게 일하는가”를 깊이 이해하는 시간이 반드시 필요합니다.