メインコンテンツまでスキップ
バージョン: 0.4.2

🏢 組織サービス

Testing Status

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


🚀 クイックスタート

import express from 'express';
import { MongoClient } from 'mongodb';

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

const { nodeBlocksErrorMiddleware } = middlewares;
const { organizationService } = services;

const client = new MongoClient('mongodb://localhost:27017').db('dev');

express()
.use(
organizationService(
{
organizations: client.collection('organizations'),
identity: client.collection('identity'),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
user: {
typeIds: {
admin: '100',
guest: '000',
user: '001',
},
},
organization: {
roles: {
admin: '100',
member: '001',
owner: '010',
},
},
}
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('サーバーが起動しました'));

📋 エンドポイント概要

メソッドパス説明認証
POST/organizations新規組織を作成Bearerトークン必須
GET/organizations/:organizationIdIDで組織を取得Bearerトークン必須(メンバー)
GET/organizations組織リストを取得Bearerトークン必須
PATCH/organizations/:organizationId組織を更新Bearerトークン必須(管理者/オーナー)
DELETE/organizations/:organizationId組織を削除Bearerトークン必須(オーナーのみ)
POST/organizations/:organizationId/membersメンバーを追加Bearerトークン必須(管理者/オーナー)
DELETE/organizations/:organizationId/members/:userIdメンバーを削除Bearerトークン必須(管理者/オーナー)
PATCH/organizations/:organizationId/members/:userId/roleメンバーロールを更新Bearerトークン必須(オーナーのみ)

🔧 必要な設定

データストア

組織サービスには以下のMongoDBコレクションが必要です:

const dataStores = {
organizations: client.collection('organizations'), // 組織データ
identity: client.collection('identity'), // 認証情報
};

設定オプション

interface OrganizationConfig {
authSecrets: {
authEncSecret: string;
authSignSecret: string;
};
user: {
typeIds: {
admin: string; // システム管理者
guest: string; // ゲスト
user: string; // 一般ユーザー
};
};
organization: {
roles: {
admin: string; // 組織管理者(例: '100')
member: string; // 一般メンバー(例: '001')
owner: string; // 組織オーナー(例: '010')
};
};
}

🏢 組織操作

1. 組織作成

curl -X POST http://localhost:8089/organizations \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "株式会社サンプル",
"description": "サンプル会社の説明",
"industry": "technology",
"website": "https://example.com"
}'

レスポンス:

{
"organizationId": "uuid-here",
"message": "組織が正常に作成されました"
}

2. 組織取得

# 特定組織の取得
curl -X GET http://localhost:8089/organizations/org-uuid-here \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# 組織リストの取得
curl -X GET http://localhost:8089/organizations \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

レスポンス例:

{
"id": "uuid-here",
"name": "株式会社サンプル",
"description": "サンプル会社の説明",
"industry": "technology",
"website": "https://example.com",
"members": [
{
"userId": "user-uuid",
"role": "owner",
"joinedAt": "2024-01-15T10:30:00.000Z"
}
],
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}

3. 組織更新

curl -X PATCH http://localhost:8089/organizations/org-uuid-here \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "更新された組織名",
"description": "新しい説明"
}'

👥 メンバー管理

メンバー追加

curl -X POST http://localhost:8089/organizations/org-uuid-here/members \
-H "Authorization: Bearer ADMIN_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-uuid-to-add",
"role": "member"
}'

メンバー削除

curl -X DELETE http://localhost:8089/organizations/org-uuid-here/members/user-uuid \
-H "Authorization: Bearer ADMIN_ACCESS_TOKEN"

メンバーロール更新

curl -X PATCH http://localhost:8089/organizations/org-uuid-here/members/user-uuid/role \
-H "Authorization: Bearer OWNER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "admin"
}'

🛡️ 権限システム

ロール階層

owner (010)    - 最高権限、組織の削除、メンバーロール変更

admin (100) - 組織管理、メンバー追加/削除

member (001) - 基本メンバー権限

アクセス制御マトリックス

操作OwnerAdminMember
組織表示
組織更新
組織削除
メンバー追加
メンバー削除
ロール変更

📊 データスキーマ

組織エンティティ

interface Organization {
id: string; // 一意識別子
name: string; // 組織名(必須)
description?: string; // 組織説明
industry?: string; // 業界
website?: string; // ウェブサイトURL
logo?: string; // ロゴURL
settings?: {
timezone?: string;
language?: string;
currency?: string;
};
members: Member[]; // メンバーリスト
metadata?: Record<string, any>; // 追加メタデータ
createdAt: string; // 作成日時
updatedAt: string; // 更新日時
}

