代理ログイン

概要説明

代理ログイン機能により、管理者はサポートやトラブルシューティング目的でグループメンバーのアイデンティティを一時的に引き受けることができます。この機能によって、管理者は特定のユーザーがアプリケーションをどのように見るかを正確に確認でき、より効果的なサポートと問題解決が可能になります。管理者がこの機能を使用する際、システムと対話しながら選択したユーザーであるかのように振る舞うことができますが、管理者のコンテキストは維持されます。

アクティビティ図

---
config:
  theme: base
  layout: dagre
  flowchart:
    curve: linear
    htmlLabels: true
  themeVariables:
    edgeLabelBackground: "transparent"
---
flowchart TB
    %% Main components
    AdminUser[管理者ユーザー]
    AdminDashboard[管理者ダッシュボード]
    Database[(データベース)]
    
    %% Process steps with numbering
    AdminUser --- Step1[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
            <p style='margin-top: 8px'>グループ/ユーザー選択</p>
        </div>
    ]
    Step1 --> SelectGroup[グループ/ユーザー選択]
    
    SelectGroup --- Step2[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
            <p style='margin-top: 8px'>リクエスト送信</p>
        </div>
    ]
    Step2 --> SendRequest[代理ログインリクエスト送信]
    
    SendRequest --- Step3[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
            <p style='margin-top: 8px'>グループ検証</p>
        </div>
    ]
    Step3 --> GroupIDCheck{有効なグループID?}
    
    GroupIDCheck -->|いいえ| Step4A[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4A</span>
            <p style='margin-top: 8px'>エラー返却</p>
        </div>
    ]
    Step4A --> ReturnError[エラー返却]
    
    GroupIDCheck -->|はい| Step4B[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4B</span>
            <p style='margin-top: 8px'>ステータス確認</p>
        </div>
    ]
    Step4B --> CheckStatus[グループステータス確認]
    CheckStatus --> Database
    
    CheckStatus --- Step5[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
            <p style='margin-top: 8px'>アクティブ確認</p>
        </div>
    ]
    Step5 --> GroupActiveCheck{グループアクティブ?}
    
    GroupActiveCheck -->|いいえ| Step6A[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6A</span>
            <p style='margin-top: 8px'>エラー返却</p>
        </div>
    ]
    Step6A --> ReturnError
    
    GroupActiveCheck -->|はい| Step6B[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6B</span>
            <p style='margin-top: 8px'>作成者検索</p>
        </div>
    ]
    Step6B --> FindCreator[グループ作成者検索]
    FindCreator --> Database
    
    FindCreator --- Step7[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
            <p style='margin-top: 8px'>作成者確認</p>
        </div>
    ]
    Step7 --> CreatorCheck{作成者あり?}
    
    CreatorCheck -->|いいえ| Step8A[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8A</span>
            <p style='margin-top: 8px'>エラー返却</p>
        </div>
    ]
    Step8A --> ReturnError
    
    CreatorCheck -->|はい| Step8B[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8B</span>
            <p style='margin-top: 8px'>セッション作成</p>
        </div>
    ]
    Step8B --> CreateSession[代理セッション作成]
    
    CreateSession --- Step9[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>9</span>
            <p style='margin-top: 8px'>Cookie設定</p>
        </div>
    ]
    Step9 --> SetCookie[代理Cookie設定]
    
    SetCookie --- Step10[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10</span>
            <p style='margin-top: 8px'>データ返却</p>
        </div>
    ]
    Step10 --> ReturnData[作成者コンテキスト付きユーザーデータ返却]
    
    ReturnData --- Step11[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>11</span>
            <p style='margin-top: 8px'>ユーザーとして閲覧</p>
        </div>
    ]
    Step11 --> UserView[ユーザーとしてアプリケーション閲覧]
    
    UserView --- Step12[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>12</span>
            <p style='margin-top: 8px'>戻る確認</p>
        </div>
    ]
    Step12 --> ReturnCheck{管理者に戻る?}
    
    ReturnCheck -->|はい、ID=0| Step13A[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>13A</span>
            <p style='margin-top: 8px'>セッションクリア</p>
        </div>
    ]
    Step13A --> ClearSession[代理セッションクリア]
    
    ClearSession --- Step14[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>14</span>
            <p style='margin-top: 8px'>管理者に戻る</p>
        </div>
    ]
    Step14 --> ReturnAdmin[管理者コンテキストに戻る]
    
    ReturnAdmin --- Step15[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>15</span>
            <p style='margin-top: 8px'>ダッシュボードに戻る</p>
        </div>
    ]
    Step15 --> AdminDashboard
    
    ReturnCheck -->|いいえ、継続| Step13B[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>13B</span>
            <p style='margin-top: 8px'>セッション継続</p>
        </div>
    ]
    Step13B --> UserView
    
    %% Styling
    style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    style AdminDashboard fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    style SelectGroup fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style SendRequest fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style GroupIDCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
    style CheckStatus fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style GroupActiveCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
    style FindCreator fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style CreatorCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
    style CreateSession fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style SetCookie fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ReturnData fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style UserView fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ReturnCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
    style ClearSession fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ReturnAdmin fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ReturnError fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
    style Database fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
    
    style Step1 fill:transparent,stroke:transparent,stroke-width:1px
    style Step2 fill:transparent,stroke:transparent,stroke-width:1px
    style Step3 fill:transparent,stroke:transparent,stroke-width:1px
    style Step4A fill:transparent,stroke:transparent,stroke-width:1px
    style Step4B fill:transparent,stroke:transparent,stroke-width:1px
    style Step5 fill:transparent,stroke:transparent,stroke-width:1px
    style Step6A fill:transparent,stroke:transparent,stroke-width:1px
    style Step6B fill:transparent,stroke:transparent,stroke-width:1px
    style Step7 fill:transparent,stroke:transparent,stroke-width:1px
    style Step8A fill:transparent,stroke:transparent,stroke-width:1px
    style Step8B fill:transparent,stroke:transparent,stroke-width:1px
    style Step9 fill:transparent,stroke:transparent,stroke-width:1px
    style Step10 fill:transparent,stroke:transparent,stroke-width:1px
    style Step11 fill:transparent,stroke:transparent,stroke-width:1px
    style Step12 fill:transparent,stroke:transparent,stroke-width:1px
    style Step13A fill:transparent,stroke:transparent,stroke-width:1px
    style Step13B fill:transparent,stroke:transparent,stroke-width:1px
    style Step14 fill:transparent,stroke:transparent,stroke-width:1px
    style Step15 fill:transparent,stroke:transparent,stroke-width:1px

