SpaceRole
SpaceRole은 Space 구성원에게 주는 권한 묶음입니다. Content Type·Content·Media에 대해 무엇을(읽기·생성·편집·삭제·발행) 할 수 있는지, Script를 실행·관리할 수 있는지, 그리고 Space 설정에 접근할 수 있는지를 한 리소스에 담습니다. 어떤 Content Type만, 자기가 만든 것만 등으로 권한 범위를 좁히는 필터도 SpaceRole 안에서 정합니다.
만든 SpaceRole은 그 자체로는 아무에게도 적용되지 않습니다. Space Membership의 roles에 이 SpaceRole의 Refer를 넣어 구성원에게 부여합니다. 한 구성원이 여러 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 Type의 Content만 읽도록 한정한 모습입니다.media: Media(파일·이미지)에 대한 권한 맵입니다.script: Script(프런트엔드가 호출하는 선언형 백엔드 엔드포인트)에 대한 권한 맵입니다. 실행(Execute)과 관리(생성·읽기·편집·삭제)를 액션별로 정합니다.settings: Space 설정 접근 권한을 정하는 문자열 배열입니다. 권한 맵이 아니라 액션 이름을 그대로 나열합니다. 전체 접근은["SETTING_ALL"], 아무 설정 접근도 주지 않으면[]이며, 필요한 설정만 골라 담을 수도 있습니다(아래settings참조).isLocked:true이면 Weegloo가 기본으로 제공하는 역할(예: Administrator)이라 수정·삭제할 수 없습니다.
시스템 속성 (sys)
모든 SpaceRole은 공통 시스템 속성을 sys 객체에 담습니다. space·createdBy·updatedBy는 Refer 모양({ "sys": { "id", "type": "Refer", "targetType" } })으로 들어갑니다.
| 속성 | 타입 | 설명 |
|---|---|---|
id | string | 리소스 고유 식별자. |
type | string | 리소스 종류. SpaceRole은 항상 "SpaceRole". |
space | Refer<Space> | 이 SpaceRole이 속한 Space. |
createdBy | Refer<User> | 생성한 사용자. |
createdAt | string (date-time) | 생성 시각. |
updatedBy | Refer<User> | 마지막으로 수정한 사용자. |
updatedAt | string (date-time) | 마지막 수정 시각. |
isLocked | boolean | true이면 기본 제공 역할이라 수정·삭제할 수 없습니다. 직접 만든 역할은 false입니다. |
version | integer (≥1) | 리소스 버전. 수정할 때마다 1씩 올라갑니다. |
SpaceRole은 발행 개념이 없는 설정 리소스입니다. 그래서 Content·Media와 달리 sys에 publish·archive·status가 없고, version만 가집니다. version은 SpaceRole을 수정할 때마다 오릅니다.
권한 맵: contentType·content·media
contentType·content·media는 각각 액션을 키로 갖는 맵입니다. 쓸 수 있는 액션은 Create(생성)·Read(읽기)·Edit(편집)·Delete(삭제)·Publish(발행)·Unpublish(발행취소)·Archive(보관)·Unarchive(보관해제)이며, 모든 액션을 한꺼번에 가리키는 All도 있습니다. Save라는 액션은 없습니다. 수정 권한은 Edit이고, Save는 Webhook이 구독하는 이벤트 이름입니다. 각 액션의 값은 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가 달린 리소스만으로 한정합니다.
어느 필터가 어느 권한 맵에서 뜻을 갖는지는 정해져 있습니다. 맞지 않는 필터를 넣으면 역할 저장이 거부됩니다. 조용히 무시하면 좁혔다고 생각한 규칙이 전체 허용이 되기 때문입니다.
| 권한 맵 | 쓸 수 있는 필터 | 넣으면 저장이 거부되는 필터 |
|---|---|---|
contentType | self(그 Content Type 자신)·createdBy | contentType |
content | contentType(그 Content가 속한 종류)·createdBy·tag | self |
media | createdBy·tag | self |
script | self(그 Script 자신)·createdBy | contentType·tag |
contentType맵의 대상은contentType이 아니라self로 지정합니다. Content Type 자신을 한정하는 일이기 때문입니다.contentType필터는 "이 리소스가 참조하는 종류"라는 뜻이라content맵에만 맞습니다.- 그 리소스에 없는 축으로 좁히려는 필터(Content Type에
tag, Media에contentType)는 저장이 막히지는 않지만 규칙이 의도대로 판정되지 않습니다. 쓰지 마세요.
createdBy필터(:self포함)를 CDA(전달)에서 판정할 때는 대상 Content Type의publishWithAuthor가true여야 합니다. CDA는 발행 스냅샷의sys.createdBy로 이 필터를 판정하는데,publishWithAuthor가 기본값false면 스냅샷에 작성자가 없어Allow규칙은 아무것도 매칭하지 않고,Deny규칙은 아무도 걸러내지 못합니다. CMA(관리)는 초안의sys.createdBy로 판정하므로 이 설정과 무관합니다.publishWithAuthor는 소급되지 않으니 콘텐츠를 발행하기 전에 켜야 하고, 이미 발행된 Content는 다시 발행해야 합니다. Content Type의publishWithAuthor설명을 참고하세요.
빈 Allow 배열 []는 그 종류 전체에 액션을 허용한다는 뜻입니다. 필터가 비어 있으니 거를 것이 없어, 모든 리소스에 그 액션이 열립니다.
빈 Deny 배열 []는 반대로 동작합니다. "아무것도 거부하지 않는다"가 아니라 그 종류 전체를 거부해서 그 액션을 완전히 막습니다. Allow를 함께 적어도 막힙니다. 거부할 대상이 없다는 뜻으로 []를 두면 정반대로 동작하므로, 아무것도 거부하지 않으려면 Deny 키 자체를 넣지 마세요.
예시 1: Administrator (전체 권한, 기본 제공)
Administrator 역할은 contentType·content·media·script 모두 All 액션에 빈 Allow를 주어 전체를 허용하고, settings에 ["SETTING_ALL"]을 주어 Space 설정 전체에 접근합니다. 이 역할은 Weegloo가 기본 제공하므로 sys.isLocked가 true이고 수정·삭제할 수 없습니다.
{
"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 역할의 예입니다. content의 Read 액션에만 규칙을 두고, 그 규칙의 contentType 필터로 특정 Content Type 하나로 한정합니다. Content Type 자체와 Media는 All을 빈 Allow로 열어 두었지만, 콘텐츠 데이터는 그 한 종류를 읽는 것만 가능합니다. settings가 []이므로 Space 설정에는 접근하지 못합니다. 이런 역할을 DeliveryAccessToken에 묶으면 전달 토큰이 그 범위만 읽게 됩니다. 이 역할의 JSON은 위 리소스 구조의 "상품 읽기 전용"과 같습니다.
settings (Space 설정 접근)
settings는 권한 맵이 아니라 문자열 배열입니다. Space 설정에 대한 접근 권한을 담으며, Allow/Deny도 필터도 없습니다. 배열에 넣은 액션은 허용되고, 넣지 않은 액션은 허용되지 않습니다.
전체 접근은 ["SETTING_ALL"], 아무 접근도 주지 않으면 []로 둡니다. 그 사이가 필요하면 아래 액션을 골라 담습니다.
| 액션 | 다룰 수 있게 되는 것 |
|---|---|
SETTING_GENERAL | Space 자체(이름·설명 등) |
SETTING_LOCALE | Locale |
SETTING_WEBHOOK | Webhook(호출 기록·상태 포함) |
SETTING_APP | Market App 설치 |
SETTING_TAG | Tag |
SETTING_DELIVERY_ACCESS_TOKEN | Delivery Access Token |
SETTING_SPACE_ACCESS_TOKEN | Space Access Token |
SETTING_USER | Space Membership(멤버 배정) |
SETTING_ROLE | SpaceRole |
SETTING_WEB_HOSTING | Web Hosting과 커스텀 도메인 |
SETTING_SERVICE_LOGIN | ServiceLogin·ServiceUser·ServiceUserRole |
SETTING_EMAIL_ACCOUNT | 메일 발신 계정 |
SETTING_MONITORING | 사용량·지표 조회 |
SETTING_SCHEDULER | Scheduler와 그 실행 기록 |
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 권한)
script는 Script(프런트엔드가 호출하는 선언형 백엔드 엔드포인트)에 대한 권한 맵입니다. 구조는 content·media와 같아, 액션을 키로 두고 Allow/Deny 규칙 배열을 값으로 가집니다. 쓰는 액션은 다음과 같습니다.
Create·Read·Edit·Delete: Script 리소스를 만들고, 조회하고, 수정하고, 삭제합니다.Execute: Script를 실행합니다(/execute호출). Script 고유 액션입니다.All: 위 모두를 포함하는 상위 액션입니다.
Script는 발행하는 리소스가 아니므로 Publish·Unpublish 같은 발행 액션은 쓰지 않습니다. 규칙 필터로 쓸 수 있는 것은 self와 createdBy 둘입니다.
self: 특정 Script 하나로 한정합니다. 그 Script를 가리키는Refer(targetType은Script)를 넣습니다.createdBy: 만든 사람으로 한정합니다(:self로 "자기가 만든 Script만").
contentType·tag는 Script에 붙지 않는 축이라, 넣으면 역할 저장이 거부됩니다.
예를 들어 모든 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.isLocked가 true인 기본 제공 역할은 수정·삭제할 수 없습니다.
관련 문서
- Space Membership: 구성원의
roles에 SpaceRole을 바인딩. - Delivery Access Token: least-privilege SpaceRole에 묶는 전달 토큰.
- Content Type: 권한 규칙이 가리키는 Content Type.
