コンテンツにスキップ

リソースレベル権限システム クイックスタートガイド

このガイドでは、リソースレベル権限システムを5分で開始する手順を説明します。

📋 前提条件

  • Node.js 18以降
  • MySQL 8.0以降
  • DATABASE_URLが設定済み

🚀 5分でスタート

ステップ1: データベースマイグレーション(1分)

新しい権限テーブルを作成します。

cd web
npx prisma migrate dev --name add_resource_permissions

これにより以下のテーブルが作成されます: - ResourcePermission - リソースレベル権限 - ResourceRoleTemplate - ロールテンプレート

ステップ2: ロールテンプレートのシード(1分)

標準的なロールテンプレートを登録します。

npx tsx prisma/seed-resource-roles.ts

これにより以下のロールテンプレートが作成されます:

Project用: - ProjectAdmin(全権限) - ProjectManager(管理権限) - ProjectEditor(編集権限) - ProjectViewer(閲覧のみ)

CircleProject用: - Manager(全権限) - Editor(編集権限) - Member(基本権限) - Viewer(閲覧のみ)

ステップ3: APIエンドポイントを登録(1分)

新しいエンドポイントをアプリケーションに登録します。

app/api/[[...route]]/route.ts を編集:

import resourcePermissionApp from '@/endpoints/resource-permission';
import resourceRoleTemplateApp from '@/endpoints/resource-role-template';

// 既存のルート登録の後に追加
app.route('/api/resource-permissions', resourcePermissionApp);
app.route('/api/resource-role-templates', resourceRoleTemplateApp);

ステップ4: 動作確認(2分)

サーバーを起動して動作確認します。

npm run dev

4-1. ロールテンプレート一覧を取得

curl http://localhost:3000/api/resource-role-templates \
  -H "Authorization: Bearer YOUR_TOKEN"

4-2. ユーザーに権限を付与

curl -X POST http://localhost:3000/api/resource-permissions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "userId": "YOUR_USER_ID",
    "resourceType": "CIRCLE_PROJECT",
    "resourceId": "YOUR_PROJECT_ID",
    "roleTemplate": "Manager"
  }'

4-3. 権限をチェック

curl "http://localhost:3000/api/resource-permissions/check?\
resourceType=CIRCLE_PROJECT&\
resourceId=YOUR_PROJECT_ID&\
permissions=READ,WRITE" \
  -H "Authorization: Bearer YOUR_TOKEN"

🎯 次にやること

既存のエンドポイントを移行

既存の認証システムから新しいリソースレベル権限に移行します。

Before(グローバルロール):

import { requireAdmin } from '@/lib/api/auth';

app.put('/api/project/:id', requireAdmin(), async (c) => {
  // ...
});

After(リソースレベル権限):

import { requireResourcePermission } from '@/lib/api/auth';

app.put('/api/project/:prefix',
  requireResourcePermission('PROJECT', 'prefix', ['WRITE']),
  async (c) => {
    // ...
  }
);

既存のメンバーに権限を付与

既存のCircleProjectメンバーにリソース権限を付与するスクリプトを実行:

// scripts/migrate-permissions.ts
import { PrismaClient } from '../app/generated/client';

const prisma = new PrismaClient();

async function main() {
  const circleProjects = await prisma.circleProject.findMany({
    include: {
      members: { orderBy: { id: 'asc' } }
    }
  });

  for (const cp of circleProjects) {
    for (let i = 0; i < cp.members.length; i++) {
      const isManager = i === 0;
      const permissions = isManager
        ? ['READ', 'WRITE', 'DELETE', 'MANAGE_MEMBERS', 'MANAGE_PERMISSIONS', 'CHECKIN', 'VIEW_PRIVATE']
        : ['READ', 'CHECKIN'];

      await prisma.resourcePermission.upsert({
        where: {
          userId_resourceType_resourceId: {
            userId: cp.members[i].userId,
            resourceType: 'CIRCLE_PROJECT',
            resourceId: cp.id,
          }
        },
        update: {
          permissions: JSON.stringify(permissions),
        },
        create: {
          userId: cp.members[i].userId,
          resourceType: 'CIRCLE_PROJECT',
          resourceId: cp.id,
          permissions: JSON.stringify(permissions),
        }
      });
    }
  }

  console.log('✅ Migration completed');
}