API: 代理ログインAPI

ケースドキュメント

ケース1: 代理ログイン成功

説明

管理者がグループメンバーの代理として正常にログインします。

シーケンス図

sequenceDiagram
    participant Admin as 管理者
    participant API as 代理ログインコントローラー
    participant Service as 認証サービス
    participant GroupService
    participant DB as データベース

    Note over Admin,API: ステップ1: 代理リクエスト送信
    Admin->>API: PATCH /api/v1/admin/auth/representative/{id}
    
    Note over API,API: ステップ2: 管理者認証確認
    API->>API: 管理者が認証済みか確認
    
    Note over API,GroupService: ステップ3: グループ読込
    API->>GroupService: getById(id)
    GroupService->>DB: グループ検索
    DB-->>GroupService: グループデータ返却
    
    Note over API,API: ステップ4: グループステータス確認
    API->>API: グループがアクティブか確認
    
    Note over API,Service: ステップ5: 代理セッション作成
    API->>Service: createRepresentative(group.creator)
    Service->>Service: 認証Cookie生成
    
    Note over API,Admin: ステップ6: レスポンス返却
    API-->>Admin: 200 OK (作成者データと代理Cookie)

ステップ

ステップ1: 代理リクエスト送信

  • 説明: 管理者がグループの代理として行動するリクエストを送信
  • リクエスト: PATCH /api/v1/admin/auth/representative/{id}
  • URLパラメータ:
    • id: 代理するグループのID (必須)
  • 認証:
    • 管理者が既に認証済みである必要がある

ステップ2: 管理者認証確認

  • 説明: システムが管理者が認証済みであることを確認
  • アクション:
    • ユーザーがログインしているか確認
    • 認証状態を確認
  • 潜在的エラー:
    • 認証チェック失敗 (403 禁止)

ステップ3: グループ読込

  • 説明: システムがリクエストされたグループを取得
  • アクション:
    • IDでグループを取得するためのグループサービス呼び出し
    • 作成者リレーションシップを持つグループをロード
  • 潜在的エラー:
    • グループが見つからない

ステップ4: グループステータス確認

  • 説明: グループがアクティブで代理可能であることを確認
  • アクション:
    • グループステータスがアクティブであることを確認
    • グループに作成者が割り当てられていることを確認
  • 潜在的エラー:
    • グループが非アクティブ (403 禁止)

ステップ5: 代理セッション作成

  • 説明: グループ作成者として行動するためのセッション作成
  • アクション:
    • 代理セッションを作成する認証サービスの呼び出し
    • 代理コンテキスト用の認証Cookie生成
    • 代理フラグをtrueに設定

