# AI와 함께 회사 ERP+CRM 운영 OS 만들기 — 고객·계약·차량·CS·메일을 한 화면으로 묶기까지

- 작성자: [Tess](https://community.clauders.ai/member/imported-member-XK9gC59H4q)
- 공간: [Claude Code MVP 공장](https://community.clauders.ai/cto)
- 게시: 2026-06-02
- 연재: [Claude Code MVP 공장 시즌 8](https://community.clauders.ai/series/cto-season-8) 3/3편
- 태그: #CTO
- 주소: https://community.clauders.ai/cto/post/ai%EC%99%80-%ED%95%A8%EA%BB%98-%ED%9A%8C%EC%82%AC-erp-crm-%EC%9A%B4%EC%98%81-os-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EA%B3%A0%EA%B0%9D-%EA%B3%84%EC%95%BD-%EC%B0%A8%EB%9F%89-cs-%EB%A9%94%EC%9D%BC%EC%9D%84-%ED%95%9C-%ED%99%94%EB%A9%B4%EC%9C%BC%EB%A1%9C-%EB%AC%B6%EA%B8%B0%EA%B9%8C%EC%A7%80-03bb9fa0-15cb-86e2-b8aa-1f34028bdcac

---

### 1. 먼저 ERP와 CRM의 경계를 다시 잡았다

처음에는 ERP와 CRM이 뒤섞여 있었다. 고객관리도 ERP 같고, 거래처도 CRM 같고, 미납 운영도 고객 문제이면서 회사 운영 문제처럼 보였다.

그래서 먼저 제품 정의를 다시 잡았다.

```
회사 내부 운영 OS를 만들고 싶다. 거기에 고객 생애주기를 통합해서 보는 CRM을 붙이고 싶다. 한 웹사이트 안에서 ERP와 CRM이 같이 있어야 한다.
```

결론은 명확했다.

> **ERP = 회사 내부 운영 OS**  
> **CRM = 고객 생애주기 운영 OS**

둘은 한 웹사이트 안에 있지만 역할은 다르다.

CRM은 고객 1명을 기준으로 첫 문의, 모델 탐색, 리스렌탈 가입, 결제, 미납, 정지/해제, CS, 만기/종료까지 이어지는 타임라인을 맡는다.

ERP는 거래처, 직원, 메일, 일정, 문서함, 회의록, 매출·정산·세무, 차량/단말 마스터 같은 회사 내부 운영을 맡는다.

이 경계를 먼저 세운 덕분에 이후 구현에서 “이 기능은 어느 메뉴에 있어야 하는가?”라는 혼란이 줄었다.

### 2. 회사 도메인에 맞는 상태모델을 만들었다

이 회사에는 크게 두 종류의 케이스가 있다.

- **신차 구매**: 보조금/구매/출고 중심의 흐름. 출고 후에는 운영영역이 크지 않음
- **리스렌탈**: 차량+보험이 묶인 장기 이용 흐름. 계약, 결제, 미납, 정지, 회수, 채권까지 이어짐

처음에는 이 둘을 같은 상태값으로 다루려는 유혹이 있었다. 하지만 그러면 운영이 망가진다. 신차 구매 흐름과 리스 렌탈 맥락이 서로 달라서 각 케이스 별 전용 상태머신이 필요했다.

```
신차 구매와 리스렌탈은 상태 enum을 공유하면 안 된다. 케이스 타입별로 완전히 분리하고, 리스렌탈은 계약 phase, 미납 단계, 실제 서비스 상태를 나눠서 봐야 한다.
```

그래서 상태모델을 분리했다.

- `case_type`: 신차 구매 / 리스렌탈
- 신차 구매: 출고까지의 단일 흐름
- 리스렌탈: 계약 phase, 미납 단계, 실제 서비스 상태, 제어원 분리
- 고위험 action: 차량 정지, 해제, 발송, 환불, 세금계산서 등은 승인 게이트 필수

특히 차량 정지/해제는 고객 생계와 직결될 수 있다. 그래서 메모나 추측이 아니라 실제 상태조회와 승인 흐름을 전제로 설계했다.

이 단계에서 배운 건, AI에게 화면을 만들게 하기 전에 **상태모델을 먼저 잠가야 한다**는 점이었다. 상태가 흔들리면 화면도, 자동화도, AI 판단도 모두 흔들린다.

### 3. 고객 360을 먼저 만들었다 — CRM의 중심 화면

CRM의 핵심은 “고객 1명 기준으로 다 보는 것”이다. 단순 고객 목록이 아니라, 고객의 생애주기와 조치 이력을 한 화면에서 보는 것이 목표였다.

```
고객 기준으로 생애주기 주요 이벤트를 묶어서 보고 싶다. 단순 고객 DB가 아니라, 고객 전방위 주요 이벤트를 통합해주는 느낌이어야 한다.
```

그래서 고객360 화면을 6개 탭으로 설계했다.

1. 개요
2. 생애주기 히스토리
3. CS 상담이력
4. 계약·리스렌탈
5. 결제·마일리지
6. 메모·조치

여기서 중요한 결정은 “모든 것을 타임라인 하나에 다 넣지 않는 것”이었다.

- 생애주기 탭에는 중요한 이벤트만 큐레이션
- CS 상담이력 탭에는 전체 대화 서랍식 보관
- 계약 탭에는 신차 구매와 리스렌탈을 타입 라벨로 구분
- 결제·마일리지 탭에는 회차, 예약금, 환불, 마일리지 변동을 표시
- 메모·조치 탭에는 운영 메모와 승인 요청 흐름을 둠

이렇게 나누니 고객을 “데이터 행”이 아니라 “운영 대상”으로 볼 수 있게 됐다.

**MVP로 한 것:** 6탭 구조, 고객 개요, 주요 생애주기, 상담 이력 구조, 계약/결제/메모 탭의 화면 뼈대와 mock/seed 기반 데이터 표시.

**아직 남은 것:** 실제 운영 데이터와의 완전 연동, 실시간 CS 웹훅 연결, 문서/증빙 자동 연결, 고위험 조치 실행/승인 워크플로우.

### 4. CS 티켓과 리스렌탈 운영을 붙였다

고객360만 있으면 조회는 되지만, 실제 운영 큐가 없다. 그래서 다음으로 CS 티켓과 리스렌탈 운영 화면을 만들었다.

CS는 채팅, 전화, 문자, 메일 등 여러 채널에서 들어오지만 대부분 채널톡 서비스를 통해 인입된다. 목표는 모든 상담을 하나의 고객 이력으로 연결하고, 매니저가 처리해야 할 것을 놓치지 않는 것이다.

```
CS 상담은 고객360에도 보여야 하고, 별도 티켓 인박스에서도 처리할 수 있어야 한다. 중요한 상담은 생애주기에 남기고, 전체 대화는 상담이력에 남겨야 한다.
```

구조는 이렇게 잡았다.

- `thread`: 고객·채널별 전체 대화
- `ticket`: 매니저 처리가 필요한 인입
- `important`: AI가 중요 후보로 분류하고 매니저가 확인
- `logged`: 중요한 처리건만 생애주기에 기록

리스렌탈 미납 운영은 이미 별도 자동화 대시보드가 강하게 작동 중이었다. 그래서 무리하게 재구현하지 않았다.

```
이미 돌아가는 미납 운영 OS는 유지하고, CRM은 읽기/통합/링크부터 시작하자. 자동화 worker는 검증 후 마지막에 흡수하자.
```

이 결정도 중요했다. AI로 새 시스템을 만든다고 해서 기존에 잘 돌아가는 자동화를 바로 갈아엎으면 위험하다. 특히 미납, 정지, 자동해제처럼 운영 리스크가 큰 영역은 **점진 흡수**가 맞았다.

**MVP로 한 것:** CS 티켓 인박스 구조, 고객별 상담 이력 구조, 중요 이벤트 개념, 리스렌탈 운영 요약, 만기/미납 연결 화면.

**아직 남은 것:** 실시간 CS 웹훅, 매니저 답변 자동 완료, AI 중요도 분류의 실데이터 적용, 미납 자동화의 클라우드/이벤트 기반 흡수.

### 5. ERP 첫 슬라이스는 거래처 관리였다

CRM에서 제조사, 보험사, PG, 메시징 업체 같은 거래처 정보가 계속 필요했다. 특히 신차 구매 수수료는 제조사별 rate가 단일 출처여야 했다.

그래서 ERP 첫 실전 슬라이스는 거래처 관리였다.

```
거래처 관리를 먼저 만들자. 제조사별 처리수수료와 영업수수료를 CRM에서 하드코딩하지 말고, ERP 거래처를 단일 출처로 참조하게 하자.
```

거래처 관리에서는 다음을 만들었다.

- 제조사, 보험사, 딜러, 부품정비, PG, 메시징 등 타입 구분
- 거래처 목록과 상세 화면
- 담당자/연락처/상태/메모
- 제조사별 처리수수료, 영업수수료 rate
- CRM 케이스가 거래처 `vendor_id`를 참조하도록 정합성 정리

이 작업의 핵심은 “화면 하나 추가”가 아니라 **CRM 수수료의 단일 출처를 ERP 거래처로 옮긴 것**이었다.

**MVP로 한 것:** 거래처 목록/상세, 타입 필터, 제조사 수수료 rate, CRM 참조 카운트와 단일출처 구조.

**아직 남은 것:** 거래처 정산 자동계산, 실제 외부 provider 연동, 계약/청구/세금계산서와의 완전 연결.

### 6. mock에서 실제 DB 기반으로 넘어갔다

처음에는 빠른 설계를 위해 mock 데이터로 화면과 도메인 구조를 만들었다. 하지만 실제 시스템이 되려면 인증, DB, 권한, 데이터 저장이 필요했다.

```
이제 인증과 실제 DB로 전환하자. 고객, 거래처, 티켓 데이터를 mock에서 실DB로 옮기고, 나중에 기존 운영 데이터와 연결할 수 있게 adapter 경계를 유지하자.
```

여기서 중요한 원칙은 “오늘은 mock, 내일은 기존 시스템 연동”이 가능하도록 repository/adapter 경계를 만드는 것이었다.

즉 UI가 직접 데이터 소스를 알지 않게 했다.

- 지금은 seed/mock 또는 DB에서 읽음
- 나중에는 기존 관리자페이지 API나 DB 어댑터로 교체
- UI와 도메인 로직은 최대한 유지

이후 로그인, 라우트 보호, 관리자 계정, 마이그레이션, 고객/거래처/티켓 실DB 전환이 진행됐다.

**MVP로 한 것:** 인증, DB 마이그레이션, 일부 도메인 실DB 전환, adapter 경계.

**아직 남은 것:** 기존 운영 시스템과의 읽기 연동, 실데이터 마이그레이션 정책, 감사로그/권한 세분화.

### 7. 메일 플랫폼을 ERP 안으로 넣었다

운영에서 메일은 빠질 수 없다. 외부 거래처, 제휴사, 내부 직원, 고객 관련 메일이 모두 업무 맥락이다. ERP 안에서 회사 메일을 읽고 보내고, CRM과 연결할 수 있어야 했다.

```
직원이 ERP에서 회사 메일을 실제로 읽고 쓸 수 있게 하자. 받은편지함, 발송, 첨부, 자동분류, 백그라운드 동기화까지 가자.
```

메일 플랫폼은 단계적으로 구현했다.

1. 직원별 메일 계정 연동
2. 앱 비밀번호를 암호화해서 저장하는 시크릿 금고
3. IMAP으로 받은편지함 읽기
4. SMTP로 메일 발송과 첨부 처리
5. 보낸이 기준 거래처/직원/외부 자동분류
6. 메일 메시지 영속 저장
7. 주기적 동기화 worker와 cron 준비

여기서도 원칙은 같았다.

- 평문 비밀번호 저장 금지
- 잘못된 인증정보는 연동 시점에 차단
- 페이지를 열 때만 메일을 가져오는 구조에서, 백그라운드 동기화 구조로 확장
- 메일을 단순 받은편지함이 아니라 CRM/ERP 맥락에 붙일 수 있게 분류

이 단계에서 “ERP가 실제 업무 도구가 되는 느낌”이 강해졌다. 단순 화면이 아니라 직원이 로그인해서 메일을 읽고, 쓰고, 분류할 수 있는 기능이 생겼기 때문이다.

**MVP로 한 것:** 메일 계정 연동, 암호화 저장, 받은편지함, 메일 발송, 첨부, 분류, 영속 저장, 동기화 worker 준비.

**아직 남은 것:** 메일과 고객/거래처 타임라인 자동 연결, 운영 알림, 외부 cron/클라우드 worker 안정화, 팀 단위 권한 정책.

### 8. 직원·설정으로 팀 사용의 전제를 만들었다

클라우드 배포까지 가면 다음 문제는 “누가 로그인할 수 있느냐”다. 관리자 1명만 들어가는 시스템은 팀 도구가 아니다.

```
팀이 쓰려면 직원 추가와 권한 관리가 필요하다. 관리자가 직원을 초대하고, 직원이 비밀번호를 설정해서 로그인하는 흐름을 만들자.
```

직원·설정에서는 다음을 구현했다.

- 직원 목록
- 이름, 이메일, 부서, 직책, 역할, 상태 관리
- 관리자 전용 접근
- 매직링크 초대
- 초대받은 직원의 비밀번호 설정
- 비활성 직원 로그인 차단
- 초대 재발송과 삭제

이 기능은 화려하지 않지만 운영 시스템에서는 필수다. 팀이 실제로 쓰려면 권한과 계정 흐름이 먼저 안정적이어야 한다.

**MVP로 한 것:** 직원 목록/검색, 초대, 역할/상태 변경, 비활성 차단, 초대 재발송/삭제.

**아직 남은 것:** 메뉴별 세밀 권한, 감사로그, 부서/직무별 기본 권한 템플릿, 설정 메뉴 확장.

### 9. 명함·문서 OCR은 다음 고도화 과제로 남겼다

ERP 내부 업무에는 명함, 계약서, 사업자등록증, 차량등록증 같은 문서 입력이 많다. 이 부분은 AI 자동입력의 좋은 후보였다.

일단 명함 OCR을 먼저 실험했다.

```
명함을 찍으면 정보가 자동으로 들어오고, 거래처나 연락처로 이어지면 좋겠다.
```

이미지 업로드 기반으로 이름, 회사, 직책, 전화번호, 이메일을 추출하고, 사용자가 확인한 뒤 거래처/연락처로 저장하는 흐름을 만들었다. 카메라 스캐너도 붙여 보았다.

다만 이 기능은 아직 다듬을 부분이 남아 있다. 특히 모바일 카메라에서 “보이는 감지 UI”와 “AI가 실제로 읽는 이미지”를 어떻게 분리할지, 명함뿐 아니라 계약서·사업자등록증·차량등록증까지 어떻게 확장할지 더 설계가 필요하다.

그래서 OCR은 이번 사례의 핵심 교훈이라기보다, **다음 단계 자동입력 고도화 과제**에 가깝다.

**MVP로 한 것:** 명함 이미지 업로드, 필드 추출, 확인/수정, 거래처/연락처 저장 흐름, 카메라 스캐너 실험.

**아직 남은 것:** 카메라 UX 안정화, 문서별 OCR 템플릿, 계약서/사업자등록증/차량등록증 자동입력, 검수 워크플로우, 고객360 문서 탭 연결.

### 10. 디자인 시스템과 리디자인까지 이어졌다

기능이 늘어나자 화면마다 스타일이 달라지고, 기본 템플릿 같은 느낌이 생겼다. ERP+CRM은 매일 보는 운영 콘솔이기 때문에 디자인 품질도 중요했다.

```
렌더 이미지로 여러 팔레트를 비교해서 보여주고, 선택한 팔레트로 디자인시스템을 확정한 뒤 풀 리디자인을 진행하자.
```

팔레트 후보를 라이트/다크로 비교했고, 최종적으로 전문적인 운영 콘솔에 맞는 방향을 잡았다. 이후 디자인시스템 문서와 JSON 상태파일을 만들고, 토큰·공통 UI 컴포넌트부터 정리하기 시작했다.

여기서도 한 번에 전체 화면을 갈아엎기보다:

1. 디자인 토큰
2. 테마 토글
3. 공통 UI primitive
4. 네비게이션/셸
5. 대시보드/테이블/폼

순서로 쌓아가는 방식이었다.

**MVP로 한 것:** 디자인 방향 선정, 디자인시스템 단일 문서, 토큰, 라이트/다크 기반, 공통 UI primitive 착수.

**아직 남은 것:** 전체 화면 일괄 적용, 모바일 QA, 데이터 밀도 조정, 실제 사용자 피드백 기반 개선.

### Before vs After

항목

Before

After

운영 정보

관리자페이지, 미납대시보드, 메일, 채팅, 문서, 사람 기억에 분산

ERP+CRM 안에서 고객·계약·CS·거래처·메일·직원 맥락 연결 시작

고객관리

고객 목록/주문 중심

고객360: 생애주기, CS, 계약, 결제, 메모, 조치 탭 구조

CS

채널별 응대 중심

티켓/상담이력/중요 이벤트/생애주기 기록 구조

리스렌탈 운영

별도 미납 운영 OS 중심

기존 자동화는 유지하고 CRM에서 요약·링크·만기 큐로 점진 흡수

ERP 내부업무

거래처, 메일, 직원, 문서 등 분리

거래처 관리, 메일 플랫폼, 직원관리가 한 사이트로 수렴

AI 협업

긴 대화가 끊기면 맥락 손실

`CONTEXT.md`, 설계문서, `.goalloop/*.json`으로 목표·상태 보존

품질관리

구현자 판단에 의존

Claude Code 구현 + Codex 리뷰 + 테스트/빌드 검증

### 실제로 만들어진 주요 기능

- ERP 홈 대시보드와 좌측 네비게이션
- CRM 대시보드
- 고객360 6탭 구조
- CS 티켓 인박스와 고객별 상담이력 구조
- 리스렌탈 운영 요약과 만기/미납 연결 구조
- 거래처 관리와 제조사 수수료 단일출처화
- 인증과 DB 마이그레이션
- 고객/거래처/티켓 데이터의 실DB 전환
- 직원 관리와 초대/비밀번호 설정
- 회사 메일 읽기/쓰기/첨부/분류/동기화 worker
- 명함 OCR MVP와 카메라 실험
- 디자인시스템과 라이트/다크 토큰 기반 리디자인 착수

### 효과적이었던 것

1. **도메인 경계를 먼저 잡기**  
   ERP와 CRM을 섞지 않고, 회사 내부 운영과 고객 생애주기 운영으로 나눈 것이 이후 모든 화면과 데이터 모델의 기준이 됐다.
2. **상태모델을 코드보다 먼저 잠그기**  
   신차 구매와 리스렌탈 상태를 분리하지 않았다면 미납, 정지, 회수 같은 위험한 기능이 잘못 적용될 수 있었다.
3. **얇은 MVP 슬라이스로 쌓기**  
   “ERP 전체 만들어줘”가 아니라 고객360, CS티켓, 거래처, 메일, 직원처럼 기능 단위로 쪼개니 실제로 진도가 났다.
4. **구현자와 리뷰어 분리하기**  
   Claude Code가 빠르게 만들고, Codex가 별도 시선으로 검토하면서 놓친 경계나 버그를 잡을 수 있었다.
5. **컨텍스트를 파일로 남기기**  
   긴 AI 작업은 언젠가 컨텍스트가 끊긴다. `CONTEXT.md`, 설계문서, JSON 상태파일이 없었다면 이어가기 어려웠다.
6. **기존 자동화를 존중하기**  
   이미 잘 돌아가는 미납 대시보드/자동해제 같은 기능은 바로 갈아엎지 않고, CRM에서 읽기·링크로 점진 흡수하는 전략이 안전했다.

### 이렇게 하면 안 돼요

1. **AI에게 “전체 ERP 만들어줘”만 던지면 안 된다**  
   범위가 너무 크면 모델이 그럴듯한 화면만 만들고 도메인 충돌을 놓친다.
2. **고객 DB와 CRM을 같은 것으로 보면 안 된다**  
   이 프로젝트에서 CRM은 고객 이름 목록이 아니라, 상담·계약·결제·미납·차량·문서가 이어지는 생애주기 운영 화면이다.
3. **상태값을 하나의 enum에 몰아넣으면 안 된다**  
   신차 구매와 리스렌탈처럼 본질이 다른 흐름은 상태모델부터 분리해야 한다.
4. **기존 시스템을 한 번에 대체하려 하면 안 된다**  
   운영 리스크가 큰 영역은 새 시스템이 먼저 읽고 연결한 뒤, 충분히 검증되면 흡수하는 게 맞다.
5. **AI 에이전트에게 기억을 맡기면 안 된다**  
   대화 컨텍스트는 언젠가 끊기므로, 목표·결정·상태·다음 작업은 반드시 파일로 남겨야 한다.

### 프롬프트 1: 사내 ERP+CRM을 시작할 때

> 우리 회사 운영을 ERP와 CRM으로 나누어 설계하고 싶다.  
> ERP는 회사 내부 운영, CRM은 고객 생애주기 운영으로 정의해줘.  
> 각 기능을 어느 도메인에 둘지 표로 나누고, 공유 키와 절대 섞이면 안 되는 경계를 정리해줘.

### 프롬프트 2: 상태모델부터 잠그기

> 이 비즈니스의 주요 케이스 유형을 나누고, 서로 다른 케이스가 같은 상태 enum을 공유하면 안 되는 지점을 찾아줘.  
> 상태값, 전이 조건, 고위험 action, 사람 승인 게이트를 먼저 설계해줘.  
> 화면 구현은 그다음으로 미뤄줘.

### 프롬프트 3: AI 코딩을 슬라이스로 진행하기

> 전체 시스템을 한 번에 만들지 말고, 가장 얇은 수직 슬라이스로 나눠줘.  
> 각 슬라이스마다 목표, 비목표, 수용 기준, 테스트/빌드 검증, Codex 리뷰 기준을 정리해줘.  
> 완료 상태는 JSON 파일에 기록해서 컨텍스트가 끊겨도 이어갈 수 있게 해줘.

### 프롬프트 4: 구현자와 리뷰어 분리하기

> Claude Code는 구현 담당, Codex는 독립 리뷰어로 둔다.  
> 각 변경 후 Codex에게 의도 충족 여부, 새 버그, 도메인 경계 위반, 보안/운영 리스크를 검토하게 해줘.  
> blocker가 있으면 구현을 되돌리거나 수정하고, NO_BLOCKERS일 때만 다음 단계로 넘어가.

### 프롬프트 5: 기존 시스템을 점진 흡수하기

> 이미 운영 중인 시스템을 새 ERP+CRM으로 바로 대체하지 말고, 읽기 연동 → 링크/요약 → 일부 UI 통합 → 자동화 이관 순서로 점진 흡수하는 계획을 세워줘.  
> 특히 고위험 자동화는 마지막에 옮기고, 그 전에는 기존 시스템을 진실 소스로 유지해줘.

### 프롬프트 6: 에이전트 팀을 구성할 때

> 이번 작업을 오케스트레이터, 설계/질문 에이전트, 구현 에이전트, 독립 리뷰어, 테스트/빌드 검증, 상태 기록자로 나눠줘.  
> 각 역할의 책임과 산출물을 정하고, 구현 에이전트가 만든 결과를 리뷰어가 독립적으로 검토하게 해줘.  
> 모든 결정과 완료 상태는 파일로 남겨 다음 세션에서도 이어갈 수 있게 해줘.