main()
  .catch(console.error)
  .finally(() => prisma.$disconnect());

実行:

npx tsx scripts/migrate-permissions.ts

🔧 よくある使用パターン

パターン1: プロジェクト管理者を追加

curl -X POST http://localhost:3000/api/resource-permissions \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "admin-user-id",
    "resourceType": "PROJECT",
    "resourceId": "chibafes2024",
    "roleTemplate": "ProjectAdmin"
  }'

パターン2: 期限付きで編集権限を付与

curl -X POST http://localhost:3000/api/resource-permissions \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "temp-editor-id",
    "resourceType": "CIRCLE_PROJECT",
    "resourceId": "project-123",
    "roleTemplate": "Editor",
    "expiresAt": "2025-12-31T23:59:59Z"
  }'

パターン3: カスタム権限セットを作成

curl -X POST http://localhost:3000/api/resource-permissions \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "custom-user-id",
    "resourceType": "CIRCLE_PROJECT",
    "resourceId": "project-456",
    "permissions": ["READ", "CHECKIN", "VIEW_PRIVATE"]
  }'

📚 詳細なドキュメント

より詳しい情報は以下を参照してください:

🎓 主要な概念

9種類の権限

  1. READ - リソースの閲覧
  2. WRITE - リソースの編集・更新
  3. DELETE - リソースの削除
  4. MANAGE_MEMBERS - メンバーの追加・削除
  5. MANAGE_PERMISSIONS - 権限の付与・削除
  6. APPROVE - 申請の承認
  7. CHECKIN - チェックイン操作
  8. ALLOCATE_RESOURCES - リソースの割り当て
  9. VIEW_PRIVATE - 非公開情報の閲覧

2種類のリソース

  1. PROJECT - イベント全体(例: 千葉大祭2024)
  2. CIRCLE_PROJECT - 個別企画

ロールテンプレート

よく使う権限セットをテンプレートとして保存し、簡単に適用できます。

⚠️ 注意事項

  1. FullAccessAdminの特別扱い
  2. FullAccessAdminロールを持つユーザーは、全リソースに対して全権限を自動的に持ちます
  3. これは後方互換性のための機能です

  4. 権限の継承なし

  5. 親プロジェクトの権限が子企画に自動継承されることはありません
  6. 必要に応じて個別に権限を付与してください

  7. 期限切れの権限

  8. expiresAtを過ぎた権限は自動的に無効になります
  9. 定期的なクリーンアップスクリプトの実行を推奨します

🐛 トラブルシューティング

問題: マイグレーションが失敗する

解決策: DATABASE_URLが正しく設定されているか確認してください。

echo $DATABASE_URL
# または
echo %DATABASE_URL%  # Windows

問題: 権限チェックが常にfalseを返す

解決策: 1. リソースIDが正しいか確認 2. ResourcePermissionテーブルにデータが存在するか確認 3. 権限の有効期限が切れていないか確認

-- 直接データベースで確認
SELECT * FROM ResourcePermission
WHERE userId = 'your-user-id'
AND resourceType = 'CIRCLE_PROJECT'
AND resourceId = 'your-project-id';

問題: エンドポイントが404を返す

解決策: ルートが正しく登録されているか確認してください。

// app/api/[[...route]]/route.ts
app.route('/api/resource-permissions', resourcePermissionApp);
app.route('/api/resource-role-templates', resourceRoleTemplateApp);

💡 ヒント

  1. 開発環境では権限チェックを頻繁に使用

    # デバッグ用エンドポイントを活用
    curl "http://localhost:3000/api/resource-permissions/check?..."
    

  2. ロールテンプレートを積極的に活用

  3. カスタム権限より標準テンプレートを優先
  4. 一貫性が保たれ、管理が容易になります

  5. 期限付き権限で安全性を向上

  6. 一時的なアクセスには必ず有効期限を設定
  7. セキュリティリスクを最小化できます

🎉 完了!

これでリソースレベル権限システムを使い始める準備が整いました。

質問や問題がある場合は、以下を確認してください: - MIGRATION_GUIDE.mdのトラブルシューティングセクション - USAGE_EXAMPLES.mdの具体的な使用例 - API_SPECIFICATION.mdのAPI仕様