🔗 CONNECTON ERP

B2B 영업대행 사내 전용 ERP 시스템 전체 설계 문서.
임원실·회계·A1·A2·O2 5개 부서 통합 관리.

5부서
32+테이블
9사용자 역할
10구현 단계
Supabase단독 백엔드
📋

프로젝트 개요

🚫
외부 고객사 로그인 완전 불가 — Supabase Auth Sign Up 비활성화 + 초대 전용 온보딩. RLS를 통해 DB 레벨에서도 차단.

🏢 조직 구성

임원실경영진·전사 대시보드·승인
회계정리입금·지출·커미션 정산
A1팀신규 문의·상담·계약
A2팀계약 고객사 영업운영
O2팀세무사 전용 영업관리

✅ 필수 확정 조건

  • ✅ 외부 고객사 로그인 불가
  • ✅ A1 커미션 = 실제 입금액 기준
  • ✅ A2·O2 14일·월간 자동 보고서
  • ✅ 팀별·프로젝트별·1:1 채팅
  • ✅ 채팅 파일 공유 + 프로젝트 자료실
  • ✅ PC 중심 반응형 + 모바일 지원

💡 A1 커미션 핵심 로직

입금(payments) 상태가 CONFIRMED/COMPLETED로 변경되는 순간
DB 트리거 auto_create_commission()가 자동 실행되어
commission_entries에 금액을 계산·삽입합니다.

기준: amount_received × rule_pct (상한 적용)

⚙️

기술 스택 & 배포 환경

