다크모드
Organization Owner 계정 생성 — Backend Handoff
정본
- baseline:
supabase/migrations/20260822000000_organization_workspace_canonical_baseline.sql - atomic CreateAccount trigger function:
private.create_organization_owner_account() - metadata kind:
create_account_kind = organization_owner - checkout flow value:
flow_mode = sign_up
이 baseline이 Prototype의 최종 blueprint다. 이전 scope metadata와 이전 DB 식별자를 담은 전환 migration·alias는 없다. Prototype DB는 baseline에서 새로 구성한다. DB column·RPC payload는 snake_case sign_up을 사용하며 kebab-case sign-up은 public URL과 query에만 사용한다.
Canonical blueprint 검증
2026-08-25에 로컬 Supabase CLI 2.115.0 / PostgreSQL 17 disposable DB를 canonical baseline 하나로 reset해 PASS했다. catalog-zero read-only audit와 아래 12개 rollback SQL smoke도 모두 PASS했다.
organization_workspace_catalog_zero_smoke.sqlorganization_workspace_canonical_core_smoke.sqliam_identity_access_prototype_smoke.sqliam_role_hierarchy_smoke.sqliam_session_scope_smoke.sql(supabase_admin실행 문맥)sales_distribution_core_smoke.sqlsales_partner_provisioning_worker_smoke.sqlaccounting_core_smoke.sqlaccounting_period_close_smoke.sqlapproval_document_workflow_smoke.sqlattendance_period_close_smoke.sqlworkforce_attendance_exceptions_smoke.sqltime_attendance_corrections_smoke.sql
이 검증은 최종 canonical 객체와 IAM·Sales 소비처가 함께 동작한다는 blueprint evidence다. Prototype DB 역시 동일 baseline에서 다시 만들며 이전 식별자의 migration, alias, redirect를 두지 않는다.
확인 후 bootstrap
Supabase SDK의 auth.signUp()은 미확인 Auth 사용자와 확인 메일만 만든다. email_confirmed_at이 채워지고 create_account_kind가 organization_owner일 때 private trigger function이 다음을 한 트랜잭션에서 생성한다.
user_profilesorganizations- active Organization Membership +
organization.ownerRole Assignment workspace_number = 0인 본점workspaces행- Organization Owner의
workspace.owner효과 Role 투영(직접 Workspace Role 중복 없음) - 상품 checkout projection
확인 전에는 public row와 사업자등록번호 선점이 없다. 어느 insert라도 실패하면 bootstrap 전체가 rollback된다. 같은 Auth 사용자에 user_profiles가 이미 있으면 멱등하게 종료한다.
입력 metadata
| 키 | 규칙 | 저장 위치 |
|---|---|---|
full_name | 공백 제외 필수 | user_profiles.full_name |
phone | 숫자 10~11자리, 0 시작 | user_profiles.phone |
organization_name | 필수 | organizations.display_name |
representative_name | 필수 | organizations.representative_name |
business_number | 숫자 10자리, 활성 Organization 전체 unique | organizations.business_number |
terms_accepted | true 필수 | user_profiles.terms_accepted_at |
패스워드는 Supabase Auth만 소유한다. public schema, Auth metadata, 애플리케이션 로그에 복제하지 않는다.
Organization·Workspace 불변식
- Organization과 Workspace는
organizations,workspaces단일 본체를 사용한다. - 초기 Workspace는
workspace_number = 0이며 Organization 생성 트랜잭션 안에서 함께 만든다. - Workspace의
organization_id,workspace_number,code는 생성 후 변경하지 않는다. - 가입 결과와 로그인 payload는
organizationId,workspaceId,workspaceNumber를 사용한다. - 이전 scope column, JSON key, relation, view, RPC alias는 제공하지 않는다.
권한과 세션 복원
- 가입 trigger는
security definer이며 제한된search_path를 사용한다. - 고객이 전달한 Organization ID로 기존 Organization의 membership을 만들지 않는다.
- 로그인 복원은 현재 Principal의 활성 Organization/Workspace Membership과 Product Activation을 서버에서 다시 읽는다.
- 브라우저 localStorage나 Auth metadata를 접근권 정본으로 사용하지 않는다.
미구현 경계
- 사업자등록번호 국세청 진위확인
- 동일 Organization에 대한 신규 Owner 가입 대신 초대 전환
- Organization 폐쇄와 법적 보존기간 처리
- 공공데이터 건축물 식별자와 Workspace 프로퍼티 연결