interface Member {
userId: string; // ユーザーID
role: 'owner' | 'admin' | 'member'; // ロール
joinedAt: string; // 参加日時
invitedBy?: string; // 招待者ID
}

検証ルール

const organizationValidation = {
name: {
required: true,
minLength: 2,
maxLength: 100
},
description: {
maxLength: 500
},
website: {
format: 'uri',
optional: true
},
industry: {
enum: ['technology', 'finance', 'healthcare', 'education', 'other']
}
};

🎯 高度な使用方法

カスタム組織フィールド

// 拡張組織スキーマ
const extendedOrgConfig = {
...baseConfig,
customFields: {
companySize: {
type: 'string',
enum: ['startup', 'small', 'medium', 'large', 'enterprise']
},
foundedYear: { type: 'number', min: 1800, max: 2100 },
headquarters: {
address: { type: 'string' },
city: { type: 'string' },
country: { type: 'string' }
}
}
};

組織検索とフィルタリング

# 名前で検索
curl -X GET "http://localhost:8089/organizations?name=株式会社" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# 業界でフィルタ
curl -X GET "http://localhost:8089/organizations?industry=technology" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# ページネーション
curl -X GET "http://localhost:8089/organizations?page=1&limit=10" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

バルク招待

// 複数ユーザーの一括招待
const bulkInvite = async (organizationId, userIds, role = 'member') => {
const invitations = userIds.map(userId => ({
organizationId,
userId,
role,
invitedAt: new Date().toISOString()
}));

return await Promise.all(
invitations.map(invitation =>
organizationService.addMember(invitation)
)
);
};

🔧 カスタマイゼーション

カスタム招待フロー

import { organizationService } from '@nodeblocks/backend-sdk';

const customInvitationFlow = {
// 招待前の承認プロセス
preInvite: async (organizationId, inviteeEmail) => {
// 管理者承認が必要かチェック
const org = await getOrganization(organizationId);
if (org.settings?.requireApproval) {
await requestAdminApproval(organizationId, inviteeEmail);
}
},

// 招待メール送信
sendInvitation: async (invitation) => {
const emailTemplate = {
to: invitation.email,
subject: `${invitation.organizationName}への招待`,
body: `
${invitation.organizationName}にご招待いただきました。
以下のリンクから参加してください:
${invitation.acceptUrl}
`
};
return await emailService.send(emailTemplate);
}
};

組織設定管理

// 組織固有の設定
const organizationSettings = {
// 時間帯設定
timezone: 'Asia/Tokyo',

// 言語設定
language: 'ja',

// 通貨設定
currency: 'JPY',

// セキュリティ設定
security: {
requireTwoFactor: true,
allowedDomains: ['@company.com'],
maxMembers: 100
},

// 通知設定
notifications: {
memberJoined: true,
memberLeft: true,
organizationUpdated: true
}
};

🧪 テスト

ユニットテスト例

import { organizationService } from '@nodeblocks/backend-sdk';
import { createMemoryDataStore } from '../test-utils';

describe('組織サービス', () => {
let orgApp;
let testDataStore;
let ownerToken, adminToken, memberToken;

beforeEach(async () => {
testDataStore = createMemoryDataStore();
orgApp = organizationService(
{
organizations: testDataStore.collection('organizations'),
identity: testDataStore.collection('identity'),
},
testConfig
);

// テストトークンを準備
ownerToken = await createTestToken('owner');
adminToken = await createTestToken('admin');
memberToken = await createTestToken('member');
});

test('組織作成が成功する', async () => {
const orgData = {
name: 'テスト組織',
description: 'テスト用の組織',
industry: 'technology'
};

const response = await request(orgApp)
.post('/organizations')
.set('Authorization', `Bearer ${ownerToken}`)
.send(orgData)
.expect(201);

expect(response.body.message).toBe('組織が正常に作成されました');
});

test('メンバー追加が成功する', async () => {
const orgId = await createTestOrganization();
const newMemberData = {
userId: 'new-user-id',
role: 'member'
};

const response = await request(orgApp)
.post(`/organizations/${orgId}/members`)
.set('Authorization', `Bearer ${adminToken}`)
.send(newMemberData)
.expect(201);

expect(response.body.message).toBe('メンバーが正常に追加されました');
});

test('権限不足でメンバー削除が失敗する', async () => {
const orgId = await createTestOrganization();
const userIdToRemove = 'user-to-remove';

await request(orgApp)
.delete(`/organizations/${orgId}/members/${userIdToRemove}`)
.set('Authorization', `Bearer ${memberToken}`)
.expect(403);
});
});

🔗 関連リソース


➡️ 次のステップ

組織サービスを設定したら、招待システムと統合してメンバー招待機能を追加することを検討してください。