레이어기술역할비고
프론트엔드React 18 + TypeScriptSPA UIVite 번들
라우팅React Router v6클라이언트 라우팅BrowserRouter
상태관리@tanstack/react-query서버 상태 캐싱Supabase 연동
스타일Tailwind CSS유틸리티 CSS@tailwindcss/forms
폼react-hook-form + zod유효성 검사
차트Recharts대시보드 시각화
아이콘Lucide ReactUI 아이콘
인증Supabase Auth이메일+비밀번호Sign Up 비활성화
DBSupabase PostgreSQL관계형 DB + RLS별도 프로젝트
실시간Supabase Realtime채팅 실시간 수신Websocket 기반
파일Supabase Storage파일 업로드/다운Private 버킷
서버리스Supabase Edge Functions초대·보고서·감사Deno 런타임
스케줄pg_cron자동 보고서매월 1·15일
배포Cloudflare PagesSPA 호스팅_redirects 필요
⚠️
SPA 라우팅 필수: public/_redirects 파일에 /* /index.html 200 추가 → Cloudflare Pages 새로고침 404 방지
🔄

부서별 업무 흐름도

🟢 A1팀 — 문의→계약→커미션

1
문의 등록

출처 기록, 담당자 배정 (status: NEW)

2
상담 진행

consultation_logs 작성 (status: IN_PROGRESS)

3
계약 체결

계약서 작성·서명, 문서 첨부 (status: SIGNED)

4
리드 인계

A2팀 또는 O2팀으로 인계 (lead_deliveries)

5
입금 확인 → 커미션 자동 발생

회계팀 입금 CONFIRMED → DB 트리거 commission_entries 생성

🟡 A2팀 — 고객사 운영

1
고객사 등록

A1 인계 후 고객사 생성·담당자 배정

2
프로젝트 생성

KPI 설정, 멤버 구성, 채팅방·자료실 자동 생성

3
영업 활동 기록

일지 작성, 파일 공유 (자료실)

4
자동 보고서

14일(매 1·15일), 월간(매 1일) 자동 생성

🔴 O2팀 — 세무사 영업

1
세무파트너 등록

법인명·세무사 정보, 담당 O2직원 배정

2
영업 활동

방문·미팅·세미나 기록

3
리드 배분

세무파트너에 고객 리드 배분 (O2_TO_PARTNER)

4
자동 보고서

A2와 동일 주기 (14일·월간)

🔵 회계팀 — 입금·정산

1
입금 등록

계약 연결, 입금액 기록

2
입금 확인

status CONFIRMED → A1 커미션 자동 생성

3
커미션 검토·지급

VERIFIED → PAID, 지급일 기록

4
월간 회계 리포트

입금·지출·커미션 합계

🗄️

ERD — 주요 테이블

32+ 테이블
🏛️ departments
PK idUUID
codeENUM UNIQUE
nameTEXT
FK manager_id→profiles
👤 profiles
PK id→auth.users
emailTEXT UNIQUE
full_nameTEXT
FK department_id→depts
is_activeBOOLEAN
🔑 role_assignments
PK idUUID
FK profile_id→profiles
roleuser_role ENUM
is_activeBOOLEAN
UNIQUE(profile_id,role)
🏢 clients
PK idUUID
company_nameTEXT
business_noUNIQUE
assigned_deptdept_code ENUM
FK primary_manager→profiles
📋 inquiries
PK idUUID
inquiry_noINQ-YYYYMM-XXXX
company_nameTEXT
statusinquiry_status
FK assigned_to→profiles
FK client_id→clients
📄 contracts
PK idUUID
contract_noCNT-YYYYMM-XXXX
total_amountNUMERIC(15,2)
statuscontract_status
FK client_id→clients
FK a1_staff_id→profiles
💵 payments
PK idUUID
payment_noPAY-YYYYMM-XXXX
amount_received커미션기준
statuspayment_status
FK contract_id→contracts
💰 commission_entries
PK idUUID
FK payment_id→payments
FK staff_id→profiles
commission_amtNUMERIC(15,2)
statuscommission_status
📁 projects
PK idUUID
project_noPRJ-YYYYMM-XXXX
FK client_id→clients
departmentA2 or O2
FK manager_id→profiles
💬 chat_messages
PK idUUID
FK room_id→chat_rooms
FK sender_id→profiles
mentionsUUID[] GIN
FK file_id→files
📂 files
PK idUUID
storage_pathUNIQUE
contextfile_context ENUM
is_deleted소프트삭제
FK project_id→projects
📜 audit_logs
PK idUUID
FK actor_id→profiles
actor_emailTEXT(보존)
actionaudit_action
old_data/new_dataJSONB
월별 파티셔닝
➕

추가 정규화 테이블 — 설계 근거

테이블설계 근거핵심 컬럼
client_contacts고객사 담당자 개인정보(이름·전화·이메일)를 clients 테이블에서 분리 → 개인정보 접근 최소화 원칙contact_name, contact_phone, contact_email (PII)
tax_partner_contacts동일 이유: 세무파트너 담당자 PII 분리contact_name, contact_phone, contact_email (PII)
user_invitationsSupabase 초대 상태 추적, 역할 사전 배정을 위한 중간 테이블. 초대 이력 감사 가능email, intended_role, status, expires_at
contract_history계약 상태 변경 이력 추적 (법적 분쟁·감사 대비). contracts UPDATE 트리거로 자동 기록old_status, new_status, old_data, new_data
kpi_historyKPI 수치 변경 추적 → 보고서 데이터 소급 검증 가능recorded_value, recorded_at, recorded_by
notification_settings사용자별 알림 수신 설정 정규화 → 알림 스팸 방지chat_mention, task_assigned 등 BOOLEAN
tags / entity_tags문의·고객사·프로젝트·태스크에 유연한 태그 부착 → 다차원 검색·분류 지원entity_type, entity_id (범용 참조)
🔗

주요 인덱스 & 제약조건

🔑 UNIQUE 제약

inquiries.inquiry_noINQ-YYYYMM-XXXX
contracts.contract_noCNT-YYYYMM-XXXX
payments.payment_noPAY-YYYYMM-XXXX
projects.project_noPRJ-YYYYMM-XXXX
daily_reports(staff_id,date)하루 1회 제한
project_members(proj,profile)중복 참여 방지
role_assignments(profile,role)역할 중복 방지
files.storage_pathStorage 경로 유일
clients.business_no사업자번호 유일

⚡ 핵심 인덱스

inquiries(status)상태 필터
payments(period)월별 입금 조회
commission_entries(period_year,month)커미션 정산
chat_messages(room_id, created_at DESC)채팅 페이징
notifications(recipient_id) WHERE unread미읽음 카운트
clients(company_name) GIN trgm고객사 검색
inquiries(company_name) GIN trgm문의 검색
chat_messages(mentions) GIN멘션 검색

🚧 CHECK 제약

payments.amount_due ≥ 0음수 방지
commission_entries.commission_amt ≥ 0음수 방지
expenses.amount > 00원 방지
contract datesend ≥ start
commission_rulesrate OR fixed 필수
chat_rooms DIRECT1:1은 project 불가
lead_deliveriesfrom ≠ to
period_month1~12 범위
🔒

권한 매트릭스

기능/테이블 admin임원회계A1팀장A1직원A2팀장A2직원O2팀장O2직원
부서·사용자 관리 CRUDR———————
문의 (inquiries) CRUDRRCRUDCRUR—R—
계약 (contracts) CRUDRRCRUDCRURRRR
입금 (payments) CRUDRCRUDR*—————
커미션 (commission_entries) CRUDRRUR(본인)R(본인)——R(본인)R(본인)
고객사 A2 (clients) CRUDRRRRCRUDR——
고객사 O2 (clients) CRUDRRRR——CRUDR
프로젝트 (A2) CRUDRR——CRUD멤버——
세무파트너 (O2) CRUDR—————CRUDR
자동 보고서 CRUDR—RRRRRR
채팅 (chat_messages) CRUDCRUDCRUDCRUDCRUDCRUDCRUDCRUDCRUD
파일 (프로젝트 자료실) CRUDRR——멤버멤버멤버멤버
감사 로그 RR———————

* R(본인): 본인 담당 데이터만 조회, 멤버: 프로젝트 멤버만 접근

🛡️

RLS 정책 핵심

ℹ️
모든 32+ 테이블에 RLS 활성화. 헬퍼 함수(STABLE + SECURITY DEFINER)로 성능 최적화. auth.uid() 기반 현재 사용자 식별.

🔧 헬퍼 함수

-- 역할 확인 (캐시 가능)
has_role(user_role) → BOOLEAN
has_any_role(user_role[]) → BOOLEAN
is_executive_or_admin() → BOOLEAN
is_a1() / is_a2() / is_o2() → BOOLEAN
is_manager_or_above() → BOOLEAN

-- 접근 권한 확인
is_project_member(project_id) → BOOLEAN
is_chat_member(room_id) → BOOLEAN

💡 정책 패턴 예시

-- 채팅 메시지: 룸 멤버만
CREATE POLICY "chat_msg_select"
  ON chat_messages FOR SELECT
  USING (
    is_executive_or_admin()
    OR is_chat_member(room_id)
  );

-- 파일: 프로젝트 멤버만
CREATE POLICY "files_select"
  ON files FOR SELECT
  USING (
    is_project_member(project_id)
    OR is_executive_or_admin()
  );
🔑

인증 & 사용자 초대 절차

🚫
Supabase Auth Sign Up 완전 비활성화 — 외부 고객사가 스스로 계정을 만들 수 없음. 관리자(admin)의 초대를 통해서만 계정 생성 가능.
1
관리자: /admin/users → "직원 초대"

이메일, 역할, 부서 입력

2
user_invitations 레코드 생성 (PENDING, 48시간 유효)

invite-user Edge Function 실행 → Supabase Auth 초대 이메일 발송

3
직원: 이메일 → 비밀번호 설정 링크 클릭

/auth/reset-password/confirm 페이지

4
Auth 트리거 자동 실행

handle_new_user() → profiles 생성 + role_assignments 배정 + notification_settings 초기화

5
로그인 가능 상태 + audit_logs 기록
📜

감사 로그 설계

이벤트audit_action기록 주체
로그인/로그아웃LOGIN / LOGOUTEdge Function
사용자 초대INVITE_SENTinvite-user Function
역할 변경ROLE_CHANGEDDB 트리거
파일 업로드/다운로드/삭제FILE_UPLOAD/DOWNLOAD/DELETEDB 트리거 + Edge Function
보고서 생성/열람REPORT_GENERATED/VIEWEDEdge Function
커미션 계산/지급COMMISSION_CALCULATED/PAIDDB 트리거
계약·입금 상태 변경UPDATEDB 트리거
✅
audit_logs는 월별 파티셔닝 적용. 매월 25일 pg_cron이 다음달 파티션 자동 생성. 삭제 불가 정책(DELETE 정책 없음).
📁

파일 접근 & Storage 설계

🗂️ Storage 버킷 구조

erp-files (Private)
├── contracts/{contract_id}/
├── projects/{project_id}/
├── chat/{room_id}/
├── expenses/{expense_id}/
├── reports/{report_id}/
└── general/{uploader_id}/

🔐 파일 다운로드 흐름

1
RLS로 files 테이블 조회
2
Signed URL 발급 (1시간 유효)
3
download_count++ + audit_logs 기록

📋 파일 정책

  • 최대 파일 크기: 50MB
  • 허용 형식: PDF, Word, Excel, PPT, 이미지, CSV
  • 소프트 삭제 (30일 후 Storage 실제 삭제)
  • Storage RLS: 버킷 레벨 정책 적용
  • 개인정보 포함 파일: 별도 접근 제어
🚀

단계별 구현 계획 (~29주)

Phase 0 — Supabase 설정 & DB 마이그레이션 (1주)
새 프로젝트 생성, SQL 마이그레이션 4단계 실행, Storage 버킷, pg_cron, Auth 설정
Phase 1 — 인증 & 공통 UI 프레임워크 (3주)
React+Vite 초기화, AuthProvider, AuthGuard/RoleGuard, 공통 레이아웃, 컴포넌트 라이브러리
Phase 2 — A1팀 기능 (4주)
문의·상담·계약 관리, 계약문서 첨부, 리드 인계, 커미션 현황
Phase 3 — A2팀 기능 (4주)
고객사·프로젝트·KPI·영업일지·자료실·보고서 뷰어
Phase 4 — O2팀 기능 (3주)
세무파트너·리드배분·O2 영업활동·보고서
Phase 5 — 회계팀 기능 (3주)
입금관리·커미션 자동생성 검증·지출관리·정산
Phase 6 — 사내 채팅 + 자료실 (3주)
Supabase Realtime 구독, 팀/프로젝트/1:1 채팅, 파일 첨부, 멘션 알림
Phase 7 — 임원 대시보드 (2주)
전사 매출·KPI 차트, 미입금 현황, 전체 보고서 열람
Phase 8 — 자동 보고서 (2주)
generate-report Edge Function, pg_cron 스케줄, JSON 템플릿, PDF 생성
Phase 9 — 관리자 + 감사 로그 (2주)
사용자 초대UI, 역할 변경, 감사 로그 뷰어, 커미션 규칙 관리
Phase 10 — QA & 배포 (2주)
성능 최적화, 보안 점검, Cloudflare Pages 배포, 운영 전환
⚠️

남은 이슈 & 검토 필요 사항

#이슈중요도상태
1회사 이메일 도메인 확정 (이메일 도메인 제한 적용)높음미결
2커미션 규칙 세부 요율 확정 (A1·O2 별도 또는 공통)높음미결
3O2 커미션 계산 로직 별도 정의 여부높음미결
4보고서 PDF 생성 도구 선택 (Puppeteer Edge Function vs react-pdf)중간미결
5외부 이메일 발송 서비스 (Resend vs SendGrid)중간미결
6pg_cron 보고서 실행 시간 (KST 기준, Supabase UTC+0 주의)중간미결
7Supabase Storage 용량 한도 (Pro 플랜 100GB, 초과 시 추가 과금)중간미결
8계약 만료 D-30 자동 알림 설정중간미결
9임원 대시보드 데이터 갱신 주기 (실시간 vs 5분 캐시)낮음미결
10모바일 PWA 지원 범위 확정낮음미결
✅
Phase 0 승인 전 체크포인트:
위 10개 이슈 중 #1(도메인), #2·#3(커미션 규칙)은 마이그레이션 전 확정 필요. 나머지는 구현 단계에서 순차 결정 가능. 설계 승인 전까지 운영 데이터 생성 및 변경 없음.
📂

생성 산출물 목록

파일내용크기
01_menu_routes.md전체 메뉴 트리, 페이지 라우트, 역할별 접근 표6.4KB
02_workflow.md5개 부서 업무 흐름도, 자동 보고서 트리거, 초대 흐름4.4KB
03_erd_migration_part1.sqlENUM·기반 테이블 (departments~expenses), 트리거, 자동번호21KB
03_erd_migration_part2.sql나머지 테이블 (projects~audit_logs), 추가 정규화 테이블24.5KB
04_constraints_index.sql인덱스, UNIQUE·CHECK 제약, FK 다이어그램14.3KB
05_rls_permissions.sql헬퍼 함수, 전체 RLS 정책, 권한 매트릭스 주석25.2KB
06_auth_invite.md인증 설정, 초대 절차, Edge Function 코드, 보안 체크리스트7.3KB
07_audit_file.md감사 로그 설계, Storage RLS, Signed URL, 개인정보 마스킹10.7KB
08_implementation_plan.md10단계 구현 계획, 테스트 기준, 남은 이슈8.5KB
index.html통합 HTML 설계 보고서 (본 파일)~40KB