작업 설명
기존 이슈 본문은 구 정책(user_team_permissions, can_* boolean permission, organization hierarchy, tag 권한)을 전제로 작성되어 있었으므로, 이 이슈의 기준을 현재 docs/ 문서로 재정의한다.
문서 기준:
docs/api/organization-rbac.md
docs/api/errors.md
docs/api/auth.md
docs/data-model/rbac-permission-policy.md
docs/data-model/physical-data-model.md
docs/architecture/auth-rbac.md
docs/decisions/ADR-202606271559-active-organization.md
docs/decisions/ADR-202606271559-auth-state-standard.md
docs/decisions/ADR-202606271559-user-direct-permission.md
충돌 해결 원칙:
GitHub 이슈 내용과 docs/가 충돌하면 항상 docs/를 따른다.
roles, user_roles, polymorphic resource_permissions는 만들지 않는다.
user_team_permissions, can_read, can_write, can_execute, can_delete, can_manage_tag, can_assign_tag 기준 API/권한 판정은 만들지 않는다.
권한 상태는 DB enum이 아니라 auth_state application-level matrix 기준으로 해석한다.
admin은 permission이 아니다.
Admin, Builder, Operator, Viewer, Auditor는 DB role이 아니라 team template 이름이다.
Active organization은 신규 organization-scoped API에서 X-Organization-Id header로 전달한다.
서버는 active organization을 session/cookie/organization row에 저장하지 않으며 PATCH /api/v1/organizations/current는 만들지 않는다.
범위 분리
이 이슈는 MVP1 범위로 좁힌다.
상세 작업
Organization / Active Organization API
GET /api/v1/organizations API를 추가한다. 인증된 사용자가 속한 active organization 목록을 반환한다.
GET /api/v1/organizations는 현재 사용자의 active team membership 기준으로 조회하고 중복 organization을 제거한다.
GET /api/v1/organizations 정렬은 created_at ASC, id ASC다.
GET /api/v1/organizations/{organization_id} API를 추가한다. 사용자의 active team membership scope 안에 있는 특정 active organization을 반환한다.
GET /api/v1/organizations/{organization_id}는 organization이 없거나 inactive 또는 scope 밖이면 404 + resource.not_found를 반환한다.
GET /api/v1/organizations/current API를 추가한다. X-Organization-Id header가 현재 사용자의 active team membership scope 안에 있으면 OrganizationResponse를 반환한다.
PATCH /api/v1/organizations/{organization_id} API를 추가한다. organization 자체 정보(name, options)만 partial update한다.
PATCH /api/v1/organizations/{organization_id}는 active organization 변경 API가 아니다.
PATCH /api/v1/organizations/{organization_id}는 X-Organization-Id header를 요구하고, header 값과 path의 organization_id가 다르면 404 + resource.not_found를 반환한다.
organization 수정 권한은 organization.created_by 또는 organization.managed_by인 organization manager 기준으로 판정한다.
created_by, managed_by, flags, is_active, deactivated_at은 이 endpoint에서 수정하지 않는다.
OrganizationResponse는 id, name, options, is_active, created_at, updated_at을 반환한다.
Team 관리 API
Resource Permission Grant/Revoke API
권한 계산 / Enforcement
Error / Audit
구 정책 기준에서 제외하는 항목
아래 항목은 기존 이슈 본문에 있었더라도 현재 문서와 충돌하므로 이 이슈 범위에서 제외한다.
organization 상위/하위 구조 API 또는 schema 신규 설계
PATCH /api/v1/organizations/current
user_team_permissions 조회/생성/삭제 API
can_manage_tag, can_assign_tag 기반 관리 권한
can_read, can_write, can_execute, can_delete boolean OR 기반 권한 계산
roles, user_roles, polymorphic resource_permissions 신규 생성
audit_events 신규 생성
user_connection_permissions, user_app_permissions, user_document_permissions, user_model_permissions 신규 생성
team 목록 응답의 effective permission 필드 추가
문서에 TBD로 남아 있는 Team 생성/수정/member API request/response schema의 임의 확정
테스트 기준
작업 설명
기존 이슈 본문은 구 정책(
user_team_permissions,can_*boolean permission, organization hierarchy, tag 권한)을 전제로 작성되어 있었으므로, 이 이슈의 기준을 현재docs/문서로 재정의한다.문서 기준:
docs/api/organization-rbac.mddocs/api/errors.mddocs/api/auth.mddocs/data-model/rbac-permission-policy.mddocs/data-model/physical-data-model.mddocs/architecture/auth-rbac.mddocs/decisions/ADR-202606271559-active-organization.mddocs/decisions/ADR-202606271559-auth-state-standard.mddocs/decisions/ADR-202606271559-user-direct-permission.md충돌 해결 원칙:
docs/가 충돌하면 항상docs/를 따른다.roles,user_roles, polymorphicresource_permissions는 만들지 않는다.user_team_permissions,can_read,can_write,can_execute,can_delete,can_manage_tag,can_assign_tag기준 API/권한 판정은 만들지 않는다.auth_stateapplication-level matrix 기준으로 해석한다.admin은 permission이 아니다.Admin,Builder,Operator,Viewer,Auditor는 DB role이 아니라 team template 이름이다.X-Organization-Idheader로 전달한다.PATCH /api/v1/organizations/current는 만들지 않는다.범위 분리
이 이슈는 MVP1 범위로 좁힌다.
user_knowledge_permissions, RAG node knowledge baseuse, knowledge permission audituser_audit_permissions, raw trace access control, audit visibility permission audit상세 작업
Organization / Active Organization API
GET /api/v1/organizationsAPI를 추가한다. 인증된 사용자가 속한 active organization 목록을 반환한다.GET /api/v1/organizations는 현재 사용자의 active team membership 기준으로 조회하고 중복 organization을 제거한다.GET /api/v1/organizations정렬은created_at ASC,id ASC다.GET /api/v1/organizations/{organization_id}API를 추가한다. 사용자의 active team membership scope 안에 있는 특정 active organization을 반환한다.GET /api/v1/organizations/{organization_id}는 organization이 없거나 inactive 또는 scope 밖이면404+resource.not_found를 반환한다.GET /api/v1/organizations/currentAPI를 추가한다.X-Organization-Idheader가 현재 사용자의 active team membership scope 안에 있으면OrganizationResponse를 반환한다.PATCH /api/v1/organizations/{organization_id}API를 추가한다. organization 자체 정보(name,options)만 partial update한다.PATCH /api/v1/organizations/{organization_id}는 active organization 변경 API가 아니다.PATCH /api/v1/organizations/{organization_id}는X-Organization-Idheader를 요구하고, header 값과 path의organization_id가 다르면404+resource.not_found를 반환한다.organization.created_by또는organization.managed_by인 organizationmanager기준으로 판정한다.created_by,managed_by,flags,is_active,deactivated_at은 이 endpoint에서 수정하지 않는다.OrganizationResponse는id,name,options,is_active,created_at,updated_at을 반환한다.Team 관리 API
GET /api/v1/teamsAPI를 추가한다.X-Organization-Idheader와limitquery를 받고list[TeamResponse]를 반환한다.GET /api/v1/teams는 관리 화면용 team 목록 API로만 사용한다. 일반 member의 “내 team 목록” 조회와 섞지 않는다.GET /api/v1/teams는 organizationmanager만 허용한다.organization.created_by또는organization.managed_by가 현재 user면 active team membership 없이도 접근 가능하다.GET /api/v1/teams는 active/inactive team을 모두 포함하고name ASC,id ASC로 정렬한다.GET /api/v1/teams의limit기본값은10, 허용 범위는1..100이다.GET /api/v1/teams응답에는member_count를 포함하지 않는다.teamstable에 해당 column이 없다.POST /api/v1/teamsAPI는 organizationmanager권한으로 추가한다. Request/Response 상세는 문서상TBD이므로 임의 schema를 만들지 않는다.PATCH /api/v1/teams/{team_id}API는 organizationmanager권한으로 추가한다. Request/Response 상세는 문서상TBD이므로 임의 schema를 만들지 않는다.POST /api/v1/teams/{team_id}/membersAPI는 organizationmanager권한으로 추가한다. Request/Response 상세는 문서상TBD이므로 임의 schema를 만들지 않는다.DELETE /api/v1/teams/{team_id}/members/{user_id}API는 organizationmanager권한으로 추가한다. Request는 없고 Response 상세는 문서상TBD이므로 임의 schema를 만들지 않는다.Resource Permission Grant/Revoke API
PUT /api/v1/permissions/workflows/{workflow_id}/teams/{team_id}API를 추가한다. workflowmanage또는 organizationmanager권한을 요구한다.DELETE /api/v1/permissions/workflows/{workflow_id}/teams/{team_id}API를 추가한다. workflowmanage또는 organizationmanager권한을 요구한다.PUT /api/v1/permissions/workflows/{workflow_id}/users/{user_id}API를 추가한다. workflowmanage또는 organizationmanager권한을 요구한다.DELETE /api/v1/permissions/workflows/{workflow_id}/users/{user_id}API를 추가한다. workflowmanage또는 organizationmanager권한을 요구한다.PUT /api/v1/permissions/llm-credentials/{credential_id}/teams/{team_id}API를 추가한다. credentialmanage또는 organizationmanager권한을 요구한다.DELETE /api/v1/permissions/llm-credentials/{credential_id}/teams/{team_id}API를 추가한다. credentialmanage또는 organizationmanager권한을 요구한다.PUT /api/v1/permissions/llm-credentials/{credential_id}/users/{user_id}API를 추가한다. credentialmanage또는 organizationmanager권한을 요구한다.DELETE /api/v1/permissions/llm-credentials/{credential_id}/users/{user_id}API를 추가한다. credentialmanage또는 organizationmanager권한을 요구한다.{ "auth_state": "viewer" }형태를 따른다.auth_state와 의미는docs/data-model/rbac-permission-policy.md의 resource별 matrix를 따른다.권한 계산 / Enforcement
teams와team_memberships다.team_workflow_permissions,team_llm_permissions를 기준으로 판정한다.user_workflow_permissions,user_llm_permissions로만 다룬다.auth_state='none'이면 deny by default로 처리한다.auth_state값은none과 동일하게 fail-closed 처리한다.organization.created_by또는organization.managed_by에 해당하는 user는 구현된 organization/team 관리 API에서 organizationmanager로 판정한다.use는 connection permission table이 아니라 consuming workflow 권한으로 허용한다. knowledge base 기준 connectionuse는 nodease/mbased#80에서 처리한다.Error / Audit
docs/api/errors.md의 목표 Error Envelope을 따른다.GET /api/v1/teams에서 인증 없음은401+auth.required를 반환한다.GET /api/v1/teams에서X-Organization-Idheader 누락은400+organization.required를 반환한다.GET /api/v1/teams에서 invalidX-Organization-Id또는 invalidlimit은422+validation.failed를 반환한다.GET /api/v1/teams에서 organization이 없거나 inactive 또는 사용자 scope 밖이면404+resource.not_found를 반환한다.GET /api/v1/teams에서 organization member지만 manager가 아니면403+permission.denied를 반환한다.GET /api/v1/organizations/{organization_id}에서 organization이 없거나 inactive 또는 사용자 scope 밖이면404+resource.not_found를 반환한다.PATCH /api/v1/organizations/{organization_id}에서X-Organization-Idheader 누락은400+organization.required를 반환한다.PATCH /api/v1/organizations/{organization_id}에서 invalidX-Organization-Id는422+validation.failed를 반환한다.PATCH /api/v1/organizations/{organization_id}에서 header 값과 path의organization_id가 다르면404+resource.not_found를 반환한다.PATCH /api/v1/organizations/{organization_id}에서 organization이 없거나 inactive 또는 현재 사용자의 scope 밖이면403+permission.denied를 반환한다.PATCH /api/v1/organizations/{organization_id}에서 현재 사용자가 organization member이지만 owner/manager가 아니면403+permission.denied를 반환한다.PATCH /api/v1/organizations/{organization_id}에서 변경 가능한 field가 없거나name이 빈 문자열이면400+validation.failed를 반환한다.PATCH /api/v1/organizations/{organization_id}에서name이 database column 길이보다 길면422+validation.failed를 반환한다.audit_logs에organization.update로 기록한다.audit_logs에 기록한다.구 정책 기준에서 제외하는 항목
아래 항목은 기존 이슈 본문에 있었더라도 현재 문서와 충돌하므로 이 이슈 범위에서 제외한다.
PATCH /api/v1/organizations/currentuser_team_permissions조회/생성/삭제 APIcan_manage_tag,can_assign_tag기반 관리 권한can_read,can_write,can_execute,can_deleteboolean OR 기반 권한 계산roles,user_roles, polymorphicresource_permissions신규 생성audit_events신규 생성user_connection_permissions,user_app_permissions,user_document_permissions,user_model_permissions신규 생성effective permission필드 추가TBD로 남아 있는 Team 생성/수정/member API request/response schema의 임의 확정테스트 기준
GET /api/v1/organizationsactive membership 조회, 중복 제거, 정렬 검증GET /api/v1/organizations/{organization_id}active membership scope와 404 envelope 검증PATCH /api/v1/organizations/{organization_id}header 누락/invalid/header-path mismatch 검증PATCH /api/v1/organizations/{organization_id}owner/manager 권한과 non-manager 거부 검증PATCH /api/v1/organizations/{organization_id}inactive/scope 밖 organization 거부 검증PATCH /api/v1/organizations/{organization_id}빈 update, blank name, max length validation 검증GET /api/v1/teams의X-Organization-Idheader 누락/invalid 케이스GET /api/v1/teams의limit기본값과 범위 검증GET /api/v1/teams에서 organization이 없거나 inactive이거나 사용자 scope 밖인 케이스GET /api/v1/teams에서 organization member지만 manager가 아닌 케이스GET /api/v1/teams에서 organization owner/manager가 active team membership 없이 접근하는 케이스GET /api/v1/teams가 active/inactive team을 모두 반환하는 케이스GET /api/v1/teams정렬이name ASC,id ASC인 케이스auth_statematrix 및 invalid state fail-closed 검증