メインコンテンツまでスキップ
バージョン: 0.9.0 (最新)

🏢 組織サービス

Testing Status

Organization Serviceは、CRUD操作を備えた組織エンティティを管理するための完全なREST APIを提供します。Nodeblocksの関数型コンポジションアプローチを使用して構築され、MongoDBとシームレスに統合されています。


🚀 クイックスタート

import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';

const { nodeBlocksErrorMiddleware } = middlewares;
const { organizationService } = services;
const { withMongo, createFileStorageDriver } = drivers;

const connectToDatabase = withMongo('mongodb://localhost:27017', 'dev', 'user', 'password');

// オプションですが、ロゴの正規化とアップロードURLには推奨:
// GOOGLE_APPLICATION_CREDENTIALSがGCPサービスアカウントJSONを指していることを確認してください。
const fileStorageDriver = createFileStorageDriver({
projectId: process.env.GCP_PROJECT_ID!,
bucketName: process.env.GCP_BUCKET_NAME!,
});

express()
.use(
organizationService(
{
...(await connectToDatabase('organizations')),
...(await connectToDatabase('identities')),
...(await connectToDatabase('users')), // 必須: 組織フォロワー機能用
...(await connectToDatabase('organizationChangeRequests')), // オプション: 変更リクエスト管理用
},
{
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操作

MethodPath説明認証が必要
POST/organizations新しい組織を作成✅ 管理者のみ
GET/organizations/:organizationIdIDで組織を取得✅ 管理者/組織アクセス
GET/organizations組織をリスト/フィルタ✅ 管理者のみ
PATCH/organizations/:organizationId組織を更新✅ 管理者/所有者アクセス
DELETE/organizations/:organizationId組織を削除✅ 管理者/所有者アクセス

ファイルアップロード操作

MethodPath説明認証が必要
GET/organizations/:organizationId/logo-upload-url組織ロゴをアップロードするための署名付きURLを取得✅ 管理者/所有者アクセス
GET/organizations/:organizationId/certificate-upload-url組織証明書をアップロードするための署名付きURLを取得✅ 管理者/所有者アクセス

変更リクエスト操作

MethodPath説明認証が必要
POST/organizations/:organizationId/change-requests証明書と資格情報を含む組織変更リクエストを作成✅ 管理者/所有者アクセス
GET/organizations/:organizationId/change-requestsページネーション付きで組織変更リクエストをリスト✅ 管理者/所有者アクセス

管理者操作

MethodPath説明認証が必要
PATCH/admin/organizations/:organizationId/監査ステータスを含む拡張管理者専用フィールドで組織を更新✅ 管理者のみ

階層操作

MethodPath説明認証が必要
GET/organizations/:organizationId/descendants子孫組織をリスト(オプションの深さ)✅ 管理者/所有者アクセス

ユーザー管理操作

MethodPath説明認証が必要
GET/organizations/:organizationId/members組織のメンバーをリスト✅ 管理者/組織アクセス
PATCH/organizations/:organizationId/members組織にメンバーを追加/更新✅ 管理者/組織アクセス
DELETE/organizations/:organizationId/members/:identityId組織からメンバーを削除✅ 管理者/組織アクセス
GET/organizations/:organizationId/members/:identityId/role組織内のメンバーのロールを取得✅ 管理者/組織アクセス
GET/organizations/members/:identityIdメンバーの組織を検索✅ 管理者/自己アクセス

組織フォロワー操作

MethodPath説明認証が必要
GET/organizations/:organizationId/followers組織フォロワーのページネーション付きリストを取得✅ 管理者/所有者アクセス

🗄️ エンティティスキーマ

組織エンティティは、基本フィールド(自動生成)と組織固有のデータを組み合わせます:

{
"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"
}

フィールド詳細

FieldType自動生成必須説明
idstring一意の識別子(UUID)
createdAtdatetime作成タイムスタンプ
updatedAtdatetime最終更新タイムスタンプ
namestring組織名(最小1文字)
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス(メール形式)
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
logoobject or null組織ロゴ。レスポンス: { type, url }; リクエスト: { objectId, type }
usersarrayロール付きアイデンティティの配列({id: string, role: string}

📝 注記: 自動生成フィールドはサービスによって設定され、作成/更新リクエストに含めるべきではありません。


🔐 認証ヘッダー

すべてのエンドポイントで、次のヘッダーを含めてください:

Authorization: Bearer <access_token>
x-nb-fingerprint: <device_fingerprint>

⚠️ 重要: x-nb-fingerprintヘッダーは、認証時にフィンガープリントが指定された場合、すべての認証済みリクエストで必須です。これがない場合、リクエストは401 Unauthorizedを返します。


🔧 APIエンドポイント

1. 組織の作成

提供された情報で新しい組織を作成します。

リクエスト:

  • Method: POST
  • Path: /organizations
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要(管理者のみ)

リクエストボディ(トップレベル):

FieldType必須説明
organizationobject組織ペイロードオブジェクト(以下を参照)
ownerIdstring組織所有者のアイデンティティID
parentIdstringオプションの親組織ID

組織オブジェクトフィールド:

FieldType必須説明
namestring組織名(最小1文字)
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス(メール形式)
branchNamestring組織の支店名
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
logoobject | nullロゴ参照({ objectId: string, type: string })またはnull
certificateImageobject証明書画像参照({ objectId: string, type: string }
certifiedQualificationsarray資格オブジェクトの配列({ name: string, status: string, value: string }
typeIdstring組織タイプID

レスポンスボディ:

FieldType説明
idstring一意の組織識別子
namestring組織名
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
usersarrayユーザーIDとロールを含むオブジェクトの配列: {id: string, role: string}
createdAtstring作成タイムスタンプ
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: 自動的に強制されます(トップレベルのorganizationownerId必須;organization内でnamedescriptioncontact_email必須;additionalProperties: false)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールが必要

リクエスト例:

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"
}
}

予期しないエラーが発生した場合(データベース接続の問題など):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to create organization"
}
}

2. IDで組織を取得

一意のIDで特定の組織を取得します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

レスポンスボディ:

FieldType説明
idstring一意の組織識別子
namestring組織名
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
usersarrayユーザーIDとロールを含むオブジェクトの配列: {id: string, role: string}
createdAtstring作成タイムスタンプ
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: なし
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織メンバーシップ(所有者/管理者/メンバー)が必要

リクエスト例:

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"
}
}

