SpaceRole

SpaceRoleSpace 구성원에게 주는 권한 묶음입니다. Content Type·Content·Media에 대해 무엇을(읽기·생성·편집·삭제·발행) 할 수 있는지, Script를 실행·관리할 수 있는지, 그리고 Space 설정에 접근할 수 있는지를 한 리소스에 담습니다. 어떤 Content Type만, 자기가 만든 것만 등으로 권한 범위를 좁히는 필터도 SpaceRole 안에서 정합니다.

만든 SpaceRole은 그 자체로는 아무에게도 적용되지 않습니다. Space Membershiproles에 이 SpaceRoleRefer를 넣어 구성원에게 부여합니다. 한 구성원이 여러 SpaceRole을 동시에 가질 수 있습니다. 또 DeliveryAccessToken도 least-privilege(최소 권한) SpaceRole 하나에 묶여, 그 토큰으로 전달받을 수 있는 범위가 결정됩니다.

리소스 구조

다음은 SpaceRole "상품 읽기 전용"의 단일 조회 응답입니다. sys(시스템 속성)와 함께, 권한을 정하는 본문 속성 contentType·content·media·settings·script를 가집니다.

{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7ObyNrQQbHbm",
    "type": "SpaceRole",
    "space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
    "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "createdAt": "2026-06-16T09:53:16.617Z",
    "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "updatedAt": "2026-06-16T09:53:16.617Z",
    "isLocked": false,
    "version": 1
  },
  "name": "상품 읽기 전용",
  "contentType": { "All": { "Allow": [] } },
  "content": {
    "Read": {
      "Allow": [
        { "contentType": { "sys": { "id": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA", "type": "Refer", "targetType": "ContentType" } } }
      ]
    }
  },
  "media": { "All": { "Allow": [] } },
  "settings": [],
  "script": {}
}

주요 키:

  • contentType: Content Type 자체(스키마)에 대한 권한 맵입니다. Content Type을 읽고, 만들고, 고치고, 삭제하고, 발행하는 권한을 액션별로 정합니다.
  • content: Content(콘텐츠 데이터)에 대한 권한 맵입니다. 위 예시는 특정 Content TypeContent만 읽도록 한정한 모습입니다.
  • media: Media(파일·이미지)에 대한 권한 맵입니다.
  • script: Script(프런트엔드가 호출하는 선언형 백엔드 엔드포인트)에 대한 권한 맵입니다. 실행(Execute)과 관리(생성·읽기·편집·삭제)를 액션별로 정합니다.
  • settings: Space 설정 접근 권한을 정하는 문자열 배열입니다. 권한 맵이 아니라 액션 이름을 그대로 나열합니다. 전체 접근은 ["SETTING_ALL"], 아무 설정 접근도 주지 않으면 []이며, 필요한 설정만 골라 담을 수도 있습니다(아래 settings 참조).
  • isLocked: true이면 Weegloo가 기본으로 제공하는 역할(예: Administrator)이라 수정·삭제할 수 없습니다.

시스템 속성 (sys)

모든 SpaceRole은 공통 시스템 속성을 sys 객체에 담습니다. space·createdBy·updatedByRefer 모양({ "sys": { "id", "type": "Refer", "targetType" } })으로 들어갑니다.

속성타입설명
idstring리소스 고유 식별자.
typestring리소스 종류. SpaceRole은 항상 "SpaceRole".
spaceRefer<Space>SpaceRole이 속한 Space.
createdByRefer<User>생성한 사용자.
createdAtstring (date-time)생성 시각.
updatedByRefer<User>마지막으로 수정한 사용자.
updatedAtstring (date-time)마지막 수정 시각.
isLockedbooleantrue이면 기본 제공 역할이라 수정·삭제할 수 없습니다. 직접 만든 역할은 false입니다.
versioninteger (≥1)리소스 버전. 수정할 때마다 1씩 올라갑니다.

SpaceRole은 발행 개념이 없는 설정 리소스입니다. 그래서 Content·Media와 달리 syspublish·archive·status가 없고, version만 가집니다. versionSpaceRole을 수정할 때마다 오릅니다.

권한 맵: contentType·content·media

contentType·content·media는 각각 액션을 키로 갖는 맵입니다. 쓸 수 있는 액션은 Create(생성)·Read(읽기)·Edit(편집)·Delete(삭제)·Publish(발행)·Unpublish(발행취소)·Archive(보관)·Unarchive(보관해제)이며, 모든 액션을 한꺼번에 가리키는 All도 있습니다. Save라는 액션은 없습니다. 수정 권한은 Edit이고, SaveWebhook이 구독하는 이벤트 이름입니다. 각 액션의 값은 Allow(허용)와 Deny(거부) 규칙 배열을 담은 객체입니다.

"content": {
  "Read":   { "Allow": [ /* 규칙 */ ], "Deny": [ /* 규칙 */ ] },
  "Edit":   { "Allow": [ /* 규칙 */ ] }
}

각 규칙(rule) 객체는 권한 범위를 좁히는 선택적 필터를 가집니다.

  • self: 그 규칙이 적용되는 대상을 리소스 자신 하나로 한정합니다. 대상 리소스를 가리키는 Refer를 넣습니다. contentType 맵에서는 특정 Content Type 하나를, script 맵에서는 특정 Script 하나를 뜻합니다.
  • contentType: 그 Content속한 Content Type으로 한정합니다. Content Type을 가리키는 Refer를 넣습니다.
  • createdBy: 특정 사용자가 만든 리소스만으로 한정합니다. sys.id에 특정 사용자 id를 넣으면 그 사람이 만든 것만, 예약값 :self를 넣으면 "지금 호출한 사용자가 만든 것만"으로 한정됩니다.
  • tag: 특정 Tag가 달린 리소스만으로 한정합니다.

어느 필터가 어느 권한 맵에서 뜻을 갖는지는 정해져 있습니다. 맞지 않는 필터를 넣으면 역할 저장이 거부됩니다. 조용히 무시하면 좁혔다고 생각한 규칙이 전체 허용이 되기 때문입니다.

권한 맵쓸 수 있는 필터넣으면 저장이 거부되는 필터
contentTypeself(그 Content Type 자신)·createdBycontentType
contentcontentType(그 Content가 속한 종류)·createdBy·tagself
mediacreatedBy·tagself
scriptself(그 Script 자신)·createdBycontentType·tag
  • contentType 맵의 대상은 contentType이 아니라 self로 지정합니다. Content Type 자신을 한정하는 일이기 때문입니다. contentType 필터는 "이 리소스가 참조하는 종류"라는 뜻이라 content 맵에만 맞습니다.
  • 그 리소스에 없는 축으로 좁히려는 필터(Content Typetag, MediacontentType)는 저장이 막히지는 않지만 규칙이 의도대로 판정되지 않습니다. 쓰지 마세요.

createdBy 필터(:self 포함)를 CDA(전달)에서 판정할 때는 대상 Content TypepublishWithAuthortrue여야 합니다. CDA는 발행 스냅샷의 sys.createdBy로 이 필터를 판정하는데, publishWithAuthor가 기본값 false면 스냅샷에 작성자가 없어 Allow 규칙은 아무것도 매칭하지 않고, Deny 규칙은 아무도 걸러내지 못합니다. CMA(관리)는 초안의 sys.createdBy로 판정하므로 이 설정과 무관합니다. publishWithAuthor는 소급되지 않으니 콘텐츠를 발행하기 전에 켜야 하고, 이미 발행된 Content는 다시 발행해야 합니다. Content TypepublishWithAuthor 설명을 참고하세요.

Allow 배열 []는 그 종류 전체에 액션을 허용한다는 뜻입니다. 필터가 비어 있으니 거를 것이 없어, 모든 리소스에 그 액션이 열립니다.

Deny 배열 []는 반대로 동작합니다. "아무것도 거부하지 않는다"가 아니라 그 종류 전체를 거부해서 그 액션을 완전히 막습니다. Allow를 함께 적어도 막힙니다. 거부할 대상이 없다는 뜻으로 []를 두면 정반대로 동작하므로, 아무것도 거부하지 않으려면 Deny 키 자체를 넣지 마세요.

예시 1: Administrator (전체 권한, 기본 제공)

Administrator 역할은 contentType·content·media·script 모두 All 액션에 빈 Allow를 주어 전체를 허용하고, settings["SETTING_ALL"]을 주어 Space 설정 전체에 접근합니다. 이 역할은 Weegloo가 기본 제공하므로 sys.isLockedtrue이고 수정·삭제할 수 없습니다.

{
  "sys": {
    "id": "3trmXRLdJF4GBlAjtcuoWfVubsasp4",
    "type": "SpaceRole",
    "space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
    "createdBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
    "createdAt": "2026-06-14T14:56:04.737Z",
    "updatedBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
    "updatedAt": "2026-06-14T14:56:04.737Z",
    "isLocked": true,
    "version": 1
  },
  "name": "Administrator",
  "description": "Members of this role have full access to everything in this space.",
  "contentType": { "All": { "Allow": [] } },
  "content": { "All": { "Allow": [] } },
  "media": { "All": { "Allow": [] } },
  "settings": ["SETTING_ALL"],
  "script": { "All": { "Allow": [] } }
}

예시 2: 읽기 전용 (특정 Content Type만)

직접 만드는 least-privilege 역할의 예입니다. contentRead 액션에만 규칙을 두고, 그 규칙의 contentType 필터로 특정 Content Type 하나로 한정합니다. Content Type 자체와 MediaAll을 빈 Allow로 열어 두었지만, 콘텐츠 데이터는 그 한 종류를 읽는 것만 가능합니다. settings[]이므로 Space 설정에는 접근하지 못합니다. 이런 역할을 DeliveryAccessToken에 묶으면 전달 토큰이 그 범위만 읽게 됩니다. 이 역할의 JSON은 위 리소스 구조의 "상품 읽기 전용"과 같습니다.

settings (Space 설정 접근)

settings는 권한 맵이 아니라 문자열 배열입니다. Space 설정에 대한 접근 권한을 담으며, Allow/Deny도 필터도 없습니다. 배열에 넣은 액션은 허용되고, 넣지 않은 액션은 허용되지 않습니다.

전체 접근은 ["SETTING_ALL"], 아무 접근도 주지 않으면 []로 둡니다. 그 사이가 필요하면 아래 액션을 골라 담습니다.

액션다룰 수 있게 되는 것
SETTING_GENERALSpace 자체(이름·설명 등)
SETTING_LOCALELocale
SETTING_WEBHOOKWebhook(호출 기록·상태 포함)
SETTING_APPMarket App 설치
SETTING_TAGTag
SETTING_DELIVERY_ACCESS_TOKENDelivery Access Token
SETTING_SPACE_ACCESS_TOKENSpace Access Token
SETTING_USERSpace Membership(멤버 배정)
SETTING_ROLESpaceRole
SETTING_WEB_HOSTINGWeb Hosting과 커스텀 도메인
SETTING_SERVICE_LOGINServiceLogin·ServiceUser·ServiceUserRole
SETTING_EMAIL_ACCOUNT메일 발신 계정
SETTING_MONITORING사용량·지표 조회
SETTING_SCHEDULERScheduler와 그 실행 기록
SETTING_ALL위 전부

토큰 두 종류는 액션이 나뉘어 있습니다. SETTING_DELIVERY_ACCESS_TOKEN만 주면 읽기 전용 Delivery Access Token은 발급할 수 있어도 쓰기까지 되는 Space Access Token은 발급하지 못합니다.

settings의 액션은 콘솔 로그인 세션과 Personal Access Token으로만 호출됩니다. Space Access Token·Delivery Access Token·ServiceUser 토큰은 역할에 어떤 액션을 넣어 두어도 이 목록의 API를 호출하지 못합니다.

권한 맵(contentType·content·media·script)의 액션 목록과 필터 키(self·contentType·createdBy·tag:self 의미, 그리고 어느 필터가 어느 맵에서 유효한지는 위 권한 맵: contentType·content·media 절을 따릅니다.

script (Script 권한)

scriptScript(프런트엔드가 호출하는 선언형 백엔드 엔드포인트)에 대한 권한 맵입니다. 구조는 content·media와 같아, 액션을 키로 두고 Allow/Deny 규칙 배열을 값으로 가집니다. 쓰는 액션은 다음과 같습니다.

  • Create·Read·Edit·Delete: Script 리소스를 만들고, 조회하고, 수정하고, 삭제합니다.
  • Execute: Script를 실행합니다(/execute 호출). Script 고유 액션입니다.
  • All: 위 모두를 포함하는 상위 액션입니다.

Script는 발행하는 리소스가 아니므로 Publish·Unpublish 같은 발행 액션은 쓰지 않습니다. 규칙 필터로 쓸 수 있는 것은 selfcreatedBy입니다.

  • self: 특정 Script 하나로 한정합니다. 그 Script를 가리키는 Refer(targetTypeScript)를 넣습니다.
  • createdBy: 만든 사람으로 한정합니다(:self로 "자기가 만든 Script만").

contentType·tagScript에 붙지 않는 축이라, 넣으면 역할 저장이 거부됩니다.

예를 들어 모든 Script를 실행할 수 있게 하되, 조회는 자기가 만든 것만 하도록 좁히려면 이렇게 씁니다.

"script": {
  "Execute": { "Allow": [] },
  "Read": {
    "Allow": [
      { "createdBy": { "sys": { "id": ":self", "type": "Refer", "targetType": "User" } } }
    ]
  }
}

self로 좁히면 Script 하나만 실행할 수 있는 최소 권한이 됩니다. 결제 대행사처럼 바깥 시스템에 실행 권한을 줄 때, 그 시스템이 부를 창구 하나만 열고 나머지는 닫아 두는 방법입니다.

"script": {
  "Execute": {
    "Allow": [
      { "self": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } } }
    ]
  }
}

이 역할을 Space Access Token에 묶으면 그 토큰으로는 지정한 Script 하나만 실행됩니다. 실행 권한 하나로 좁히는 이유와 Script 실행이 작성자의 권한을 위임받는다는 점은 Script의 실행 시맨틱, 제약, 보안에서 다룹니다.

script 권한은 "Script 리소스를 실행·관리할 수 있는가"를 정합니다. 이와 별개로, Script저작(생성·수정)할 때는 저장 시점에 작성자가 그 Script의 statement들이 다루는 Content·Media 작업 권한까지 실제로 갖고 있어야 하며, 없으면 저장이 거부됩니다(Script의 오류 참조). 자세한 내용은 Script의 실행 시맨틱, 제약, 보안에서 다룹니다.

오류

SpaceRole을 다룰 때 만나는 코드입니다. 모든 리소스에 공통인 코드는 공통 오류를 참조하세요.

코드조건
WGL400020그 권한 맵에서 뜻을 갖지 않는 필터를 규칙에 넣어 역할을 저장하려 했습니다.

API

아래 모든 엔드포인트의 기준 URL은 https://cma.weegloo.com/v1이며, Authorization 헤더에 CMA를 인증하는 Bearer 토큰이 필요합니다. 역할 수정(PUT·PATCH)에는 낙관적 동시성 제어를 위해 X-Weegloo-Version 헤더(현재 리소스의 sys.version)를 함께 보내야 합니다. 생성과 삭제에는 이 헤더가 없습니다. sys.isLockedtrue인 기본 제공 역할은 수정·삭제할 수 없습니다.