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": "[email protected]"
},
"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": "[email protected]",
"password": "SecureP@ss123!"
},
"settings": {
"timezone": "Asia/Seoul",
"locale": "ko"
}
}

Request Body​

필드타입필수설명
namestring✅테넌트 이름
slugstring✅URL 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": "[email protected]"
},
"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": "[email protected]",
"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": "[email protected]",
"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": "[email protected]",
"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": "[email protected]",
"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: '[email protected]',
password: 'SecureP@ss123!',
},
});

관련 문서​