予期しないエラーが発生した場合(データベース接続の問題など):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to get organization"
}
}

3. 組織のリスト取得

オプションのフィルタリングとページネーションで組織のリストを取得します。

リクエスト:

  • Method: GET
  • Path: /organizations
  • Authorization: Bearerトークンが必要(管理者のみ)

クエリパラメータ:

ParameterType必須説明
namestring名前で組織をフィルタ(最小1文字)
descriptionstring説明で組織をフィルタ
contact_emailstring連絡先メールで組織をフィルタ(メール形式)
contact_phonestring連絡先電話で組織をフィルタ
pagenumberページ番号(1-1000)
limitnumberページあたりの項目数(1-50)

レスポンスボディ:

FieldType説明
idstring一意の組織識別子
namestring組織名
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
usersarrayユーザーIDとロールを含むオブジェクトの配列: {id: string, role: string}
createdAtstring作成タイムスタンプ
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: name(最小長1)、contact_email(メール形式)、contact_phone(文字列)、description(文字列)、ページネーションパラメータ(最小/最大制約付き整数)のクエリパラメータバリデーション
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールが必要

リクエスト例:

すべての組織をリスト:

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"
}
]

エラーレスポンス:

予期しないエラーが発生した場合(データベース接続の問題、無効なフィルタ構文など):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to find organizations"
}
}

4. 組織の更新

部分的なデータで既存の組織を更新します。

リクエスト:

  • Method: PATCH
  • Path: /organizations/:organizationId
  • Headers: Content-Type: application/json
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

リクエストボディ(すべてのフィールドはオプション):

FieldType必須説明
branchNamestring組織の支店名
contact_emailstring連絡先メールアドレス(メール形式)
contact_phonestring連絡先電話番号
descriptionstring組織の説明

レスポンスボディ:

FieldType説明
idstring一意の組織識別子
namestring組織名
descriptionstring更新された組織の説明
contact_emailstring更新された連絡先メールアドレス
contact_phonestring更新された連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
createdAtstring作成タイムスタンプ
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: 自動的に強制されます(部分更新、すべてのフィールドはオプション: branchName、contact_email、contact_phone、description)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

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"
}
}

予期しないエラーが発生した場合(データベース接続の問題など):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to update organization"
}
}

5. 組織の削除

システムから組織を永続的に削除します。

