Skip to content

BE 핸드오프 — Company·Office 생성

정본

  • migrations: supabase/migrations/20260713180000_company_office_creation.sql, supabase/migrations/20260714120000_company_office_property_creation.sql
  • RPC: create_company_office_with_property(text,text,text,text,text,integer,text[],text,text,jsonb)

RPC는 한 transaction에서 다음을 수행한다.

  1. 호출자의 active Company 관리자 membership 확인
  2. offices 생성
  3. 호출자를 office_memberships(role=office_admin,status=active)로 등록
  4. prototype checkout entitlement를 Company contract item으로 동기화
  5. 선택 module의 office_module_entitlements 생성
  6. 프로퍼티 후보를 선택했다면 property_external_code, property_data_source, 조회 시각, 원본 스냅샷 저장

요청 module은 호출자 소유 product_workspaces(slug=goldnus)의 active product_entitlements 부분집합이어야 한다. 프론트가 보낸 가격·계약 상태·관리자 이름은 신뢰하지 않는다. 가격 snapshot은 product_catalog에서 다시 읽는다.

불변식

  • Office 코드는 Company 안에서 unique.
  • Office·관리자 권한·entitlement 중 하나라도 실패하면 전체 rollback.
  • 선택한 data.go.kr 스냅샷 저장이 실패해도 전체 rollback하여 Office만 남는 부분 성공을 허용하지 않는다.
  • 빈 module 배열과 미계약 module은 거부.
  • security definer 함수의 search_pathpublic,pg_temp로 고정.
  • 호출 권한은 authenticated만 보유.

공공데이터 키는 서버 Edge Function 환경변수로 Leyve가 중앙 관리한다. Company·Office 요청에는 키를 받지 않는다. 주소 검색은 법정동을 포함한 사용자의 입력을 사용하며, 선택한 후보의 도로명주소와 호실 수는 생성 요청에 반영한다. 건축물대장 상세는 첫 응답의 totalCount로 페이지 수를 확정하고 최대 4페이지씩 제한 병렬 조회한다. 무제한 병렬 호출이나 100페이지 순차 호출로 사용자 요청을 장시간 점유하지 않는다.

로그인 후 Office 선택과 상단 업무 범위 전환의 radio-card 정정은 UI-only다. 서버는 계속 허용된 Office ID와 active membership을 기준으로 범위를 검증하며 라디오의 순서나 표시 문자열을 신뢰하지 않는다.