テナント削除
テナントとそれに関連するすべてのデータを完全に削除します。この操作は安全のために3重の検証が必要です。
重要: このページのすべてのエンドポイントはグローバルAPIキーが必要です。これは取り消しできない危険な操作です。
テナント削除
DELETE /api/tenant
テナントとそれに関連するすべてのデータを完全に削除します。安全のため3重の検証が必要です。
警告
この操作は元に戻せません。すべてのテナントデータが完全に削除されます:
- すべてのプロジェクトとそのデータセット
- すべての調査、ノートブック、ダッシュボード
- BLOBストレージコンテナとファイル
- データベースのレコードおよび設定
- テナントへのユーザー割り当て(ユーザー自体は削除されません)
テナントを削除する前に、重要なデータを必ずエクスポートしてください。
リクエストボディ
{
"tenantId": "12345678-1234-1234-1234-123456789012",
"name": "acme-corp",
"displayName": "Acme Corporation"
}
3重検証
削除を進めるには、3つの識別子すべてが正確に一致している必要があります:
| フィールド | 種類 | 必須 | 説明 |
|---|---|---|---|
tenantId |
GUID | 必須 | 削除対象のテナントID |
name |
文字列 | 必須 | テナント名(正確に一致する必要があります) |
displayName |
文字列 | 必須 | 表示名(正確に一致する必要があります) |
この3重検証によって、3つの識別子すべてを知り確認する必要があり、誤削除を防止します。
レスポンス(200 OK)
{
"message": "Tenant 'Acme Corporation' deleted successfully",
"tenantName": "acme-corp",
"tenantDisplayName": "Acme Corporation",
"storageContainerDeleted": true
}
レスポンスフィールド
| フィールド | 種類 | 説明 |
|---|---|---|
message |
文字列 | 削除成功の確認メッセージ |
tenantName |
文字列 | 削除されたテナントのシステム名 |
tenantDisplayName |
文字列 | 削除されたテナントの表示名 |
storageContainerDeleted |
ブール | Blobストレージが削除されたか |
エラー応答
Not Found (404)
{
"error": "Tenant not found with ID '12345678-1234-1234-1234-123456789012'"
}
検証失敗 (400)
テナント名が不一致の場合:
{
"error": "Tenant name 'wrong-name' does not match the tenant with ID '12345678-1234-1234-1234-123456789012'. Expected 'acme-corp'.",
"hint": "安全のために3つの識別子(ID、名前、表示名)がすべて正確に一致する必要があります"
}
表示名が不一致の場合:
{
"error": "Display name 'Wrong Name' does not match the tenant with ID '12345678-1234-1234-1234-123456789012'. Expected 'Acme Corporation'.",
"hint": "安全のために3つの識別子(ID、名前、表示名)がすべて正確に一致する必要があります"
}
認証エラー (401)
{
"error": "This endpoint requires a Global API key.",
"hint": "グローバルAPIキーは /admin/global-api-keys で作成できます"
}
実装例
cURL
# テナント削除(3重検証が必要)
curl -X DELETE "https://your-mindzie-instance.com/api/tenant" \
-H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenantId": "12345678-1234-1234-1234-123456789012",
"name": "test-tenant",
"displayName": "Test Tenant"
}'
Python
import requests
BASE_URL = 'https://your-mindzie-instance.com'
class TenantDeleter:
def __init__(self, global_api_key):
"""グローバルAPIキー(テナント固有ではない)で初期化します。"""
self.headers = {
'Authorization': f'Bearer {global_api_key}',
'Content-Type': 'application/json'
}
def get_tenant(self, tenant_id):
"""検証用にテナント詳細を取得します。"""
url = f'{BASE_URL}/api/tenant/{tenant_id}'
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()
def delete_tenant(self, tenant_id, name, display_name, confirm=False):
"""
3重検証によるテナント削除。
引数:
tenant_id: テナントのGUID
name: テナントのシステム名(正確に一致)
display_name: テナントの表示名(正確に一致)
confirm: Trueに設定すると実際に削除を実行
"""
if not confirm:
# 検証モード - 値が一致するか確認
tenant = self.get_tenant(tenant_id)
errors = []
if tenant['name'] != name:
errors.append(f"名前の不一致: 期待値 '{tenant['name']}', 入力値 '{name}'")
if tenant['displayName'] != display_name:
errors.append(f"表示名の不一致: 期待値 '{tenant['displayName']}', 入力値 '{display_name}'")
if errors:
raise ValueError("検証失敗:\n" + "\n".join(errors))
print(f"テナント '{display_name}' ({name}) の検証に成功しました")
print(f" - ID: {tenant_id}")
print(f" - ユーザー数: {tenant.get('userCount', 'N/A')}")
print(f" - ケース数: {tenant.get('caseCount', 'N/A')}")
print("\n削除を実行するには confirm=True を指定して呼び出してください。")
return None
# 削除を実行
url = f'{BASE_URL}/api/tenant'
payload = {
'tenantId': tenant_id,
'name': name,
'displayName': display_name
}
response = requests.delete(url, json=payload, headers=self.headers)
if response.ok:
return response.json()
elif response.status_code == 404:
raise Exception(f'テナントが見つかりません: {tenant_id}')
elif response.status_code == 400:
error = response.json()
raise Exception(f"検証失敗: {error.get('error', '不明なエラー')}")
else:
raise Exception(f'テナント削除に失敗しました: {response.text}')
# 使用例 - 安全な削除ワークフロー
deleter = TenantDeleter('your-global-api-key')
tenant_id = '12345678-1234-1234-1234-123456789012'
tenant_name = 'test-tenant'
display_name = 'Test Tenant'
# ステップ1: 検証(削除は行わない)
try:
deleter.delete_tenant(tenant_id, tenant_name, display_name, confirm=False)
except ValueError as e:
print(f"検証に失敗しました: {e}")
exit(1)
# ステップ2: 削除を確定(準備ができたらコメントアウトを解除)
# result = deleter.delete_tenant(tenant_id, tenant_name, display_name, confirm=True)
# print(f"削除完了: {result['message']}")
JavaScript
const BASE_URL = 'https://your-mindzie-instance.com';
class TenantDeleter {
constructor(globalApiKey) {
this.headers = {
'Authorization': `Bearer ${globalApiKey}`,
'Content-Type': 'application/json'
};
}
async getTenant(tenantId) {
const url = `${BASE_URL}/api/tenant/${tenantId}`;
const response = await fetch(url, { headers: this.headers });
if (!response.ok) throw new Error(`テナント取得に失敗しました: ${response.status}`);
return await response.json();
}
async deleteTenant(tenantId, name, displayName, confirm = false) {
if (!confirm) {
// 検証モード
const tenant = await this.getTenant(tenantId);
const errors = [];
if (tenant.name !== name) {
errors.push(`名前の不一致: 期待値 '${tenant.name}', 入力値 '${name}'`);
}
if (tenant.displayName !== displayName) {
errors.push(`表示名の不一致: 期待値 '${tenant.displayName}', 入力値 '${displayName}'`);
}
if (errors.length > 0) {
throw new Error('検証失敗:\n' + errors.join('\n'));
}
console.log(`テナント '${displayName}' (${name}) の検証に成功しました`);
console.log(` - ID: ${tenantId}`);
console.log(` - ユーザー数: ${tenant.userCount || 'N/A'}`);
console.log('\n削除を実行するには confirm=true を指定してください。');
return null;
}
// 削除を実行
const url = `${BASE_URL}/api/tenant`;
const response = await fetch(url, {
method: 'DELETE',
headers: this.headers,
body: JSON.stringify({ tenantId, name, displayName })
});
if (response.ok) {
return await response.json();
}
const error = await response.json();
throw new Error(error.error || `削除失敗: ${response.status}`);
}
}
// 使用例 - 安全な削除ワークフロー
const deleter = new TenantDeleter('your-global-api-key');
const tenantId = '12345678-1234-1234-1234-123456789012';
const tenantName = 'test-tenant';
const displayName = 'Test Tenant';
// ステップ1: 検証(削除は実行しない)
try {
await deleter.deleteTenant(tenantId, tenantName, displayName, false);
} catch (e) {
console.error(`検証に失敗しました: ${e.message}`);
process.exit(1);
}
// ステップ2: 削除を確定(準備ができたらコメント解除)
// const result = await deleter.deleteTenant(tenantId, tenantName, displayName, true);
// console.log(`削除完了: ${result.message}`);
安全な運用のベストプラクティス
削除前に
- すべてのデータをエクスポート: Project APIを使い、すべてのプロジェクトを .mpz ファイルとしてエクスポートする
- ユーザー確認: 割り当てられているユーザーを確認し通知する
- 記録を残す: 何をなぜ削除するのか監査用に記録する
- 再確認: テナントID、名前、表示名が正しいか確認する
削除中に
- 検証パターンを使う: まず検証のみでdeleteエンドポイントを呼び出す
- レスポンス確認: 正しいテナント情報が返されるかチェックする
- 慎重に確定: 手動で検証し終えてから
confirm=Trueを指定する
削除後に
- 削除の検証: テナント一覧に削除したテナントが表示されないことを確認する
- ユーザーのアクセス確認: 該当ユーザーが削除されたテナントにアクセスできないか確認する
- ドキュメント更新: システムドキュメントに削除記録を残す
代替案:削除ではなく無効化
データを保持しつつアクセスを制限したい場合は、テナントを無効化することを検討してください:
# テナント無効化(データは保持)
curl -X PUT "https://your-mindzie-instance.com/api/tenant" \
-H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenantId": "12345678-1234-1234-1234-123456789012",
"isDisabled": true
}'
無効化されたテナント:
- ユーザーはテナントにログインできません
- すべてのデータは保持されます
- 後で
isDisabled: falseに設定して再有効化可能 - テナント一覧には
isDisabled: trueとして表示されます
通常は永続的な削除より安全な選択肢です。