ステップ6: レスポンス返却

  • 説明: 代理セッションで成功レスポンスを送信
  • レスポンス:
    • 成功: 200 OK (作成者ユーザーデータ付き)
    • 代理Cookieを設定
    • 必要なリレーションシップ(ロール、グループ)を含める

関連するデータベーステーブルとフィールド

erDiagram
    users {
        id bigint "主キー"
        name string "ユーザーのフルネーム"
        email string "ユーザーのメールアドレス (ユニーク)"
        uid string "Firebase UID (ユニーク)"
        payment_provider_customer_id string "決済プロバイダーの顧客ID (nullable)"
        status int "アカウントステータス (0: 非アクティブ, 1: アクティブ)"
        is_first_login int "初回ログインフラグ (0: まだ, 1: ログイン済)"
        remember_token string "記憶トークン"
        created_at timestamp "レコード作成タイムスタンプ"
        updated_at timestamp "レコード最終更新タイムスタンプ"
        deleted_at timestamp "ソフト削除タイムスタンプ"
    }
    groups {
        id bigint "主キー"
        name string "グループ名"
        created_by bigint "usersテーブルへの参照"
        status int "グループステータス (0: 非アクティブ, 1: アクティブ)"
        created_at timestamp "レコード作成タイムスタンプ"
        updated_at timestamp "レコード最終更新タイムスタンプ"
    }
    group_members {
        id bigint "主キー"
        user_id bigint "usersテーブルへの参照"
        group_id bigint "groupsテーブルへの参照"
        group_role_id bigint "group_rolesテーブルへの参照"
        is_creator boolean "グループ作成者フラグ"
        joined_at timestamp "メンバー参加タイムスタンプ"
        created_at timestamp "レコード作成タイムスタンプ"
        updated_at timestamp "レコード最終更新タイムスタンプ"
    }
    group_roles {
        id bigint "主キー"
        name string "ロール名"
        slug string "ロールスラッグ"
        created_at timestamp "レコード作成タイムスタンプ"
        updated_at timestamp "レコード最終更新タイムスタンプ"
    }

    users ||--o{ group_members : has
    groups ||--o{ group_members : has
    group_roles ||--o{ group_members : has

エラー処理

  • ログ

    • 代理ログイン失敗を記録
    • グループステータスの問題を記録
  • エラー詳細:

    コード メッセージ 説明
    401 "ログイン情報が正しくありません。" 管理者ロールにユーザーが見つからない場合
    401 "認証情報と一致するレコードがありません。" ログインに失敗した場合
    401 "問題が発生しました。申し訳ございませんが、もう一度お試しください。" 予期しないエラーが発生した場合

ケース2: 管理者アカウントに戻る

説明

代理管理者が元の管理者アカウントに戻ります。

シーケンス図

sequenceDiagram
    participant Admin as 管理者
    participant API as 代理ログインコントローラー
    participant Auth
    participant Cookie

    Admin->>API: PATCH /api/v1/admin/auth/representative/0
    API->>Auth: 現在のユーザーを取得
    Auth-->>API: 管理者ユーザーを返却
    API->>Cookie: forget(representative)
    API-->>Admin: 200 OK (管理者ユーザーデータ)

ステップ

ステップ1: 戻りリクエスト送信

  • 説明: 管理者が管理者アカウントに戻るリクエストを送信
  • リクエスト: PATCH /api/v1/admin/auth/representative/0
  • URLパラメータ:
    • id: 0 (管理者に戻ることを示す特別な値)

ステップ2: 代理フラグリセット

  • 説明: システムが代理ステータスをクリア
  • アクション:
    • 代理フラグをfalseに設定
    • 変更なしで現在の管理者ユーザーを使用

ステップ3: 代理Cookieクリア

  • 説明: 代理コンテキストCookieを削除
  • アクション:
    • 代理Cookie用の「忘れる」Cookieを作成
    • 過去の有効期限でCookieを設定

ステップ4: レスポンス返却

  • 説明: 管理者コンテキストを復元
  • レスポンス:
    • 成功: 200 OK (管理者ユーザーデータ付き)
    • Cookieクリア指示を含める

追加事項

  • 代理ログイン機能は、管理者の実際のアイデンティティと代理ユーザーの間に明確な区別を維持します
  • システムはCookieを使用して代理状態を追跡します
  • 代理として行動している場合、特定の管理機能が制限される場合があります
  • 管理者モードに戻るのは管理者機能を完全に復元する簡単なプロセスです
  • グループ作成者のみが代理可能で、任意のグループメンバーではありません