🛣️ 組織ルート
組織ルートは、NodeBlocksアプリケーションで組織管理操作のための事前設定されたHTTPエンドポイントを提供します。これらのルートは、ブロック、ターミネーター、バリデーターを組み合わせて、適切な認証、認可、エラーハンドリングを備えた完全なAPIエンドポイントを作成します。
🎯 概要
組織ルートは以下の目的で設計されています:
- 完全なAPIエンドポイントを提供 - 組織管理操作用
- セキュアな操作のためのブロックとターミネーターの組み合わせ - セキュリティ
- 認証と認可チェックを含む - アクセス制御
- 関数型合成パターンをサポート - 構成可能性
- ログとエラー管理を自動処理 - 運用性
📋 ルート構造
各組織ルートは一貫したパターンに従います:
- HTTP Method: 操作タイプを定義(GET、POST、PATCH、DELETE)
- Path: パラメータ付きエンドポイントURLを指定
- Handler: ブロックとターミネーターを使用した構成された関数チェーン
- バリデーター: 認証と認可チェック
🔧 利用可能な組織ルート
createOrganizationRoute
新しい組織を作成し、作成されたリソースを返します。
目的: 完全なリソース取得を含む組織作成を処理
ルート詳細:
- Method:
POST - Path:
/organizations - 認証: Required (Bearer token)
ブロック: createOrganization, getOrganizationById, calculateChildAncestors, normalizeLogoOfOwner
ターミネーター: normalizeOrganizationTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createOrganizationRoute);
getOrganizationRoute
IDで特定の組織を取得します。
目的: アクセス制御付きで組織データを取得
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId - 認証: Required (Bearer token)
ブロック: getOrganizationById, normalizeLogoOfOwner
ターミネーター: normalizeOrganizationTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin', 'member'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getOrganizationRoute);
findOrganizationsRoute
正規化されたリスト形式ですべての組織を取得します。
目的: ページネーションとアクセス制御付きで組織を一覧表示
ルート詳細:
- Method:
GET - Path:
/organizations - 認証: Required (Bearer token)
ブロック: findOrganizations, normalizeLogosOfOwners
ターミネーター: normalizeOrganizationsListTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationsRoute);
updateOrganizationRoute
既存の組織を更新し、更新されたリソースを返します。
目的: アクセス制御付きで組織データを変更
ルート詳細:
- Method:
PATCH - Path:
/organizations/:organizationId - 認証: Required (Bearer token)
ブロック: updateOrganization, getOrganizationById, normalizeLogoOfOwner
ターミネーター: normalizeOrganizationTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateOrganizationRoute);
deleteOrganizationRoute
IDで組織を削除します。
目的: アクセス制御付きで組織を削除
ルート詳細:
- Method:
DELETE - Path:
/organizations/:organizationId - 認証: Required (Bearer token)
ブロック: getOrganizationById, deleteLogoOfOwner, deleteOrganization
ターミネーター: deleteOrganizationTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteOrganizationRoute);
getOrganizationMemberRoleRoute
組織内の特定のメンバーのロールを取得します。
目的: 組織内のメンバーロールを取得
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/members/:identityId/role - 認証: Required (Bearer token)
ブロック: getOrganizationById, buildOrganizationsForMemberByIdsQuery, findOrganizations, calculateMemberRole
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getOrganizationMemberRoleRoute);
checkOrganizationMemberExistenceRoute
組織内にメンバーが存在するかどうかを確認します。
目的: 組織内のメンバーシップを検証
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/members/check-existence - 認証: Required (Bearer token)
ブロック: getOrganizationById, checkOrganizationMemberExistence
ターミネーター: normalizeOrganizationMemberExistenceTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.checkOrganizationMemberExistenceRoute);
findOrganizationMembersRoute
組織内のすべてのメンバーを取得します。
目的: 組織メンバーを一覧表示
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/members - 認証: Required (Bearer token)
ブロック: findOrganizationMembers
ターミネーター: normalizeOrganizationMembersListTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationMembersRoute);
upsertOrganizationMembersRoute
組織内のメンバーを作成または更新します。
目的: 組織メンバーシップを管理
ルート詳細:
- Method:
PATCH - Path:
/organizations/:organizationId/members - 認証: Required (Bearer token)
ブロック: getOrganizationById, upsertOrganizationMembers
ターミネーター: upsertOrganizationMembersTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.upsertOrganizationMembersRoute);
deleteOrganizationMemberRoute
組織からメンバーを削除します。
目的: 組織メンバーシップからメンバーを削除
ルート詳細:
- Method:
DELETE - Path:
/organizations/:organizationId/members/:identityId - 認証: Required (Bearer token)
ブロック: deleteOrganizationMember
ターミネーター: deleteOrganizationMemberTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteOrganizationMemberRoute);
findOrganizationsForMemberRoute
特定のアイデンティティ(メンバー)のすべての組織を取得します。includeInherited=trueクエリパラメータを介して、子孫組織からの継承ロールのオプションの包含をサポートします。
目的: アイデンティティがメンバーである組織を一覧表示し、オプションで継承ロールを含む
ルート詳細:
- Method:
GET - Path:
/organizations/members/:identityId - 認証: Required (Bearer token)
ブロック: buildOrganizationsForMemberByRoleQuery, findOrganizations, normalizeLogosOfOwners, buildOrganizationsWithDescendantsQuery, extractAncestors, buildOrganizationsForMemberByIdsQuery, calculateMemberRoleForOrganizations, normalizeOrganizationsForMember
ターミネーター: ロール情報を含む組織リストをフォーマット;orThrowによる成功/エラーマッピング
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), isSelf(['params', 'requestParams', 'identityId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationsForMemberRoute);
getLogoUploadUrlRoute
GET /organizations/:organizationId/logo-upload-urlを介して組織ロゴ用の署名付きアップロードURLを生成します。
目的: 組織ロゴを安全にアップロードするための事前署名付きURLを発行
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/logo-upload-url - 認証: Required (Bearer token)
ブロック: generateSignedLogoUploadUrl
ターミネーター: orThrowによる組み込み成功/エラーマッピング
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Use in feature composition:
export const logoUploadFeature = compose(getSignedImageUploadUrlSchema, getLogoUploadUrlRoute);
findOrganizationDescendantsRoute
指定された組織のすべての子孫組織を取得します。
目的: 組織ツリー内の子孫を一覧表示;?depth=<n>クエリパラメータを介して深度をサポート
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/descendants - 認証: Required (Bearer token)
ブロック: getOrganizationById, buildDescendantsQuery, findOrganizations, normalizeOrganizations
ターミネーター: orThrowによる成功/エラーマッピングで子孫組織リストを正規化
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationDescendantsRoute);
getCertificateUploadUrlRoute
組織証明書用の署名付きアップロードURLを生成します。
目的: 自動オブジェクトID生成を備えた証明書ファイル用の安全なアップロードURLを提供
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/certificate-upload-url - 認証: Required (Bearer token)
- クエリパラメータ:
contentType- 証明書MIMEタイプ(application/pdf、image/gif、image/jpeg、image/png)contentLength- バイト単位のファイルサイズ(最大10MB)
ブロック: generateFileUploadUrl
レスポンス: { objectId: string; url: string } - UUIDと署名付きアップロードURL
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
ハンドラープロセス:
- 認証と認可を検証
- UUIDオブジェクトIDを生成
- ファイル拡張子付きの署名付きアップロードURLを作成
- クライアントアップロード用のオブジェクトIDとURLを返す
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getCertificateUploadUrlRoute);
// Client usage:
const response = await fetch(
`/api/organizations/org-123/certificate-upload-url?contentType=application/pdf&contentLength=102400`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { objectId, url } = await response.json();
createChangeRequestRoute
自動監査ステータス更新付きで組織変更リクエストを作成します。
目的: バリデーション、証明書アップロード、監査追跡を含む組織変更リクエストを処理
ルート詳細:
- Method:
POST - Path:
/organizations/:organizationId/change-requests - 認証: Required (Bearer token)
- リクエストボディ: 少なくとも1つのフィールドが必要(name、address、certificate、qualificationsなど)
- レスポンス:
204 No Content- 成功時に空のレスポンスボディ
ブロック: getOrganizationById, validateOrganizationName, extractTokenFromAuthorizationHeader, checkToken, createChangeRequest, buildUpdateOrganizationAfterNewChangeRequestPayload, updateOrganization, normalizeEmptyBody
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
エラーレスポンス:
400 Bad Request- 無効な入力、重複した組織名、または無効なトークン401 Unauthorized- 認証失敗500 Internal Server Error- データベースまたはファイルストレージエラー
ハンドラープロセス:
- IDで組織を取得
- 提供された場合、組織名の一意性を検証
- Authorizationヘッダーからアクセストークンを抽出して検証
- トークンからidentityIdを使用して変更リクエストを作成
- 組織の監査ステータスを
waiting_for_reviewに更新 - 204ステータスで空のボディを返す
主な機能:
- 自動組織名一意性検証
- 変更リクエスト作成者用のトークンベースのアイデンティティ抽出
waiting_for_reviewへの自動監査ステータス更新- 証明書画像と認定資格のサポート
- 特定のエラークラスによる包括的なエラーハンドリング
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createChangeRequestRoute);
// Client usage:
const response = await fetch(`/api/organizations/org-123/change-requests`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Updated Organization Name',
addressLine1: '123 Main Street',
certificateImage: {
objectId: cert-uuid',
type: 'application/pdf'
},
certifiedQualifications: [
{ name: 'ISO 9001', status: 'approved', value: '2024' }
]
})
});
// Returns 204 No Content on success
findChangeRequestsForOrganizationRoute
ページネーションとファイルURLエンリッチメント付きで特定の組織の変更リクエストを取得します。
目的: 正規化されたデータと証明書用の署名付きダウンロードURLを含む組織変更リクエストを一覧表示
ルート詳細:
- Method:
GET - Path:
/organizations/:organizationId/change-requests - 認証: Required (Bearer token)
ブロック: findChangeRequests, normalizeChangeRequests
ターミネーター: ページネーションメタデータを含むレスポンスフォーマット
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
レスポンス形式:
{
"data": [
{
"id": "string",
"organizationId": "string",
"identityId": "string",
"name": "string",
"certificateImage": {
"objectId": "string",
"type": "string"
},
"certificateImageUrl": "string",
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
エラーレスポンス:
401 Unauthorized- 認証失敗403 Forbidden- ユーザーに管理者権限または組織所有権がない500 Internal Server Error- データベースクエリ失敗またはファイルURL生成エラー
ハンドラープロセス:
- ユーザーを認証し、組織アクセスを検証
- ページネーション付きでデータベースから変更リクエストを取得
- 各変更リクエストを正規化(
_idを削除し、証明書URLを生成) - 正規化されたデータを含むページネーション付きレスポンスを返す
主な機能:
- 設定可能なページサイズによるページネーションサポート
- 証明書画像の自動ファイルURL生成
- URL生成失敗時の優雅なフォールバック
- 組織オーナーと管理者のためのアクセス制御
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findChangeRequestsForOrganizationRoute);
// Client usage:
const response = await fetch(`/api/organizations/org-123/change-requests?page=1&limit=20`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const result = await response.json();
// Returns 200 OK with paginated change requests
updateOrganizationAsAdminRoute
拡張フィールドアクセスと監査ステータス検証付きで管理者として組織を更新します。
目的: 名前変更、監査ステータス、認定フィールドを含む管理者専用の組織更新を提供
ルート詳細:
- Method:
PATCH - Path:
/admin/organizations/:organizationId/ - 認証: Required (Bearer token)
- 認可: 管理者アイデンティティタイプのみ
- リクエストボディ: 少なくとも1つのフィールド(すべてのフィールドはオプション)
- レスポンス:
200 OK- 正規化されたロゴURLを含む更新された組織を返す
ブロック: validateAuditStatus, updateOrganization, getOrganizationById, normalizeLogoOfOwner
ターミネーター: normalizeOrganizationTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
エラーレスポンス:
400 Bad Request- 無効な監査ステータスまたは検証失敗401 Unauthorized- 認証失敗403 Forbidden- 非管理者ユーザーが管理者更新を試行404 Not Found- 組織が見つからない500 Internal Server Error- データベースまたは処理エラー
ハンドラープロセス:
- 提供された場合、監査ステータスを検証('approved'または'rejected'である必要がある)
- 提供されたフィールドで組織を更新
- データベースから更新された組織を取得
- 署名付きダウンロードURLを含むようにロゴを正規化
- 正規化された組織データを返す
利用可能な更新フィールド:
- 共通フィールド:
branchName、contact_email、contact_phone、description - 管理者承認フィールド:
name、address、certificateImage、certifiedQualifications、logo、typeId、auditStatus
主な機能:
- 管理者専用アクセス制御
- 名前変更を含む拡張フィールドアクセス
- 変更リクエストワークフロー用の監査ステータス検証
- 証明書画像と認定資格のサポート
- レスポンスでの自動ロゴURL正規化
- 柔軟な部分更新(すべてのフィールドはオプション)
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateOrganizationAsAdminRoute);
// Client usage:
const response = await fetch(`/api/admin/organizations/org-123/`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${adminToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Updated Organization Name',
auditStatus: 'approved',
certificateImage: {
objectId: 'cert-uuid',
type: 'application/pdf'
},
certifiedQualifications: [
{ name: 'ISO 9001', status: 'approved', value: '2024' }
]
})
});
const updatedOrg = await response.json();
// Returns 200 OK with normalized organization including logo URL
組織フォロワー取得
getOrganizationFollowersRoute
GET /organizations/:organizationId/followersを介して組織のページネーション付きフォロワーリストを取得します。
目的: ページネーションとアバター正規化付きで組織フォロワーを取得するためのAPIエンドポイントを提供
ルート詳細:
- Method: GET
- Path:
/organizations/:organizationId/followers - 認証: Required (Bearer token)
ブロック: getOrganizationById, buildOrganizationFollowersByFollowOrganizationIdQuery, buildWithoutMongoIdFindOptions, findProfiles, normalizeFollowers
ターミネーター: 200ステータスコード付きのorThrowによる組み込み成功/エラーマッピング
バリデーター:
isAuthenticatedsome(checkIdentityType(['admin']),hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
リクエストボディ: なし(空のボディ)
レスポンス(200 OK): ページネーション付きフォロワーリストとメタデータを含むJSON
パスパラメータ:
organizationId: string- フォロワーを取得する組織のID
クエリパラメータ:
page?: number- ページネーション用のページ番号(デフォルト: 1)limit?: number- 1ページあたりの結果数(デフォルト: 20)
レスポンス構造:
{
"data": [
{
"id": "string",
"name": "string",
"avatar": {
"url": "string",
"type": "string"
}
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number
}
}
}
エラーレスポンス:
400 Bad Request: 無効なリクエストパラメータまたは不正な形式のパス401 Unauthorized: 認証失敗403 Forbidden: ユーザーに管理者権限がなく、組織を所有していない404 Not Found: 組織が存在しない500 Internal Server Error: データベースまたはファイルストレージ操作が失敗
ハンドラープロセス:
- 認証と認可: ユーザーが認証され、権限(管理者または組織オーナー)を持っていることを検証
- 組織検証: getOrganizationByIdを使用して組織が存在することを確認
- クエリ構築: 組織フォロワー用のMongoDBフィルタを構築
- 検索オプション: クエリオプションを構築(MongoDB _idを除外)
- フォロワー取得: findProfilesを使用してページネーション付きでプロファイルを検索
- アバター正規化: アバターobjectIdをアクセス可能なURLに変換
- レスポンスフォーマット: フォロワーデータとページネーションメタデータを結合
- エラーマッピング: 特定のブロックエラーを適切なHTTPステータスコードにマッピング
- 成功レスポンス: ページネーション付きの正規化されたフォロワーリストで200 OKを返す
主な機能:
- ページネーションサポート: 大規模なフォロワーリストの効率的な処理
- アバター正規化: ストレージ参照のアクセス可能なURLへの自動変換
- 認可制御: 管理者と組織オーナーへのアクセスを制限
- 包括的なエラーハンドリング: 異なる失敗シナリオに対する特定のエラーレスポンスを提供
- プロファイルブロックの再利用: 既存のfindProfilesとnormalizeFollowers関数を活用
認可に関する注意事項:
- Bearerトークンによる認証が必要
- 管理者または組織オーナーがアクセス可能
someバリデーターを使用して、管理者アクセスまたは組織所有権のいずれかを許可
使用例:
import { routes } from '@nodeblocks/backend-sdk';
const { getOrganizationFollowersRoute } = routes;
// Register route with Express app
app.use('/api', getOrganizationFollowersRoute);
// Client usage - get organization followers
const response = await fetch('/api/organizations/org-123/followers?page=1&limit=20', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 200) {
const { data, metadata } = await response.json();
console.log('Followers:', data);
console.log('Pagination:', metadata.pagination);
} else if (response.status === 404) {
console.log('Organization not found');
} else {
console.error('Failed to retrieve followers:', response.status);
}
ルート構成: ルートは関数型プログラミングパターンを使用して構成されます:
const getOrganizationFollowersRoute = withRoute({
handler: compose(
// Validate organization exists
withLogging(
applyPayloadArgs(getOrganizationById, [
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId']
]),
'organization'
),
// Build query filter for followers
flatMapAsync(
withLogging(
applyPayloadArgs(buildOrganizationFollowersByFollowOrganizationIdQuery, [
['params', 'requestParams', 'organizationId']
]),
'filter'
)
),
// Build find options
flatMapAsync(
withLogging(
applyPayloadArgs(buildWithoutMongoIdFindOptions, []),
'options'
)
),
// Find profiles with pagination
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(findProfiles, [
['context', 'db', 'users'],
['context', 'data', 'filter'],
['context', 'data', 'options']
]),
'paginatedFollowers'
)
)
),
// Normalize follower avatars
flatMapAsync(
withLogging(
applyPayloadArgs(normalizeFollowers, [
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedFollowers', 'data']
]),
'normalizedFollowers'
)
),
// Format response with pagination metadata
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedFollowers'],
['context', 'data', 'paginatedFollowers', 'metadata']
],
'normalizedBody'
)
),
// Map errors to HTTP status codes
lift(
orThrow([
[OrganizationNotFoundError, 404],
[OrganizationDbError, 500],
[AvatarBlockError, 500],
[ProfileDbBlockError, 500],
], [['context', 'data', 'normalizedBody'], 200])
)
),
method: 'GET',
path: '/organizations/:organizationId/followers',
validators: [/* authentication and authorization validators */]
});
パフォーマンスに関する考慮事項:
- 大規模なフォロワーリストを処理するためのページネーションサポート
- 高速検証のためのインデックス付き組織ルックアップ
- 複数のフォロワーに対するバッチアバターURL正規化
- 必須のフォロワーデータのみを含む最小限のレスポンスペイロード
- 配列マッチングのための効率的なMongoDB $elemMatchクエリ
統合パターン:
- 完全な組織管理のために組織サービスと組み合わせ
- アバターURL生成のためにファイルストレージドライバーと統合
- スケーラブルなフォロワーリストのためにページネーションミドルウェアと連携
- プロファイルと組織機能全体で一貫性のためにプロファイルブロックを再利用
- リアルタイムフォロワー数更新と通知をサポート