Representative Login

Overview Description

The Representative Login feature enables administrators to temporarily assume the identity of a group member for support and troubleshooting purposes. This capability allows administrators to view the application exactly as a specific user would see it, facilitating more effective support and issue resolution. When an administrator uses this feature, they maintain their administrative context while interacting with the system as if they were the selected user.

Activity Diagram

---
config:
  theme: base
  layout: dagre
  flowchart:
    curve: linear
    htmlLabels: true
  themeVariables:
    edgeLabelBackground: "transparent"
---
flowchart TB
    %% Main components
    AdminUser[Admin User]
    AdminDashboard[Admin Dashboard]
    Database[(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'>Select Group/User</p>
        </div>
    ]
    Step1 --> SelectGroup[Select Group/User]
    
    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'>Send Request</p>
        </div>
    ]
    Step2 --> SendRequest[Send Representative Login Request]
    
    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'>Validate Group</p>
        </div>
    ]
    Step3 --> GroupIDCheck{Valid Group ID?}
    
    GroupIDCheck -->|No| 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'>Return Error</p>
        </div>
    ]
    Step4A --> ReturnError[Return Error]
    
    GroupIDCheck -->|Yes| 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'>Check Status</p>
        </div>
    ]
    Step4B --> CheckStatus[Check Group Status]
    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'>Verify Active</p>
        </div>
    ]
    Step5 --> GroupActiveCheck{Group Active?}
    
    GroupActiveCheck -->|No| 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'>Return Error</p>
        </div>
    ]
    Step6A --> ReturnError
    
    GroupActiveCheck -->|Yes| 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'>Find Creator</p>
        </div>
    ]
    Step6B --> FindCreator[Find Group Creator]
    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'>Verify Creator</p>
        </div>
    ]
    Step7 --> CreatorCheck{Creator Found?}
    
    CreatorCheck -->|No| 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'>Return Error</p>
        </div>
    ]
    Step8A --> ReturnError
    
    CreatorCheck -->|Yes| 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'>Create Session</p>
        </div>
    ]
    Step8B --> CreateSession[Create Representative Session]
    
    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'>Set Cookie</p>
        </div>
    ]
    Step9 --> SetCookie[Set Representative 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'>Return Data</p>
        </div>
    ]
    Step10 --> ReturnData[Return User Data with Creator Context]
    
    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'>View as User</p>
        </div>
    ]
    Step11 --> UserView[View Application as User]
    
    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'>Return Check</p>
        </div>
    ]
    Step12 --> ReturnCheck{Return to Admin?}
    
    ReturnCheck -->|Yes, 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'>Clear Session</p>
        </div>
    ]
    Step13A --> ClearSession[Clear Representative Session]
    
    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'>Return Admin</p>
        </div>
    ]
    Step14 --> ReturnAdmin[Return to Admin Context]
    
    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'>Return Dashboard</p>
        </div>
    ]
    Step15 --> AdminDashboard
    
    ReturnCheck -->|No, Continue| 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'>Continue Session</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: Representative Login API

Case Documentation

Case 1: Successful Representative Login

Description

Administrator successfully logs in as a representative of a group member.

Sequence Diagram

sequenceDiagram
    participant Admin
    participant API as RepresentativeLoginController
    participant Service as AuthService
    participant GroupService
    participant DB as Database

    Note over Admin,API: Step 1: Submit Representative Request
    Admin->>API: PATCH /api/v1/admin/auth/representative/{id}
    
    Note over API,API: Step 2: Verify Admin Authentication
    API->>API: Check Admin is Authenticated
    
    Note over API,GroupService: Step 3: Load Group
    API->>GroupService: getById(id)
    GroupService->>DB: Find Group
    DB-->>GroupService: Return Group Data
    
    Note over API,API: Step 4: Check Group Status
    API->>API: Verify Group is Active
    
    Note over API,Service: Step 5: Create Representative Session
    API->>Service: createRepresentative(group.creator)
    Service->>Service: Generate Auth Cookie
    
    Note over API,Admin: Step 6: Return Response
    API-->>Admin: 200 OK with creator data and representative cookie

Steps

Step 1: Submit Representative Request

  • Description: Admin requests to act as a representative for a group
  • Request: PATCH /api/v1/admin/auth/representative/{id}
  • URL Parameters:
    • id: The ID of the group to represent (required)
  • Authentication:
    • Admin must be already authenticated