リクエスト:

  • Method: DELETE
  • Path: /organizations/:organizationId
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

レスポンスボディ:

FieldType説明
レスポンスボディなし-削除エンドポイントは成功時にレスポンスボディを返しません

バリデーション:

  • スキーマバリデーション: なし
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

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"
}
}

予期しないエラーが発生した場合(データベース接続の問題など):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to delete organization"
}
}

👥 ユーザー管理エンドポイント

6. 組織メンバーのリスト取得

組織に関連付けられたユーザーのリストを取得します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/members
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

バリデーション:

  • スキーマバリデーション: なし(GETリクエスト)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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. 組織メンバーの追加/更新

組織に新しいユーザーを追加するか、既存のユーザーロールを更新します。アップサートロジックを使用 - ユーザーが存在する場合、ロールを更新;存在しない場合、追加します。

リクエスト:

  • Method: PATCH
  • Path: /organizations/:organizationId/members
  • Headers: Content-Type: application/json, Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

リクエストボディ: 追加/更新するメンバーオブジェクトの配列:

FieldType必須説明
idstringアイデンティティ識別子
rolestring組織内のメンバーロール

バリデーション:

  • スキーマバリデーション: 自動的に強制されます(必須のidとroleフィールドを持つ配列)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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. 組織からメンバーを削除

組織から特定のユーザーを削除します。

リクエスト:

  • Method: DELETE
  • Path: /organizations/:organizationId/members/:identityId
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子
identityIdstring一意のアイデンティティ識別子

バリデーション:

  • スキーマバリデーション: なし(DELETEリクエスト)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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. 組織内のメンバーロールを取得

組織内の特定のユーザーのロールを取得します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/members/:identityId/role
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子
identityIdstring一意のアイデンティティ識別子

バリデーション:

  • スキーマバリデーション: パスパラメータバリデーション(organizationId、identityId必須)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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. 組織内のメンバー存在確認

特定のユーザーが組織内に存在するかどうかを確認します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/members/check-existence
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/組織アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

クエリパラメータ:

ParameterType必須説明
identityIdstring確認する一意のアイデンティティ識別子

バリデーション:

  • スキーマバリデーション: なし(GETリクエスト)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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. メンバーの組織を検索

特定のアイデンティティが所属するすべての組織を取得します。リクエスト時にオプションで継承されたロールを含みます。

リクエスト:

  • Method: GET
  • Path: /organizations/members/:identityId
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/自己アクセス)

URLパラメータ:

ParameterType必須説明
identityIdstring一意のアイデンティティ識別子

クエリパラメータ:

ParameterType必須説明
rolesstringオプションのカンマ区切りロールフィルタ(例: owner,admin)
includeInheritedboolean子孫組織からの継承されたロールを含める

バリデーション:

  • スキーマバリデーション: パスパラメータバリデーション(identityId必須)とオプションのクエリバリデーション(rolesは文字列;includeInheritedはブール値)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは自己が必要

リクエスト例:

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を返します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/logo-upload-url
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring対象組織ID

クエリパラメータ:

