Skip to main content

테넌트 API

테넌트 관리를 위한 API 레퍼런스입니다.

개요

테넌트는 Multi-SaaS Kit의 핵심 격리 단위입니다. 각 테넌트는 독립적인 데이터 영역을 가집니다.

항목설명
격리 방식PostgreSQL RLS (Row-Level Security)
접근 권한Platform Admin, SaaS Admin만 전체 관리
데이터 범위테넌트별 완전 격리

권한별 접근

권한 레벨가능한 작업
Platform Admin (0)모든 테넌트 CRUD
SaaS Admin (1)모든 테넌트 CRUD
Tenant Admin (2)자기 테넌트 조회/수정
기타 (3-6)자기 테넌트 조회만

엔드포인트

GET /api/v1/tenants

테넌트 목록 조회

Request

GET /api/v1/tenants?page=1&per_page=15
Authorization: Bearer YOUR_TOKEN

Query Parameters

파라미터타입기본값설명
pageinteger1페이지 번호
per_pageinteger15페이지당 항목 수
searchstring-이름/slug 검색
statusstring-상태 필터 (active/suspended/trial)
planstring-요금제 필터
sortstringcreated_at정렬 필드
orderstringdesc정렬 방향

Response

성공 (200 OK)

{
"success": true,
"data": [
{
"id": 1,
"name": "Example Company",
"slug": "example",
"domain": "example.saas.com",
"status": "active",
"plan": "professional",
"settings": {
"timezone": "Asia/Seoul",
"locale": "ko"
},
"stats": {
"users_count": 25,
"organizations_count": 3
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T00:00:00Z"
}
],
"meta": {
"current_page": 1,
"total": 50
}
}

GET /api/v1/tenants/:id

테넌트 상세 조회

Request

GET /api/v1/tenants/1
Authorization: Bearer YOUR_TOKEN

Response

성공 (200 OK)

{
"success": true,
"data": {
"id": 1,
"name": "Example Company",
"slug": "example",
"domain": "example.saas.com",
"status": "active",
"plan": "professional",
"settings": {
"timezone": "Asia/Seoul",
"locale": "ko",
"features": {
"two_factor_auth": true,
"api_access": true,
"export_data": true
},
"limits": {
"max_users": 100,
"max_storage_gb": 50
}
},
"billing": {
"plan_started_at": "2024-01-01T00:00:00Z",
"next_billing_date": "2024-02-01T00:00:00Z"
},
"stats": {
"users_count": 25,
"organizations_count": 3,
"workspaces_count": 8,
"storage_used_mb": 1250
},
"owner": {
"id": 1,
"name": "관리자",
"email": "admin@example.com"
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T00:00:00Z"
}
}

POST /api/v1/tenants

새 테넌트 생성

권한 필요

Platform Admin 또는 SaaS Admin만 테넌트를 생성할 수 있습니다.

Request

POST /api/v1/tenants
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"name": "New Company",
"slug": "new-company",
"domain": "new.saas.com",
"plan": "starter",
"owner": {
"name": "관리자",
"email": "admin@new-company.com",
"password": "SecureP@ss123!"
},
"settings": {
"timezone": "Asia/Seoul",
"locale": "ko"
}
}

Request Body

필드타입필수설명
namestring테넌트 이름
slugstringURL slug (고유, 영문소문자/숫자/하이픈)
domainstring-커스텀 도메인
planstring-요금제 (기본: starter)
ownerobject테넌트 관리자 정보
owner.namestring관리자 이름
owner.emailstring관리자 이메일
owner.passwordstring관리자 비밀번호
settingsobject-테넌트 설정

Response

성공 (201 Created)

{
"success": true,
"message": "테넌트가 생성되었습니다.",
"data": {
"id": 2,
"name": "New Company",
"slug": "new-company",
"status": "active",
"owner": {
"id": 10,
"email": "admin@new-company.com"
},
"created_at": "2024-01-20T00:00:00Z"
}
}

PUT /api/v1/tenants/:id

테넌트 정보 수정

Request

PUT /api/v1/tenants/1
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"name": "Updated Company Name",
"settings": {
"timezone": "America/New_York",
"features": {
"api_access": false
}
}
}

Response

성공 (200 OK)

{
"success": true,
"message": "테넌트 정보가 수정되었습니다.",
"data": {
"id": 1,
"name": "Updated Company Name",
"updated_at": "2024-01-20T12:00:00Z"
}
}

DELETE /api/v1/tenants/:id