Step 2: Verify Admin Authentication

  • Description: System confirms admin is authenticated
  • Action:
    • Check if user is logged in
    • Verify authentication status
  • Potential errors:
    • Authentication check failure (403 Forbidden)

Step 3: Load Group

  • Description: System retrieves the requested group
  • Action:
    • Call group service to get group by ID
    • Load group with creator relationship
  • Potential errors:
    • Group not found

Step 4: Check Group Status

  • Description: Verify group is active and can be represented
  • Action:
    • Check group status is Active
    • Ensure group has creator assigned
  • Potential errors:
    • Group is inactive (403 Forbidden)

Step 5: Create Representative Session

  • Description: Create session for acting as the group creator
  • Action:
    • Call auth service to create representative session
    • Generate authentication cookie for representative context
    • Set representative flag to true

Step 6: Return Response

  • Description: Send successful response with representative session
  • Response:
    • Success: 200 OK with creator user data
    • Set representative cookie
    • Include necessary relationships (roles, group)

Database Related Tables & Fields

erDiagram
    users {
        id bigint "Primary key"
        name string "User's full name"
        email string "User's email address (unique)"
        uid string "Firebase UID (unique)"
        payment_provider_customer_id string "Payment provider customer ID (nullable)"
        status int "Account status (0: Inactive, 1: Active)"
        is_first_login int "First login flag (0: not yet, 1: logged in)"
        remember_token string "Remember token"
        created_at timestamp "Record creation timestamp"
        updated_at timestamp "Record last update timestamp"
        deleted_at timestamp "Soft delete timestamp"
    }
    groups {
        id bigint "Primary key"
        name string "Group name"
        created_by bigint "Reference to users table"
        status int "Group status (0: Inactive, 1: Active)"
        created_at timestamp "Record creation timestamp"
        updated_at timestamp "Record last update timestamp"
    }
    group_members {
        id bigint "Primary key"
        user_id bigint "Reference to users table"
        group_id bigint "Reference to groups table"
        group_role_id bigint "Reference to group_roles table"
        is_creator boolean "Is group creator flag"
        joined_at timestamp "Member joined timestamp"
        created_at timestamp "Record creation timestamp"
        updated_at timestamp "Record last update timestamp"
    }
    group_roles {
        id bigint "Primary key"
        name string "Role name"
        slug string "Role slug"
        created_at timestamp "Record creation timestamp"
        updated_at timestamp "Record last update timestamp"
    }

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

Error Handling

  • Log

    • Representative login failures logged
    • Group status issues recorded
  • Error Detail:

    Code Message Description
    401 "ログイン情報が正しくありません。" When user is not found in admin role
    401 "認証情報と一致するレコードがありません。" When login fails
    401 "問題が発生しました。申し訳ございませんが、もう一度お試しください。" When unexpected errors occur

Case 2: Return to Admin Account

Description

Representative admin returns to their original admin account.

Sequence Diagram

sequenceDiagram
    participant Admin
    participant API as RepresentativeLoginController
    participant Auth
    participant Cookie

    Admin->>API: PATCH /api/v1/admin/auth/representative/0
    API->>Auth: Get current user
    Auth-->>API: Return admin user
    API->>Cookie: forget(representative)
    API-->>Admin: 200 OK with admin user data

Steps

Step 1: Submit Return Request

  • Description: Admin requests to return to admin account
  • Request: PATCH /api/v1/admin/auth/representative/0
  • URL Parameters:
    • id: 0 (special value to indicate return to admin)

Step 2: Reset Representative Flag

  • Description: System clears representative status
  • Action:
    • Set representative flag to false
    • Use current admin user without changes

Step 3: Clear Representative Cookie

  • Description: Remove representative context cookie
  • Action:
    • Create "forget" cookie for representative cookie
    • Set cookie with past expiration

Step 4: Return Response

  • Description: Restore admin context
  • Response:
    • Success: 200 OK with admin user data
    • Include cookie clearing instruction

Additional Notes

  • The representative login feature maintains a clear distinction between the admin's actual identity and the represented user
  • The system uses cookies to track the representative state
  • When acting as a representative, certain administrative functions may be limited
  • Returning to admin mode is a simple process that fully restores admin capabilities
  • Only the group creator can be represented, not arbitrary group members