ParameterType必須説明
contentTypestring画像MIMEタイプ(例: image/png
contentLengthnumberファイルサイズ(バイト単位、最大10MB)

レスポンスボディ:

FieldType説明
objectIdstringロゴ用に生成されたストレージオブジェクトID
urlstringファイルをアップロードするための事前署名付きURL

バリデーション:

  • スキーマバリデーション: 画像アップロードスキーマを使用(コンテンツタイプとサイズ制約)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

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. 組織証明書アップロードURLを取得

組織証明書ファイルを安全にアップロードするための事前署名付きURLを生成します。オブジェクトIDと一時的な署名付きURLを返します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/certificate-upload-url
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring対象組織ID

クエリパラメータ:

ParameterType必須説明
contentTypestring証明書MIMEタイプ(application/pdfimage/gifimage/jpegimage/png
contentLengthnumberファイルサイズ(バイト単位、最大10MB)

レスポンスボディ:

FieldType説明
objectIdstring証明書用に生成されたストレージオブジェクトID
urlstringファイルをアップロードするための事前署名付きURL

バリデーション:

  • スキーマバリデーション: 証明書アップロードスキーマ(コンテンツタイプ列挙型とサイズ制約)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

curl "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/certificate-upload-url?contentType=application/pdf&contentLength=1048576" \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

{
"objectId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"url": "https://storage.googleapis.com/bucket/certificates/...&X-Goog-Expires=900&X-Goog-Signature=..."
}

14. 組織変更リクエストを作成

証明書と資格情報を含む新しい組織変更リクエストを作成します。組織の保留中の変更ステータスを更新します。

リクエスト:

  • Method: POST
  • Path: /organizations/:organizationId/change-requests
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring組織識別子

リクエストボディ(少なくとも1つのフィールドが必要):

FieldType必須説明
namestring組織名(最小1文字)
branchNamestring組織の支店名
addressLine1string住所1行目
addressLine2string住所2行目
addressLine3string住所3行目
postalCodestring郵便番号
typeIdstring組織タイプID
certificateImageobject証明書画像参照({ objectId: string, type: string }
certifiedQualificationsarray資格オブジェクトの配列({ name: string, status: string, value: string }

レスポンスボディ: レスポンスボディなし(204 No Content)

バリデーション:

  • スキーマバリデーション: リクエストボディには少なくとも1つのプロパティが必要
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

curl -X POST "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/change-requests" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"name": "Updated Organization Name",
"certificateImage": {
"objectId": "cert-123",
"type": "application/pdf"
},
"certifiedQualifications": [
{
"name": "ISO 9001",
"status": "certified",
"value": "2024"
}
]
}'

成功レスポンス:

HTTP/1.1 204 No Content

15. 組織変更リクエストをリスト

特定の組織の変更リクエストのページネーション付きリストを取得します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/change-requests
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring組織識別子

クエリパラメータ:

ParameterType必須説明
pagenumberページ番号(1-1000)
limitnumberページあたりの項目数(1-50)

レスポンスボディ: 変更リクエスト配列とメタデータを含むページネーション付きレスポンス。

レスポンス構造:

{
"data": [
{
"id": "string",
"organizationId": "string",
"requesterId": "string",
"name": "string",
"certificateImage": {
"url": "string",
"type": "string"
},
"certifiedQualifications": [
{
"name": "string",
"status": "string",
"value": "string"
}
],
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}

バリデーション:

  • スキーマバリデーション: パスパラメータバリデーションとページネーションクエリパラメータ
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者ロールが必要

リクエスト例:

curl "{{host}}/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/change-requests?page=1&limit=20" \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"data": [
{
"id": "change-request-123",
"organizationId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"requesterId": "identity-456",
"name": "Updated Organization Name",
"certificateImage": {
"url": "https://storage.googleapis.com/...",
"type": "application/pdf"
},
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}

16. 管理者として組織を更新

監査ステータス、証明書画像、認定資格を含む拡張管理者専用フィールドで組織を更新します。

リクエスト:

  • Method: PATCH
  • Path: /admin/organizations/:organizationId/
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者のみ)

URLパラメータ:

ParameterType必須説明
organizationIdstring一意の組織識別子

リクエストボディ(すべてのフィールドはオプション):

FieldType必須説明
namestring組織名(最小1文字)
branchNamestring組織の支店名
descriptionstring組織の説明
contact_emailstring連絡先メールアドレス(メール形式)
contact_phonestring連絡先電話番号
addressobjectアドレスオブジェクト(自由形式のJSON)
typeIdstring組織タイプID
logoobject | nullロゴ参照({ objectId: string, type: string })またはnull
certificateImageobject証明書画像参照({ objectId: string, type: string }
certifiedQualificationsarray資格オブジェクトの配列({ name: string, status: string, value: string }
auditStatusstring監査ステータス(ブロックで検証、スキーマではない)

レスポンスボディ:

FieldType説明
idstring一意の組織識別子
namestring更新された組織名
descriptionstring更新された組織の説明
contact_emailstring更新された連絡先メールアドレス
contact_phonestring更新された連絡先電話番号
addressobject更新されたアドレスオブジェクト
logoobject | null更新されたロゴ参照
certificateImageobject | null更新された証明書画像参照
certifiedQualificationsarray更新された認定資格
auditStatusstring更新された監査ステータス
createdAtstring作成タイムスタンプ
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: すべての組織フィールドに監査ステータスを加えた拡張管理者スキーマ
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールのみが必要

リクエスト例:

curl -X PATCH "{{host}}/admin/organizations/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"auditStatus": "approved",
"certificateImage": {
"objectId": "cert-123",
"type": "application/pdf"
}
}'

成功レスポンス:

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",
"auditStatus": "approved",
"certificateImage": {
"url": "https://storage.googleapis.com/...",
"type": "application/pdf"
},
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2025-01-15T14:22:15.789Z"
}

17. 子孫組織をリスト

指定された組織のすべての子孫組織を取得します。オプションで階層の深さによって制限できます。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/descendants
  • Headers: Authorization: Bearer <access-token>
  • Authorization: Bearerトークンが必要(管理者/所有者アクセス)

URLパラメータ:

ParameterType必須説明
organizationIdstring親組織識別子

クエリパラメータ:

ParameterType必須説明
depthnumber (>=1)階層の深さによって子孫を制限

バリデーション:

  • スキーマバリデーション: パスパラメータバリデーション(organizationId必須);depthが提供される場合は正の数である必要がある
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは組織所有者/管理者ロールが必要

リクエスト例:

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"
}
]

18. 組織フォロワーを取得

特定の組織のフォロワー(ユーザー/プロファイル)のページネーション付きリストを取得します。

リクエスト:

  • Method: GET
  • Path: /organizations/:organizationId/followers
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearerトークンが必要(管理者または組織所有者)
  • Body: 空(リクエストボディは不要)

URLパラメータ:

ParameterType必須説明
organizationIdstringフォロワーを取得する組織のID

クエリパラメータ:

ParameterType必須Default説明
pagenumber1ページネーションのページ番号(1-1000)
limitnumber20ページあたりの結果数(1-50)

レスポンスボディ: ページネーション付きフォロワーリストとメタデータを含むJSON

レスポンス構造:

{
"data": [
{
"id": "string",
"name": "string",
"avatar": {
"url": "string",
"type": "string"
}
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}

バリデーション:

  • スキーマバリデーション: 組織IDのパスパラメータバリデーション
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 組織の管理者ロールまたは所有者ロールが必要
    • 組織がデータベースに存在する必要がある
  • ビジネスロジック: アバターURL正規化付きのページネーション付きリストを返す

エラーレスポンス:

  • 400 Bad Request: 無効な組織IDまたは不正なリクエスト
  • 401 Unauthorized: 認証トークンが欠落しているか無効
  • 403 Forbidden: ユーザーに権限がない(管理者または組織所有者ではない)
  • 404 Not Found: 組織が存在しない
  • 500 Internal Server Error: データベースまたはファイルストレージ操作が失敗

リクエスト例:

curl -X GET "{{host}}/organizations/org-abc-123/followers?page=1&limit=20" \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"data": [
{
"id": "user-456",
"name": "John Doe",
"avatar": {
"url": "https://storage.example.com/avatars/avatar123.png",
"type": "image/png"
}
},
{
"id": "user-789",
"name": "Jane Smith",
"avatar": {
"url": "https://storage.example.com/avatars/avatar456.jpg",
"type": "image/jpeg"
}
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 20,
"total": 50,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}

組織が見つからないレスポンス:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"status": 404,
"message": "Organization not found",
"code": "OrganizationNotFoundError"
}

ユースケース:

  • 組織分析 - フォロワー数の追跡と成長
  • メンバーシップ管理 - 組織の購読者の表示と分析
  • コンテンツ配信 - フォロワーベースのコンテンツ配信
  • コミュニティエンゲージメント - 組織中心のソーシャル機能

主な機能:

  • ページネーション: 大きなフォロワーリストの効率的な処理
  • アバター正規化: ストレージ参照のアクセス可能なURLへの自動変換
  • 柔軟なクエリ: カスタマイズ可能なページサイズとページ番号
  • パフォーマンス: $elemMatch演算子を使用した最適化されたMongoDBクエリ
  • プロファイルブロックの再利用: 既存のfindProfilesとnormalizeFollowers関数を活用

⚙️ 設定オプション

サービス設定

interface OrganizationServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT encryption secret
authSignSecret: string; // JWT signing secret
};
identity?: {
typeIds?: {
admin: string; // Admin user type identifier
guest: string; // Guest user type identifier
regular: string; // Regular user type identifier
};
};
organization?: {
roles?: {
admin: string; // Admin role identifier
member: string; // Member role identifier
owner: string; // Owner role identifier
};
};
}

設定の詳細

組織サービス設定は、セキュリティ、ユーザータイプ管理、組織ロール管理の論理グループに整理されています。

🔐 セキュリティ設定

authSecrets - JWTトークンセキュリティシークレット

  • Type: { authEncSecret: string; authSignSecret: string }
  • 説明: JWT暗号化と署名のためのシークレットキー(トークン検証に使用)
  • 必須: はい(本番環境の場合)
  • 子プロパティ:
    • authEncSecret: JWTペイロード暗号化のためのシークレットキー
    • authSignSecret: JWT署名検証のためのシークレットキー

👥 ユーザータイプ設定

identity.typeIds - ユーザータイプ識別子設定

  • Type: { admin?: string; guest?: string; regular?: string }
  • 説明: ロールベースアクセス制御のためのカスタムユーザータイプ識別子
  • デフォルト: undefined(デフォルトのタイプ検証を使用)
  • 子プロパティ:
    • admin: 管理者ユーザータイプ識別子
      • Type: string
      • 説明: 管理者ユーザー用のカスタム識別子
      • ユースケース: 管理操作のロールベースアクセス制御
      • : "admin", "administrator", "superuser"
    • guest: ゲストユーザータイプ識別子
      • Type: string
      • 説明: ゲストユーザー用のカスタム識別子
      • ユースケース: 未認証または一時的なユーザー向けの制限付きアクセス
      • : "guest", "visitor", "anonymous"
    • regular: 通常ユーザータイプ識別子
      • Type: string
      • 説明: 通常ユーザー用のカスタム識別子
      • ユースケース: 標準的なユーザーアクセス権限
      • : "user", "member", "customer"

🏢 組織ロール設定

organization.roles - 組織ロール識別子設定

  • Type: { admin?: string; member?: string; owner?: string }
  • 説明: 組織内のユーザー管理のためのカスタム組織ロール識別子
  • デフォルト: undefined(デフォルトのロール検証を使用)
  • 子プロパティ:
    • admin: 管理者ロール識別子
      • Type: string
      • 説明: 組織管理者ロール用のカスタム識別子
      • ユースケース: 組織内の管理権限
      • : "admin", "administrator", "manager"
    • member: メンバーロール識別子
      • Type: string
      • 説明: 組織メンバーロール用のカスタム識別子
      • ユースケース: 組織内の標準メンバー権限
      • : "member", "user", "employee"
    • owner: 所有者ロール識別子
      • Type: 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'
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001'
}
},
organization: {
roles: {
admin: '100',
member: '001',
owner: '010'
}
}
};

