Developer Guide
This guide covers the technical implementation of Access Control for CX Assistants, including data models, the access check logic, and API reference.
Architecture Overview
Access Control restricts which users can access specific Assistants through a group-based permission system:
Data Model
AssistantUserGroup
Groups that can be assigned to both users and Assistants to control access.
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Auto | Primary key |
name | string | Yes | Unique group name (max 255 characters) |
users | ManyToMany | No | Users who belong to this group |
created_at | datetime | Auto | Timestamp when the group was created |
updated_at | datetime | Auto | Timestamp when the group was last updated |
Django Model Definition:
class AssistantUserGroup(TimestampedModel):
name = models.CharField(
max_length=255,
unique=True,
error_messages={"unique": "Group with this name already exists."}
)
class Meta:
verbose_name = "User Group"
verbose_name_plural = "User Groups"
Assistant (Access Control Fields)
The Assistant model includes group-based authorization:
| Field | Type | Description |
|---|---|---|
authorized_groups | ManyToMany | Groups that have access to this Assistant |
Django Model Definition (relevant excerpt):
class Assistant(TimestampedModel):
# ... other fields ...
authorized_groups = models.ManyToManyField(
"assistants.AssistantUserGroup",
blank=True,
related_name="authorized_assistants"
)
CustomUser (Group Membership)
Users are assigned to groups through the assistant_user_groups field:
| Field | Type | Description |
|---|---|---|
assistant_user_groups | ManyToMany | Groups the user belongs to |
Django Model Definition (relevant excerpt):
class CustomUser(AbstractBaseUser, PermissionsMixin):
# ... other fields ...
assistant_user_groups = models.ManyToManyField(
"assistants.AssistantUserGroup",
blank=True,
related_name="users"
)
User (Domain Model)
The internal domain representation used during evaluation:
class User(BaseModel):
user_id: int
assistant_groups: list[int] = []
Access Control Logic
user_has_access Method
The user_has_access method on the Assistant domain model determines whether a user can access the Assistant:
def user_has_access(self, user: User) -> bool:
if not self.authorized_groups:
return True
return any(group in user.assistant_groups for group in self.authorized_groups)
Logic:
- If the Assistant has no
authorized_groupsconfigured, all users have access - If
authorized_groupsare configured, the user must belong to at least one of those groups
Evaluation Check
The access check is performed in the AssistantEvaluator._evaluate_assistant method:
if user is not None and not assistant.user_has_access(user):
logger.info(
"Assistant %s: user cannot access (evaluation trace ID: %s)",
assistant.code,
evaluation_trace_id
)
return USER_HAS_NO_ACCESS_MESSAGE, evaluation_id, EvaluationStatus.NO_ACCESS_TO_ASSISTANT
Constants:
USER_HAS_NO_ACCESS_MESSAGE = "User has no access to this assistant."EvaluationStatus.NO_ACCESS_TO_ASSISTANT- Returned when access is denied
User Group Resolution
When evaluating an Assistant, the user's groups are retrieved from the database:
class UserRepository:
async def get_user(self, user_uuid: str) -> User:
orm_user = await orm.CustomUser.objects.filter(uuid=user_uuid).afirst()
if not orm_user:
raise ValueError(f"User with UUID {user_uuid} not found")
return User(
user_id=orm_user.id,
assistant_groups=[group.id async for group in orm_user.assistant_user_groups.all()],
)
API Reference
Assistant User Groups API
CRUD operations for managing user groups.
List Groups
GET /api/v1/assistants/user-groups/
Response:
[
{
"id": 1,
"name": "Pilot Group",
"users": [
{
"id": 42,
"email": "agent@example.com",
"first_name": "John",
"last_name": "Doe"
}
],
"assistants": [
{
"id": 10,
"code": "support-assistant",
"name": "Support Assistant"
}
]
}
]
Create Group
POST /api/v1/assistants/user-groups/
Request Body:
{
"name": "Technical Support",
"users": [42, 43, 44]
}
Update Group
PUT /api/v1/assistants/user-groups/{id}/
Request Body:
{
"name": "Technical Support Team",
"users": [42, 43, 44, 45]
}
Delete Group
DELETE /api/v1/assistants/user-groups/{id}/
Deleting a group immediately removes access for all users in that group to any Assistants that only authorized that group.
Evaluation Response
When a user lacks access to an Assistant, the evaluation endpoint returns:
{
"output": "User has no access to this assistant.",
"evaluation_id": "abc-123",
"evaluation_status": "no_access_to_assistant"
}
Integration with On-Demand Assistants
For on-demand Assistants displayed in the UI, the profile serializer filters Assistants based on user group membership:
if user and user.assistant_user_groups.exists():
assistant_user_group_ids = list(user.assistant_user_groups.values_list("id", flat=True))
assistant_id_list += list(
Assistant.authorized_groups.through.objects.filter(
assistantusergroup_id__in=assistant_user_group_ids
).values_list("assistant_id", flat=True)
)
This ensures users only see Assistants they have access to in the frontend.
Access Control Matrix
| Assistant Config | User Groups | Result |
|---|---|---|
| No authorized groups | Any | Access granted |
| Groups: [A, B] | User in [A] | Access granted |
| Groups: [A, B] | User in [B, C] | Access granted |
| Groups: [A, B] | User in [C, D] | Access denied |
| Groups: [A] | User in [] | Access denied |
Source Code References
| Component | Location |
|---|---|
| AssistantUserGroup model | assistants/models.py:291-301 |
| Assistant.authorized_groups | assistants/models.py:221-222 |
| CustomUser.assistant_user_groups | dashboard/models/custom_user.py:53 |
| User domain model | backend/domains/assistants/models/user.py |
| user_has_access method | backend/domains/assistants/models/assistant.py:150-154 |
| Access check in evaluator | backend/domains/assistants/services/evaluate.py:188-192 |
| UserRepository | backend/domains/assistants/repositories/user.py |
| AssistantUserGroupViewSet | assistants/views.py:385-390 |
Related Documentation
- Overview: Conceptual overview of Access Control
- User Guide: Configuration instructions
- Assistants Developer Guide: Full Assistant evaluation flow