Skip to content

Party Directory / 거래처 마스터 — FE 메인테이너 참고

2026-09-15 KST — 담당자 정보 완전성 (로컬 후보)

상세·생성에 주담당자와 부담당자 카드를 한 열로 표시합니다. 각 7필드(부서·이름·휴대전화·일반전화· 팩스·이메일·비고)이며 ContactPersonCardOrg를 멤버 사업자 증빙과 함께 사용합니다. contactPersonFields.js가 필드 매핑을 소유하고 기존 mobileNum/phoneNum/faxNum/email은 주담당자의 단일 원본으로 유지합니다. 원본 필드명·목록 이메일·서버 RPC 인자는 바꾸지 않습니다.

mock에서는 확장 필드도 create/edit/read에 왕복합니다. Supabase 모드에서는 기존 4개 연락처만 저장 가능하므로 나머지 10개 입력은 readonly이고 접근성 설명을 제공합니다. adapter도 지원되지 않는 비어 있지 않은 값이 들어오면 RPC 이전에 거부합니다. 미지원 필드를 조용히 버리고 성공으로 표시하지 않습니다. 실제 DB·API 확장과 배포는 이 로컬 후보에 포함하지 않습니다. 기존 거래처에 두 담당자 정보가 실제 저장돼 있었다는 이력은 확인되지 않았으며, 사업자 상세의 이전 7+7 화면을 복원 기준으로 삼았습니다.

검증: ContactPersonCards.spec.js, contactPersonFields.spec.js, useCounterpartyContacts.spec.js 및 실제 거래처 route.

독자: FE 메인테이너/AI. 이번 슬라이스는 거래처 페이지까지 운영화한다.

1. 데이터 흐름

text
useAccountContext.activeWorkspace.id
  → useCounterparties.loadCounterparties(workspaceId)
  → partyDirectoryRepo.listByWorkspace()
  → workspace_party_assignments + master_parties + workspace_party_roles
  → module-level reactive store
  ├─ counterparties      거래처 화면
  ├─ businesses          기존 사업체 호환 projection
  └─ facilityPartners    기존 시설 호환 projection

Supabase 설정이 없거나 test mode이면 기존 8건 seed를 유지한다. 연결 환경에서는 현재 Workspace의 DB 행으로 같은 store를 교체한다. 이 방식으로 사업체·시설 소비 API를 깨지 않으면서 거래처 화면부터 운영화했다.

2. 파일

파일역할
src/composables/partyDirectoryRepo.jsDB row 정규화, Workspace 조회, create/update RPC
src/composables/useCounterparties.js호환 projection + 로딩/오류/선택/CRUD adapter
components/master-data/counterparty/general/MainOrg.vueactive Workspace 변경 시 조회
blocks/DynamicTableOrg.vue이름→타입→등록번호→역할 목록, 정확한 UUID 선택
overlays/SheetCreateCounterpartyArt.vuecreate 전용 전체 폼
overlays/SheetReadCounterpartyArt.vue단일 read↔edit 상세 시트

별도 SheetUpdateCounterpartyArt.vue는 제거했다.

3. 호환 API

기존 소비자를 위해 아래 동기 API를 유지한다.

  • counterparties, businesses, facilityPartners
  • byRegNum, counterpartyOf, counterpartiesByRegNum, hasRole
  • addCounterparty, updateCounterparty, resetCounterparties

updateCounterpartyid, assignment, Organization/Workspace, 관리코드, 등록종류·등록번호 patch를 버린다. mock seam에서도 DB 불변식과 같은 방향을 유지한다.

운영 화면용 추가 API:

  • loading, error, backend
  • selectedCounterparty, selectCounterparty
  • loadCounterparties(workspaceId)
  • createCounterparty(input)
  • saveCounterparty(id, input)

4. DB↔FE 값 매핑

FEDB
매출처ar_customer
매입처ap_vendor
시설협력업체facility_partner
사업자등록번호business_registration_number
주민등록번호resident_registration_number
법인corporation
개인사업자sole_proprietor
개인individual

등록번호 중복은 배열 index로 유지하지만 identity는 항상 counterparty.id UUID다.

5. 화면 규약

  • 목록: 관리코드와 전용 상세 열 없음
  • 목록 타입 배지·Criteria: 법인 / 개인 두 분류. 원본 legalType의 개인사업자는 목록에서 개인으로 표시하고, 개인 필터에 포함한다. 등록·상세와 사업체 projection이 사용하는 3종 원본 값은 변경하지 않는다.
  • 주 식별자 이름: font-medium cursor-pointer hover:underline
  • 이름 클릭: 먼저 selectCounterparty(row), 같은 버튼이 상세 시트를 엶
  • 상세: 관리코드는 우측 상단에만 표시
  • read↔edit: 한 시트 안에서 전환
  • edit: 등록종류·등록번호 disabled
  • save: 이름·역할 유효 + dirty일 때만 활성
  • create: 관리코드·등록정보 최초 입력 가능
  • merge/delete/upload: backend 이력·검증 계약 전까지 disabled

6. 테스트

  • partyDirectoryRepo.spec.js
  • useCounterparties.spec.js
  • blocks/__tests__/DynamicTableOrg.spec.js
  • overlays/__tests__/SheetReadCounterpartyArt.spec.js
  • partyDirectoryMigration.spec.js

회귀 시 facility/business 화면이 같은 객체 projection을 계속 소비하는지 useCounterparties.spec.js의 참조 동일성 단언을 보존한다.

7. 후속 시 주의

  • useAccountContext.js, router, locale을 이 슬라이스에서 수정하지 않았다.
  • 사업체/시설을 DB로 전환할 때 새 store를 만들지 말고 현재 adapter에 role/profile projection을 추가한다.
  • 멤버는 owner 결정의 카드별 편집 + 전체 편집 이원화 패턴을 별도로 유지한다.
  • 회계·계약·Unit 파일은 Party UUID 계약 병합 후 각 소유 트랙이 연결한다.