테넌트 삭제 (Soft Delete)

주의

테넌트 삭제 시 해당 테넌트의 모든 데이터(사용자, 조직, 워크스페이스 등)가 함께 삭제됩니다.

Request

DELETE /api/v1/tenants/1
Authorization: Bearer YOUR_TOKEN

Response

성공 (200 OK)

{
"success": true,
"message": "테넌트가 삭제되었습니다."
}

테넌트 상태 관리

PUT /api/v1/tenants/:id/suspend

테넌트 정지

PUT /api/v1/tenants/1/suspend
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"reason": "결제 실패",
"notify_users": true
}

PUT /api/v1/tenants/:id/activate

테넌트 활성화

PUT /api/v1/tenants/1/activate
Authorization: Bearer YOUR_TOKEN

테넌트 멤버 관리

GET /api/v1/tenants/:id/members

테넌트 멤버 목록 조회

GET /api/v1/tenants/1/members?page=1&role=admin
Authorization: Bearer YOUR_TOKEN

Response

{
"success": true,
"data": [
{
"id": 1,
"name": "홍길동",
"email": "hong@example.com",
"permission_level": 2,
"permission_level_name": "Tenant Admin",
"joined_at": "2024-01-01T00:00:00Z"
}
]
}

POST /api/v1/tenants/:id/members

테넌트에 멤버 추가 (초대)

POST /api/v1/tenants/1/members
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"email": "newuser@example.com",
"name": "신규 사용자",
"permission_level": 6,
"organization_id": 1,
"send_invitation": true
}

DELETE /api/v1/tenants/:id/members/:userId

테넌트에서 멤버 제거

DELETE /api/v1/tenants/1/members/5
Authorization: Bearer YOUR_TOKEN

테넌트 설정

GET /api/v1/tenants/:id/settings

테넌트 설정 조회

GET /api/v1/tenants/1/settings
Authorization: Bearer YOUR_TOKEN

Response

{
"success": true,
"data": {
"general": {
"timezone": "Asia/Seoul",
"locale": "ko",
"date_format": "Y-m-d",
"time_format": "H:i"
},
"features": {
"two_factor_auth": true,
"api_access": true,
"export_data": true,
"audit_log": true
},
"limits": {
"max_users": 100,
"max_organizations": 10,
"max_storage_gb": 50
},
"notifications": {
"email_digest": "daily",
"slack_webhook": null
}
}
}

PUT /api/v1/tenants/:id/settings

테넌트 설정 수정

PUT /api/v1/tenants/1/settings
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"general": {
"timezone": "America/New_York"
},
"features": {
"two_factor_auth": false
}
}

테넌트 통계

GET /api/v1/tenants/:id/stats

테넌트 사용량 통계

GET /api/v1/tenants/1/stats?period=30d
Authorization: Bearer YOUR_TOKEN

Query Parameters

파라미터설명
period기간 (7d, 30d, 90d, 1y)

Response

{
"success": true,
"data": {
"overview": {
"users_count": 25,
"active_users_count": 20,
"organizations_count": 3,
"workspaces_count": 8,
"teams_count": 12
},
"storage": {
"used_mb": 1250,
"limit_mb": 51200,
"usage_percent": 2.4
},
"activity": {
"logins_count": 450,
"api_calls_count": 12500,
"documents_created": 89
},
"growth": {
"new_users": 5,
"new_users_change": 25.0
}
}
}

오류 코드

HTTP 코드코드설명
400invalid_slug잘못된 slug 형식
403forbidden권한 부족
404tenant_not_found테넌트 없음
409slug_existsslug 중복
409domain_exists도메인 중복
422validation_error입력값 오류

사용 예제

cURL

# 테넌트 생성
curl -X POST "https://api.example.com/api/v1/tenants" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "New Tenant",
"slug": "new-tenant",
"owner": {
"name": "Admin",
"email": "admin@tenant.com",
"password": "SecureP@ss123!"
}
}'

# 테넌트 멤버 추가
curl -X POST "https://api.example.com/api/v1/tenants/1/members" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "user@tenant.com",
"name": "New User",
"permission_level": 6
}'

JavaScript

// 테넌트 생성
const createTenant = async (tenantData) => {
const response = await fetch('/api/v1/tenants', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(tenantData),
});

return response.json();
};

// 사용
const newTenant = await createTenant({
name: 'New Company',
slug: 'new-company',
owner: {
name: 'Admin',
email: 'admin@company.com',
password: 'SecureP@ss123!',
},
});

관련 문서