🏢 組織サービス
組織サービスは、組織エンティティをCRUD操作で管理するための完全な REST API を提供します。NodeBlocks の関数型合成アプローチで構築され、MongoDB とシームレスに統合します。
🚀 クイックスタート
import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { organizationService } = services;
const { getMongoClient, createFileStorageDriver } = drivers;
const client = getMongoClient('mongodb://localhost:27017', 'dev');
// オプションですが、ロゴ正規化およびアップロードURLには推奨されます:
// GOOGLE_APPLICATION_CREDENTIALS が GCP サービスアカウント JSON を指していることを確認してください。
const fileStorageDriver = createFileStorageDriver({
projectId: process.env.GCP_PROJECT_ID!,
bucketName: process.env.GCP_BUCKET_NAME!,
});
express()
.use(
organizationService(
{
organizations: client.collection('organizations'),
identities: client.collection('identities'),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
organization: {
roles: {
admin: '100',
member: '001',
owner: '010',
},
},
},
{ fileStorageDriver }
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));
📋 エンドポイント概要
基本CRUD操作
メソッド | パス | 説明 | 認可 |
---|---|---|---|
POST | /organizations | 新しい組織を作成 | ベアラートークン必須(管理者のみ) |
GET | /organizations/:organizationId | IDで組織を取得 | ベアラートークン必須(管理者/組織アクセス) |
GET | /organizations | 組織を一覧/フィルタ | ベアラートークン必須(管理者のみ) |
PATCH | /organizations/:organizationId | 組織を更新 | ベアラートークン必須(管理者/所有者アクセス) |
DELETE | /organizations/:organizationId | 組織を削除 | ベアラートークン必須(管理者/所有者アクセス) |
ファイルアップロード操作
メソッド | パス | 説明 | 認可 |
---|---|---|---|
GET | /organizations/:organizationId/logo-upload-url | 組織ロゴアップロード用の署名付きURLを取得 | ベアラートークン必須(管理者/所有者アクセス) |
階層操作
メソッド | パス | 説明 | 認可 |
---|---|---|---|
GET | /organizations/:organizationId/descendants | 子孫組織を一覧(オプションの深さ制限) | ベアラートークン必須(管理者/所有者アクセス) |
ユーザ管理操作
メソッド | パス | 説明 | 認可 |
---|---|---|---|
GET | /organizations/:organizationId/members | 組織のメンバーを一覧 | ベアラートークン必須(管理者/組織アクセス) |
PATCH | /organizations/:organizationId/members | 組織にメンバーを追加/更新 | ベアラートークン必須(管理者/組織アクセス) |
DELETE | /organizations/:organizationId/members/:identityId | 組織からメンバーを削除 | ベアラートークン必須(管理者/組織アクセス) |
GET | /organizations/:organizationId/members/:identityId/role | 組織内のメンバーの役割を取得 | ベアラートークン必須(管理者/組織アクセス) |
GET | /organizations/members/:identityId | メンバーの所属組織を検索 | ベアラートークン必須(管理者/自己アクセス) |
🗄️ エンティティスキーマ
組織エンティティは、自動生成されるベースフィールドと組織固有のデータで構成されます:
{
"id": "string",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)",
"name": "string",
"description": "string",
"contact_email": "string",
"contact_phone": "string",
"address": "object",
"logo": "object or null",
"users": "array"
}
フィールド詳細
フィールド | 型 | 自動生成 | 必須 | 説明 |
---|---|---|---|---|
id | string | ✅ | ✅ | 一意識別子(UUID) |
createdAt | datetime | ✅ | ✅ | 作成日時 |
updatedAt | datetime | ✅ | ✅ | 最終更新日時 |
name | string | ❌ | ✅ | 組織名(最小1文字) |
description | string | ❌ | ✅ | 組織説明 |
contact_email | string | ❌ | ✅ | 連絡先メールアドレス(メール形式) |
contact_phone | string | ❌ | ❌ | 連絡先電話番号 |
address | object | ❌ | ❌ | アドレスオブジェクト(自由形式JSON) |
logo | object or null | ❌ | ❌ | 組織ロゴ。レスポンス: { type, url } ; リクエスト: { objectId, type } |
users | array | ❌ | ❌ | 役割付きのアイデンティティ配列({id: string, role: string} ) |
📝 注意: 自動生成フィールドはサービス側で設定され、作成/更新リクエストに含めないでください。
🔐 認証ヘッダー
すべてのエンドポイントで、次のヘッダーを含めてください:
Authorization: Bearer <access_token>
x-nb-fingerprint: <device_fingerprint>
⚠️ 重要: 認可時にフィンガープリントを指定した場合、認証済みのすべてのリクエストで
x-nb-fingerprint
ヘッダーが必須です。欠如している場合は 401 Unauthorized が返ります。
🔧 APIエンドポイント
1. 組織作成
提供された情報で新しい組織を作成します。
リクエスト:
- メソッド:
POST
- パス:
/organizations
- ヘッダー:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者のみ)
リクエストボディ(トップレベル):
フィールド | 型 | 必須 | 説明 |
---|---|---|---|
organization | object | ✅ | 組織ペイロードオブジェクト(下記参照) |
ownerId | string | ✅ | 組織所有者のアイデンティティID |
parentId | string | ❌ | オプションの親組織ID |
組織オブジェクトフィールド:
フィールド | 型 | 必須 | 説明 |
---|---|---|---|
name | string | ✅ | 組織名(最小1文字) |
description | string | ✅ | 組織説明 |
contact_email | string | ✅ | 連絡先メールアドレス(メール形式) |
contact_phone | string | ❌ | 連絡先電話番号 |
address | object | ❌ | アドレスオブジェクト(自由形式JSON) |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
id | string | 一意の組織識別子 |
name | string | 組織名 |
description | string | 組織説明 |
contact_email | string | 連絡先メールアドレス |
contact_phone | string | 連絡先電話番号 |
address | object | アドレスオブジェクト(自由形式JSON) |
users | array | ユーザーIDと役割を含むオブジェクトの配列: {id: string, role: string} |
createdAt | string | 作成日時 |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: 自動強制(トップレベルの
organization
とownerId
必須;organization
内でname
、description
、contact_email
必須; additionalProperties: false) - ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロール必須
リクエスト例:
curl -X POST {{host}}/organizations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"organization": {
"name": "ACME Corp",
"description": "Leading provider of rocket skates",
"contact_email": "info@acme.test",
"contact_phone": "+1-202-555-0199",
"address": {
"street": "1 Road Runner Way",
"city": "Desert",
"country": "US"
}
},
"ownerId": "identity-123",
"parentId": "org-parent-001"
}'
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "ACME Corp",
"description": "Leading provider of rocket skates",
"contact_email": "info@acme.test",
"contact_phone": "+1-202-555-0199",
"address": {
"street": "1 Road Runner Way",
"city": "Desert",
"country": "US"
},
"users": [
{
"id": "owner-id",
"role": "owner"
}
],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}
エラーレスポンス:
リクエストボディに必須フィールドがない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'name'",
"request body must have required property 'description'",
"request body must have required property 'contact_email'",
"request body must have required property 'ownerId'"
]
}
}
認可トークンが提供されていない場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "token could not be verified"
}
}
データベース挿入操作が挿入されたIDを返せなかった場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Failed to create organization"
}
}
予期しないエラーが発生した場合(DB接続問題など):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to create organization"
}
}
2. IDで組織取得
一意のIDで特定の組織を取得します。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
id | string | 一意の組織識別子 |
name | string | 組織名 |
description | string | 組織説明 |
contact_email | string | 連絡先メールアドレス |
contact_phone | string | 連絡先電話番号 |
address | object | アドレスオブジェクト(自由形式JSON) |
users | array | ユーザーIDと役割を含むオブジェクトの配列: {id: string, role: string} |
createdAt | string | 作成日時 |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: なし
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織メンバーシップ必須(所有者/管理者/メンバー)
リクエスト例:
curl {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "ACME Corp",
"description": "Leading provider of rocket skates",
"contact_email": "info@acme.test",
"contact_phone": "+1-202-555-0199",
"address": {
"street": "1 Road Runner Way",
"city": "Desert",
"country": "US"
},
"users": [
{
"id": "owner-id",
"role": "owner"
}
],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}
エラーレスポンス:
指定IDの組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
予期しないエラーが発生した場合(DB接続問題など):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to get organization"
}
}
3. 組織一覧
フィルタやページングを指定して組織の一覧を取得します。
リクエスト:
- メソッド:
GET
- パス:
/organizations
- 認可: ベアラートークン必須(管理者のみ)
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
name | string | ❌ | 組織名でフィルタ(最小1文字) |
description | string | ❌ | 組織説明でフィルタ |
contact_email | string | ❌ | 連絡先メールアドレスでフィルタ(メール形式) |
contact_phone | string | ❌ | 連絡先電話番号でフィルタ |
page | number | ❌ | ページ番号 |
limit | number | ❌ | 1ページあたりの件数 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
id | string | 一意の組織識別子 |
name | string | 組織名 |
description | string | 組織説明 |
contact_email | string | 連絡先メールアドレス |
contact_phone | string | 連絡先電話番号 |
address | object | アドレスオブジェクト(自由形式JSON) |
users | array | ユーザーIDと役割を含むオブジェクトの配列: {id: string, role: string} |
createdAt | string | 作成日時 |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: name(最小長1)、contact_email(メール形式)、contact_phone(string)、description(string)、ページングパラメータ(最小/最大制約のある整数)のクエリ検証
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロール必須
リクエスト例:
全件取得:
curl {{host}}/organizations
組織名でフィルタ:
curl "{{host}}/organizations?name=ACME Corp"
連絡先メールアドレスでフィルタ:
curl "{{host}}/organizations?contact_email=info@acme.test"
組織説明でフィルタ:
curl "{{host}}/organizations?description=rocket skates"
連絡先電話番号でフィルタ:
curl "{{host}}/organizations?contact_phone=+1-202-555-0199"
複合フィルタ:
curl "{{host}}/organizations?name=ACME&contact_email=info@acme.test&page=1&limit=20"
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "ACME Corp",
"description": "Leading provider of rocket skates",
"contact_email": "info@acme.test",
"contact_phone": "+1-202-555-0199",
"address": {
"street": "1 Road Runner Way",
"city": "Desert",
"country": "US"
},
"users": [
{
"id": "owner-id",
"role": "owner"
}
],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
},
{
"id": "8fec096b-1bc7-5bfe-c827-3600e8fe2790",
"name": "Wayne Enterprises",
"description": "Gotham's premier technology company",
"contact_email": "contact@wayneenterprises.com",
"users": [
{
"id": "owner-id",
"role": "owner"
}
],
"createdAt": "2024-05-29T10:15:33.441Z",
"updatedAt": "2024-05-29T10:15:33.441Z"
}
]
エラーレスポンス:
予期しないエラーが発生した場合(DB接続問題、フィルタ構文不正など):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to find organizations"
}
}
4. 組織更新
部分更新で既存の組織を更新します。
リクエスト:
- メソッド:
PATCH
- パス:
/organizations/:organizationId
- ヘッダー:
Content-Type: application/json
- 認可: ベアラートークン必須(管理者/所有者アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
id | string | 一意の組織識別子 |
name | string | 更新後の組織名 |
description | string | 更新後の組織説明 |
contact_email | string | 更新後の連絡先メールアドレス |
contact_phone | string | 更新後の連絡先電話番号 |
address | object | 更新後のアドレスオブジェクト(自由形式JSON) |
createdAt | string | 作成日時 |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: 自動強制(部分更新、全フィールド任意)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者ロール必須
リクエスト例:
curl -X PATCH {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Content-Type: application/json" \
-d '{"description": "Updated description for ACME Corp"}'
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "ACME Corp",
"description": "Updated description for ACME Corp",
"contact_email": "info@acme.test",
"contact_phone": "+1-202-555-0199",
"address": {
"street": "1 Road Runner Way",
"city": "Desert",
"country": "US"
},
"users": [
{
"id": "owner-id",
"role": "owner"
}
],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T14:22:15.789Z"
}
エラーレスポンス:
リクエストボディがないまたは空の場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Request body is required"
}
}
指定IDの組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
更新操作でデータが変更されない場合(変更なし):
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Failed to update organization"
}
}
予期しないエラーが発生した場合(DB接続問題など):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to update organization"
}
}
5. 組織削除
システムから組織を完全に削除します。
リクエスト:
- メソッド:
DELETE
- パス:
/organizations/:organizationId
- 認可: ベアラートークン必須(管理者/所有者アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
なし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: なし
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者ロール必須
リクエスト例:
curl -X DELETE {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2
成功レスポンス:
HTTP/1.1 204 No Content
エラーレスポンス:
指定IDの組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
予期しないエラーが発生した場合(DB接続問題など):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to delete organization"
}
}
👥 ユーザ管理エンドポイント
6. 組織メンバーの一覧
組織に関連付けられたユーザーの一覧を取得します。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId/members
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
バリデーション:
- スキーマ検証: なし(GET リクエスト)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/members
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"count": 2,
"total": 2,
"value": [
{
"id": "identity-123",
"role": "admin"
},
{
"id": "392157b1-dc7a-4935-a6f9-a2d333b910ea",
"role": "owner"
}
]
}
7. 組織メンバーの追加/更新
組織に新しいユーザーを追加するか、既存のユーザーロールを更新します。upsertロジックを使用 - ユーザーが存在する場合ロールを更新、存在しない場合は追加します。
リクエスト:
- メソッド:
PATCH
- パス:
/organizations/:organizationId/members
- ヘッダー:
Content-Type: application/json
,Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
リクエストボディ: 追加/更新するメンバーオブジェクトの配列:
フィールド | 型 | 必須 | 説明 |
---|---|---|---|
id | string | ✅ | アイデンティティ識別子 |
role | string | ✅ | 組織内のメンバーロール |
バリデーション:
- スキーマ検証: 自動強制(必須のidおよびroleフィールドを含む配列)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl -X PATCH {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/members \
-H "Content-Type: application/json" \
-d '[
{"id": "user123", "role": "admin"},
{"id": "user456", "role": "member"}
]'
成功レスポンス:
HTTP/1.1 204 No Content
エラーレスポンス:
リクエストボディがないまたは空の場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Request body non-empty array required"
}
}
組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
データベース操作が失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to upsert organization users"
}
}
8. 組織からのメンバー削除
組織から特定のユーザーを削除します。
リクエスト:
- メソッド:
DELETE
- パス:
/organizations/:organizationId/members/:identityId
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
identityId | string | ✅ | 一意のアイデンティティ識別子 |
バリデーション:
- スキーマ検証: なし(DELETE リクエスト)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl -X DELETE {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/members/identity-123
成功レスポンス:
HTTP/1.1 204 No Content
エラーレスポンス:
組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
ユーザーが組織にいない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Failed to remove user from organization"
}
}
データベース操作が失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to delete organization user"
}
}
9. 組織内のメンバー役割取得
組織内の特定のユーザーの役割を取得します。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId/members/:identityId/role
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
identityId | string | ✅ | 一意のアイデンティティ識別子 |
バリデーション:
- スキーマ検証: パスパラメータ検証(organizationId、identityId必須)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl {{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/members/identity-123/role
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"inheritedFrom": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2" ,
"role": "owner"
}
エラーレスポンス:
組織またはユーザーが存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
データベース操作が失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to get organization user role"
}
}
10. 組織内のメンバー存在確認
組織内に特定のユーザーが存在するかどうかを確認します。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId/members/check-existence
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/組織アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 一意の組織識別子 |
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
identityId | string | ✅ | 確認する一意のアイデンティティ識別子 |
バリデーション:
- スキーマ検証: なし(GET リクエスト)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/members/check-existence?identityId=identity-123"
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"isUserInOrganization": true
}
エラーレスポンス:
組織が存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Organization not found"
}
}
データベース操作が失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to check organization user existence"
}
}
11. メンバーの所属組織検索
特定のアイデンティティが所属するすべての組織を取得します。オプションで要求された場合、継承された役割も含みます。
リクエスト:
- メソッド:
GET
- パス:
/organizations/members/:identityId
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/自己アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
identityId | string | ✅ | 一意のアイデンティティ識別子 |
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
roles | string | ❌ | オプションのカンマ区切り役割フィルタ(例: owner,admin) |
includeInherited | boolean | ❌ | 子孫組織からの継承された役割を含む |
バリデーション:
- スキーマ検証: パスパラメータ検証(identityId必須)とオプションのクエリ検証(rolesはstring; includeInheritedはboolean)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは自己必須
リクエスト例:
curl {{host}}/organizations/members/identity-123
成功レスポンス:
[
{
"member": { "inheritedFrom": null, "role": "owner" },
"organization": {
"id": "org1",
"name": "ACME Corp",
"ancestors": [],
"members": [{ "identityId": "identity-123", "role": "owner" }]
}
},
{
"member": { "inheritedFrom": "org1", "role": "owner" },
"organization": {
"id": "org2",
"ancestors": ["org1"],
"members": [{ "identityId": "identity-123", "role": "member" }]
}
}
]
ユーザーが存在しない場合:
HTTP/1.1 200 OK
Content-Type: application/json
{
"count": 0,
"total": 0,
"value": []
}
12. 組織ロゴアップロードURL取得
組織ロゴ画像を安全にアップロードするための署名付きURLを生成します。オブジェクトIDと一時的な署名付きURLを返します。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId/logo-upload-url
- ヘッダー:
Authorization: Bearer <token>
- 認可: ベアラートークン必須(管理者/所有者アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 対象組織ID |
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
contentType | string | ✅ | 画像MIMEタイプ(例: image/png ) |
contentLength | number | ✅ | ファイルサイズ(バイト単位、最大10MB) |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
objectId | string | ロゴ用の生成されたストレージオブジェクトID |
url | string | ファイルをアップロードするための署名付きURL |
バリデーション:
- スキーマ検証: 画像アップロードスキーマを使用(コンテンツタイプとサイズ制約)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者ロール必須
リクエスト例:
curl "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/logo-upload-url?contentType=image/png&contentLength=1048576" \
-H "Authorization: Bearer <access-token>"
成功レスポンス:
{
"objectId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"url": "https://storage.googleapis.com/bucket/logos/...&X-Goog-Expires=900&X-Goog-Signature=..."
}
13. 子孫組織一覧
指定された組織の子孫組織をすべて取得します。オプションで深さ制限を指定できます。
リクエスト:
- メソッド:
GET
- パス:
/organizations/:organizationId/descendants
- ヘッダー:
Authorization: Bearer <access-token>
- 認可: ベアラートークン必須(管理者/所有者アクセス)
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
organizationId | string | ✅ | 親組織識別子 |
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
depth | number (>=1) | ❌ | 階層深さで子孫を制限 |
バリデーション:
- スキーマ検証: パスパラメータ検証(organizationId必須); depthは提供された場合正の数である必要があります
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロールまたは組織所有者/管理者ロール必須
リクエスト例:
curl "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/descendants?depth=2" \
-H "Authorization: Bearer <access-token>"
成功レスポンス:
[
{
"id": "9044d797-384e-4c60-a3b6-1d900ffd8be8",
"name": "ACME Corp",
"description": "Leading provider of rocket skates",
"contact_email": "info@acme.test",
"createdAt": "2025-08-25T07:42:18.643Z",
"updatedAt": "2025-08-25T07:42:18.643Z"
}
]
⚙️ 設定オプション
サービス設定
interface OrganizationServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT 暗号化シークレット
authSignSecret: string; // JWT 署名シークレット
};
identity?: {
typeIds?: {
admin: string; // 管理者ユーザー種別識別子
guest: string; // ゲストユーザー種別識別子
regular: string; // 一般ユーザー種別識別子
};
};
organization?: {
roles?: {
admin: string; // 管理者役割識別子
member: string; // メンバー役割識別子
owner: string; // 所有者役割識別子
};
};
}
設定詳細
組織サービスの設定は、セキュリティ、ユーザー種別管理、組織役割管理の論理グループに整理されています。
🔐 セキュリティ設定
authSecrets
- JWT トークンのセキュリティシークレット
- 型:
{ authEncSecret: string; authSignSecret: string }
- 説明: JWT の暗号化および署名に使用する秘密鍵(トークン検証に使用)
- 必須: 本番環境では必須
- 子プロパティ:
authEncSecret
: JWT ペイロード暗号化の秘密鍵authSignSecret
: JWT 署名検証の秘密鍵
👥 ユーザー種別設定
user.typeIds
- ユーザー種別識別子の設定
- 型:
{ admin?: string; guest?: string; user?: string }
- 説明: ロールベースアクセス制御のためのカスタムユーザー種別識別子
- デフォルト:
undefined
(デフォルトの種別検証を使用) - 子プロパティ:
admin
: 管理者ユーザー種別の識別子- 型:
string
- 説明: 管理者ユーザーのカスタム識別子
- 利用例: 管理操作のロールベースアクセス制御
- 例:
"admin"
,"administrator"
,"superuser"
- 型:
guest
: ゲストユーザー種別の識別子- 型:
string
- 説明: ゲストユーザーのカスタム識別子
- 利用例: 未認証/一時ユーザーの限定的アクセス
- 例:
"guest"
,"visitor"
,"anonymous"
- 型:
user
: 一般ユーザー種別の識別子- 型:
string
- 説明: 一般ユーザーのカスタム識別子
- 利用例: 標準的なユーザー権限
- 例:
"user"
,"member"
,"customer"
- 型:
🏢 組織役割設定
organization.roles
- 組織役割識別子の設定
- 型:
{ admin?: string; member?: string; owner?: string }
- 説明: 組織内ユーザー管理のためのカスタム組織役割識別子
- デフォルト:
undefined
(デフォルトの役割検証を使用) - 子プロパティ:
admin
: 管理者役割識別子- 型:
string
- 説明: 組織管理者役割のカスタム識別子
- 利用例: 組織内の管理権限
- 例:
"admin"
,"administrator"
,"manager"
- 型:
member
: メンバー役割識別子- 型:
string
- 説明: 組織メンバー役割のカスタム識別子
- 利用例: 組織内の標準的なメンバー権限
- 例:
"member"
,"user"
,"employee"
- 型:
owner
: 所有者役割識別子- 型:
string
- 説明: 組織所有者役割のカスタム識別子
- 利用例: 組織内の完全制御権限
- 例:
"owner"
,"founder"
,"creator"
- 型:
設定例
const organizationConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
user: {
typeIds: {
admin: '100',
guest: '000',
user: '001'
}
},
organization: {
roles: {
admin: '100',
member: '001',
owner: '010'
}
}
};
🚨 エラーハンドリング
組織サービスのエラーは、適切なHTTPステータスコードとJSON形式で返されます:
代表的なエラーコード
ステータス | エラーメッセージ | 説明 |
---|---|---|
400 | Validation Error | リクエストボディ形式が無効または必須フィールドがない |
400 | Request body is required | PATCH操作のリクエストボディがない |
400 | Request body non-empty array required | ユーザー管理操作の配列がないまたは空 |
400 | Failed to create organization | データベース挿入操作が挿入されたIDを返せなかった |
400 | Failed to update organization | 更新操作でデータが変更されない(変更なし) |
400 | Failed to remove user from organization | ユーザーが組織にいないまたは削除が失敗した |
401 | token could not be verified | 認可トークンがない/無効 |
403 | User is not authorized to access this resource | 必要な権限がない(管理者/組織アクセス) |
404 | Organization not found | 要求された操作の対象組織が存在しない |
500 | Failed to create organization | 作成中のDB接続問題/予期せぬ失敗 |
500 | Failed to get organization | 取得中のDB接続問題/予期せぬ失敗 |
500 | Failed to find organizations | 一覧取得中のDB接続問題/フィルタ構文不正/予期せぬ失敗 |
500 | Failed to update organization | 更新中のDB接続問題/予期せぬ失敗 |
500 | Failed to delete organization | 削除中のDB接続問題/予期せぬ失敗 |
500 | Failed to upsert organization users | ユーザー管理中のDB接続問題/予期せぬ失敗 |
500 | Failed to delete organization user | ユーザー削除中のDB接続問題/予期せぬ失敗 |
500 | Failed to get organization user role | 役割取得中のDB接続問題/予期せぬ失敗 |
500 | Failed to check organization user existence | 存在確認中のDB接続問題/予期せぬ失敗 |
500 | Cannot read properties of undefined (reading 'organizations') | ユーザー組織検索エンドポイントのハンドラー実装バグ |
エラーレスポンス形式
{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}
検証エラーには追加の詳細が含まれます:
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'name'",
"request body must have required property 'description'",
"request body must have required property 'contact_email'",
"request body must have required property 'ownerId'"
]
}
}
🔗 関連ドキュメント
- ユーザーサービス - ユーザー管理操作
- 認証サービス - 認証および認可
- エラーハンドリング - エラーパターンの理解
- スキーマコンポーネント - データ検証の概念
- カスタムサービステュートリアル - 独自サービスの構築