Portfolio
work-SaaS — 멀티테넌트 현장운영 SaaS
2026 ~ 현재 (진행 중)
공통 코어 위에 업종별(화물·냉난방) 모듈을 얹고 구독으로 기능을 켜는 멀티테넌트 SaaS. 백엔드·프론트·DB·배포까지 1인 풀스택.
문제 · 맥락
실제 가족 사업(냉난방 설치·AS, 화물 운송)의 라이브 요구사항을 입력으로, '한 코어 + 다업종 플러그인' SaaS를 만드는 과제. 핵심 난제는 (1) 테넌트 간 데이터를 안전하게 격리하고, (2) 인프라(스토리지·결제·알림)를 나중에 갈아끼울 수 있게 하며, (3) 같은 기능도 테넌트마다 다르게 동작시키는 것.
핵심 설계 결정
Day-1 헥사고날 포트-어댑터 (ADR 0006)
프로젝트 첫날부터 6개 포트(Storage / Auth / Notification / Payment / Search / EventBus)를 추상화.
application.yml의 app.<port>.type 한 줄로 어댑터 빈 교체(NAS→R2 등), 미구현은 NoOp 어댑터로 부팅 차단 없이 흡수.
실제 9개 포트 인터페이스 + 11개 어댑터(JWT·Google OAuth·NAS·InProcess EventBus·Email + 각 NoOp) 구현.
PostgreSQL RLS 기반 멀티테넌시 이중 가드 (ADR 0004 / 0013)
단일 DB·단일 스키마, 전 테이블 tenant_id.
애플리케이션 TenantContext 주입 + PostgreSQL Row Level Security(FORCE ROW LEVEL SECURITY + current_setting)로 행 격리를 DB 레벨에서 강제.
마이그레이션마다 RLS 정책 + 권한 백필 + 시드를 함께 넣는 표준 패턴으로 테넌트 데이터 유출 가능성을 구조적으로 차단.
Feature / Variant / Platform-admin 3계층 테넌시 (ADR 0009 / 0011 / 0012)
feature·tenant_feature 카탈로그 + @RequireFeature AOP 가드로 구독 기반 기능 토글.
동일 기능의 테넌트별 분기는 코드 Strategy 빈(tenant_variant)으로.
플랫폼 운영자(work admin, aud:platform)가 cross-tenant로 기능·구독을 연결.
BE↔FE 계약 자동 결속
springdoc /v3/api-docs → openapi-typescript로 공유 타입 패키지 생성.
FE는 도메인별 BE 호출을 /api/be/[...path] 제네릭 BFF 프록시 + lib/<domain>/api.ts로 경유 → 타입 드리프트 제거.
성과 · 지표
약 84 PR · 22 ADR · 29 Flyway 마이그레이션 · 149 통합테스트 · BE 약 10.4K LOC (저장소 기준 집계).
큰 결정마다 Context/Decision/Consequences/Alternatives를 ADR로 기록해 설계 추적성 확보.
NAS 자가 배포 파이프라인 운영.
한 줄 요약
Kotlin/Spring + Next.js로 멀티테넌트 SaaS를 1인 풀스택 설계. Day-1 헥사고날 6포트와 PostgreSQL RLS 이중 가드로 인프라 교체성과 테넌트 격리를 구조화하고, Feature/Variant/Platform-admin 3계층으로 '한 코어 + 다업종' 구독 모델을 구현.