User Roles & Permissions
UALS implements a three-tier role system for class management that balances flexibility, security, and accountability. Understanding these roles is critical for effective collaboration.
The Three Roles
Original Creator
The teacher who initially created the class. This role is permanently assigned and never changes, even after ownership transfers.
Immutable Audit Trail Historical RecordCurrent Owner
The teacher with full administrative control over the class. This role can be transferred to another teacher, but only with their explicit acceptance.
Full Control Transferable AdministrativeContent Expert
Teachers invited to collaborate on content creation and editing. They have content-only access and cannot modify class settings or invite others.
Content Only Class-Specific Invited RoleDetailed Permission Breakdown
Original Creator Permissions
Current Owner Permissions
Content Expert Permissions
How Roles Are Assigned
Original Creator - Automatic at Class Creation
When you create a new class, you are automatically designated as the Original Creator. This assignment is permanent and stored in the xAPI statement with extension fields:
{
"http://uals.app/class/creator-email": "teacher@school.edu",
"http://uals.app/class/creator-name": "Dr. Jane Smith"
}
Current Owner - Initially Same as Creator
When you create a class, you start as both Creator and Owner. The owner can change through ownership transfer, but the creator never changes.
{
"http://uals.app/class/teacher-email": "teacher@school.edu",
"http://uals.app/class/teacher-name": "Dr. Jane Smith"
}
Content Expert - Invited by Owner
The current owner can invite content experts by entering their email address. The invited expert will see the class appear in their "Content Expert Invitations" section.
{
"http://uals.app/class/content-experts": "[\"expert1@school.edu\",\"expert2@university.edu\"]"
}
Common Scenarios
Scenario 1: Teacher Leaves Institution
Situation: Dr. Smith created a class but is leaving the school. She wants Dr. Johnson to take over.
Solution:
- Dr. Smith initiates ownership transfer to Dr. Johnson's email
- Dr. Johnson sees pending transfer on dashboard and accepts
- Dr. Johnson becomes the new owner with full control
- Dr. Smith remains listed as Original Creator for records
- Dr. Smith loses all owner permissions immediately
- Optional: Dr. Johnson can re-invite Dr. Smith as content expert if needed
Scenario 2: Collaborative Content Development
Situation: Prof. Anderson owns a Computer Science class and wants Prof. Williams (subject matter expert) to help improve assessment items.
Solution:
- Prof. Anderson opens class details and clicks "Invite Content Expert"
- Enters Prof. Williams' email and submits
- Prof. Williams sees invitation on their dashboard
- Prof. Williams clicks "Edit Content" and reviews/edits assessment items
- Prof. Anderson retains full owner permissions
- Both can see each other's edits through version history
Scenario 3: Removing a Collaborator
Situation: A content expert's contract ends and they should no longer have access to class content.
Solution:
- Class owner opens class details modal
- Clicks "Show Content Experts" to expand the list
- Clicks the "Remove" button next to the expert's email
- Confirms the removal
- Expert immediately loses content editing access
- Expert's email removed from contentExperts array in xAPI
- Class no longer appears in expert's invitation list
Scenario 4: Former Owner Becomes Content Expert
Situation: Dr. Lee transferred ownership to Dr. Kim but still wants to contribute content improvements.
Solution:
- Dr. Lee transfers ownership to Dr. Kim (loses all permissions)
- Dr. Kim accepts ownership
- Dr. Kim invites Dr. Lee as content expert
- Dr. Lee regains content editing access (but not administrative control)
- Dr. Lee remains Original Creator in system records
Permission Matrix
Quick reference table for all three roles:
| Permission | Creator | Owner | Expert |
|---|---|---|---|
| Edit cached content | ❌ | ✅ | ✅ |
| View assessment answers | ❌ | ✅ | ✅ |
| Modify class settings | ❌ | ✅ | ❌ |
| Invite content experts | ❌ | ✅ | ❌ |
| Remove content experts | ❌ | ✅ | ❌ |
| Transfer ownership | ❌ | ✅ | ❌ |
| View student analytics | ❌ | ✅ | ❌ |
| Delete/archive class | ❌ | ✅ | ❌ |
| Listed in audit trail | ✅ | ✅ | ✅ |
| Role is transferable | ❌ | ✅ | N/A |
Best Practices
- Only invite content experts you trust completely
- Review the content experts list periodically and remove inactive members
- Communicate clearly with experts about their role and responsibilities
- Use ownership transfer only when permanent handoff is needed
- Before transferring, ensure the new owner accepts the responsibility
- Remember you can see assessment answers - maintain academic integrity
- Coordinate with the class owner before making major content changes
- Use version control features to track your edits
- Respect the owner's pedagogical approach and goals
- If you need more permissions, discuss ownership transfer with current owner
- Assuming creator role grants editing permissions after ownership transfer
- Sharing content expert access with unauthorized individuals
- Transferring ownership without communicating with the new owner first
- Forgetting to remove content experts who no longer need access
- Confusing "creator" with "owner" - they are different roles!
Technical Implementation
For developers: Role information is stored in xAPI LRS statements with the following extension fields:
{
"extensions": {
"http://uals.app/class/creator-email": "original@school.edu",
"http://uals.app/class/creator-name": "Dr. Original Creator",
"http://uals.app/class/teacher-email": "current@school.edu",
"http://uals.app/class/teacher-name": "Dr. Current Owner",
"http://uals.app/class/content-experts": "[\"expert1@school.edu\",\"expert2@university.edu\"]",
"http://uals.app/class/ownership-transfer-pending": null
}
}
Permission checks in backend code:
async function canEditClassContent(userEmail, classId) {
const classData = await getClassData(classId);
const classOwnerEmail = classData.teacherEmail;
if (classOwnerEmail && userEmail === classOwnerEmail) {
return true;
}
const contentExperts = classData.contentExperts || [];
if (contentExperts.includes(userEmail)) {
return true;
}
return false;
}