🚨 エラーハンドリング

すべての組織サービスエラーは、適切なHTTPステータスコードと共にJSON形式で返されます:

一般的なエラーコード

StatusError Message説明
400Validation Error無効なリクエストボディ形式または必須フィールドの欠落
400Request body is requiredPATCH操作のリクエストボディが欠落
400Request body non-empty array requiredユーザー管理操作の配列が欠落しているか空
400Failed to create organizationデータベース挿入操作が挿入されたIDを返さなかった
400Failed to update organization更新操作がデータを変更しなかった(変更が検出されなかった)
400Failed to remove user from organizationユーザーが組織にいないか、削除に失敗した
401token could not be verified認証トークンが欠落しているか無効
403User is not authorized to access this resourceユーザーに必要な権限がない(管理者/組織アクセス)
404Organization not foundリクエストされた操作に対して組織が存在しない
500Failed to create organization作成中のデータベース接続の問題または予期しない失敗
500Failed to get organization取得中のデータベース接続の問題または予期しない失敗
500Failed to find organizationsリスト取得中のデータベース接続の問題、無効なフィルタ構文、または予期しない失敗
500Failed to update organization更新中のデータベース接続の問題または予期しない失敗
500Failed to delete organization削除中のデータベース接続の問題または予期しない失敗
500Failed to upsert organization usersユーザー管理中のデータベース接続の問題または予期しない失敗
500Failed to delete organization userユーザー削除中のデータベース接続の問題または予期しない失敗
500Failed to get organization user roleロール取得中のデータベース接続の問題または予期しない失敗
500Failed to check organization user existence存在確認中のデータベース接続の問題または予期しない失敗
500Cannot read properties of undefined (reading 'organizations')ユーザー用の組織検索エンドポイントのハンドラー実装バグ

エラーレスポンス形式

{
"error": {
"message": "エラーメッセージの説明",
"data": ["追加のエラー詳細"]
}
}

バリデーションエラーには追加の詳細が含まれます:

{
"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'"
]
}
}

🔗 関連ドキュメント