다크모드
Party Directory / 거래처 마스터 — BE 참고
독자: BE 개발자/AI. 구현 정본은
20260822000000_organization_workspace_canonical_baseline.sql이다.
1. 이번 슬라이스
Wave 1 F1-A 첫 운영 슬라이스는 거래처 화면에 필요한 공통 Party 기반만 만든다.
- 포함: Party DB, Workspace assignment, roles, RLS, create/update RPC, 거래처 CRUD
- 제외: 멤버·사업체 페이지 DB 전환, 계약·Unit, 회계 FK, 안전한 통합/삭제
- 운영 DB 적용: 이 작업에서는 금지. migration 파일과 로컬 검증 계약만 제공한다.
2. Identity 불변식
목록의 법인 / 개인은 프런트엔드 표시·검색 분류다. 개인사업자는 개인에 포함하지만 저장된 legal_type·party_kind·등록번호를 변환하지 않는다. 이 표시 조정으로 API·스키마·사업체 projection을 변경하지 않는다.
| 구분 | 저장 위치 | 규칙 |
|---|---|---|
| 시스템 고유코드 | master_parties.id | UUID PK, 고객에게 노출하지 않음 |
| 관리코드 | workspace_party_assignments.management_code | Workspace 범위 unique, create 시 입력 또는 자동 생성, 이후 불변 |
| 등록종류·등록번호 | master_parties.registration_kind/registration_number | 중복 허용, create 이후 불변 |
| 이름 | master_parties.display_name | 중복·수정 허용 |
등록번호는 identity가 아니다. 같은 등록번호가 여러 UUID에 존재할 수 있고 자동 병합하지 않는다. 조회·중복 후보 표시에만 사용한다.
3. 스키마
master_parties
Organization 범위 Party 본체다. party_kind, legal_type, 등록정보, 이름, 대표자, 사업·연락 속성, 상태와 작성자를 가진다.
organization_id → organizations.id(organization_id, registration_kind, registration_number)는 비고유 조회 인덱스organization_id, 등록종류, 등록번호 변경은 trigger가party_identity_immutable로 거부
workspace_party_assignments
Party를 Workspace에 노출하고 고객 안정키인 관리코드를 부여한다.
workspace_id → workspaces.idparty_id → master_parties.idunique(workspace_id, management_code)unique(workspace_id, party_id)- Workspace와 Party의 Organization가 다르면
party_workspace_organization_mismatch - workspace, party, management code 변경은
party_assignment_identity_immutable
workspace_party_roles
assignment별 다중 역할이다.
memberar_customerap_vendorfacility_partner
PK는 (assignment_id, role)이다.
4. 권한·RLS
세 public 테이블 모두 RLS를 활성화한다.
- Organization active membership: 해당 Organization Party/assignment 조회
- Workspace active membership: 자신이 배정된 Workspace assignment와 연결 Party 조회
- 수정 가능 Organization Role:
organization.owner | organization.admin | organization.manager - 수정 가능 Workspace Role:
workspace.owner | workspace.admin | workspace.manager organization.viewer | workspace.viewer: 읽기만 가능- anon: 테이블·RPC 권한 없음
권한 helper와 mutation 구현은 비노출 private schema의 SECURITY DEFINER, search_path='' 함수다. public RPC는 SECURITY INVOKER wrapper이며 authenticated만 실행할 수 있다.
현재 Supabase Data API는 grant와 RLS를 별도 계층으로 취급하므로 migration에서 둘을 함께 명시한다. authenticated는 테이블 SELECT만 받고 INSERT/UPDATE/DELETE는 받지 않는다. 쓰기는 RPC만 허용한다.
- Supabase: Securing your API
- Supabase: Row Level Security
- Supabase breaking change: tables not exposed automatically
5. RPC
create_master_party
한 transaction에서 다음을 수행한다.
- 인증과 Workspace 관리권한 확인
- Workspace Organization 결정
- Party UUID 생성
- 관리코드 입력값 정규화 또는
CP-{UUID 8자리}생성 - Party, assignment, roles 삽입
- FE용 JSON 반환
등록번호에는 unique 검사를 하지 않는다. 관리코드 충돌만 DB unique constraint로 거부한다.
update_master_party
assignment_id로 대상과 권한을 잠그고 이름·역할·연락 속성·상태만 갱신한다. 파라미터에 등록정보·관리코드·Organization·Workspace가 존재하지 않는다. DB trigger도 우회 변경을 거부한다.
6. 인덱스
master_parties(organization_id)master_parties(organization_id, registration_kind, registration_number)— non-uniqueworkspace_party_assignments(party_id)workspace_party_assignments(workspace_id, status, created_at desc, id)workspace_party_roles(role, assignment_id)- 작성자 FK partial indexes
7. 검증
partyDirectoryMigration.spec.js: 테이블·불변 trigger·RLS·grants·private helper·인덱스 정적 계약partyDirectoryRepo.spec.js: query/RPC payload와 DB↔FE 정규화- 실제 SQL reset/advisor는 Docker 또는 Supabase dev branch에서 migration 적용 전 반드시 실행
- 운영 DB에는 이 작업에서 적용하지 않는다.
8. 후속 계약
2026-09-15 KST — 담당자 확장 필드의 저장 경계
현재 migration과 create_master_party/update_master_party는 mobile_number, phone_number, fax_number, email 네 연락처만 지원합니다. 프런트 복원 후보는 이를 주담당자 연락처로 그대로 매핑하고 부서·이름·비고 및 부담당자 7필드를 추가하지만, 기존 RPC에 새 인자를 임의로 보내지 않습니다. mock 모드만 확장 값의 메모리 저장을 지원합니다. 실서버 모드는 미지원 입력을 readonly 처리하고, adapter에서도 미지원 비어 있지 않은 값이 있으면 전체 요청을 RPC 이전에 거부합니다.
추가 영속 저장에는 별도 모델·권한·migration·RPC 반환 계약의 승인이 필요합니다. 이번 작업은 그 계약이나 운영 DB를 변경하지 않았습니다. UI 표시 복원을 서버 저장 복원으로 보고하지 않습니다.
- 멤버와 사업체를 같은 Party UUID에 연결
- 시설 projection을 DB-backed adapter로 전환
- 회계 전표에는
party_idFK와 거래 당시 명칭 snapshot을 함께 저장 - Unit 정본 이후 occupancy contract가
workspace_party_assignment_id를 참조 - 통합은 모든 FK 재연결과 감사 이력 RPC가 생기기 전까지 금지