Eviworx
Docs

Users, Roles & Agent Groups API

Diese API umfasst User-Management, dynamisches Role-Based Access Control (RBAC), die Manager-Hierarchie (Organigramm), Agents inkl. Agent-Groups mit Assignment-Strategien sowie Specialties (Skill-Routing). Das Auth-/Permission-Modell selbst ist zentral beschrieben unter Permissions & RBAC.

Abwesenheiten/Vertretung (mit Manager-Genehmigung) sind eine eigene Domain: Absences API. Rechte-Auflösung, Cache & kritische Aktionen: Permissions & RBAC.

👥
Funktionen
✓ Dynamische Rollen (eigenes Rechte-Set + Priorität)
✓ Manager-Hierarchie & Organigramm
✓ Anlegen per Einladung
✓ Archivieren mit Übergabe an Nachfolger
✓ Agent Groups (4 Zuweisungs-Strategien)
✓ Specialties für Skill-Routing (SKILL_BASED)
✓ E-Mail-only-Kontakte (ohne Portal-Login)
✓ EntraID/SSO (Gruppe → Rolle)

Vorinstallierte Rollen

Neben den System-Rollen lassen sich beliebig viele Custom-Rollen anlegen, jede mit eigenem Permission-Set und einer Priorität (Reihenfolge/Vorrang). System-Rollen (isSystem) lassen sich weder deaktivieren noch löschen noch verschieben. Vorinstalliert sind die vier System-Rollen und die Rolle DATA_PROTECTION_OFFICER, die als Custom-Rolle angelegt ist:

RoleZweck
END_USERKunde/Requester — eigene Tickets
AGENTSupport-Agent — alle Tickets/Problems verwalten
ADMINAdministrator — voller Zugriff
APPROVERChange-Approver
DATA_PROTECTION_OFFICERDatenschutzbeauftragter (DSGVO: Breach-Details, Incident-Einsicht, Audit); Custom-Rolle, isSystem = false

User-Endpoints /api/users

MethodEndpointBeschreibung
GET/Liste (Filter/Suche); anonymisierte User default ausgeblendet — includeAnonymized=true nur für die Verwaltung
GET/statsCounts pro Rolle
GET/assignable?entityType=Zuweisbare Kandidaten je Entity-Art (TICKET, PROBLEM, CHANGE, INCIDENT, WORKFLOW) — mit ?groupId, ?search, ?take/skip
GET/approvers?entityType=Users mit Approve-Recht (CHANGE, CHANGE_TEMPLATE, INCIDENT)
GET/checkout-recipientsEmpfänger für Asset-Checkout
GET/check-emailE-Mail-Verfügbarkeit prüfen
GET/:idEinzelner User
POST/User erstellen (mit Einladung); eine Einladung verlangt ein aktives Konto — sonst 400 INVITATION_ACCOUNT_NOT_ACTIVE
PATCH/:idUser aktualisieren (inkl. roleId)
PATCH/:id/profileProfil/Status (isActive …)
POST/:id/promoteE-Mail-Kontakt zum Nutzer befördern (Portal-Zugang, optional neue Rolle); verlangt ein aktives Konto — sonst 400 PROMOTE_ACCOUNT_NOT_ACTIVE
POST/:id/resend-invitationEinladung erneut senden; verlangt ein aktives Konto — sonst 400 INVITATION_ACCOUNT_NOT_ACTIVE
GET / PUT/:id/languageSprache (de, en, es, fr, it)
GET/:id/archival-checkPrüft, ob archivierbar
POST/:id/archive-with-transferArchivieren + Items übertragen

Anzeige-Einstellungen des Benutzers: Sprache, Zeitzone und Datumsform gehören dem Benutzer selbst — die Sprache über /:id/language, Zeitzone und Datumsform über das eigene Profil (PUT /api/auth/profile). Sie wirken in der Oberfläche und ebenso in den Texten, die der Server erzeugt: E-Mail, Push, Teams und Webex. Eine Nachricht erreicht den Empfänger damit in seiner Sprache, mit seinen Uhrzeiten und in seiner Datumsform, unabhängig davon, wer sie ausgelöst hat. Welche Stufe greift, wenn nichts gesetzt ist.

Hinweis: Für Benutzer gibt es keinen DELETE-Endpoint. Sie werden über /:id/profile deaktiviert (isActive=false) oder über /:id/archive-with-transfer archiviert (Items gehen an einen Nachfolger).

Drei Kontozustände: Ein Konto ist aktiv, gesperrt oder archiviert — archiviert heißt IMMER gesperrt. Wer nur isArchived: true sendet, bekommt isActive: false still dazu; wer isActive: true an einem archivierten Konto verlangt, bekommt 400 ARCHIVED_USER_CANNOT_BE_ACTIVE. Reaktiviert wird mit beiden Feldern in EINEM Request (isArchived: false, isActive: true). So fällt ein archiviertes Konto überall heraus, wo nur aktive Konten zählen: bei Benachrichtigungen, in Workflows und beim Verzeichnis-Sync. Gesperrte und archivierte Konten können sich auf keinem Weg anmelden (403 ACCOUNT_DEACTIVATED); ein Login ändert den Status nie, Ent-archivieren geht nur über PATCH /:id/profile mit users.archive.

In der Schnittstelle tragen die drei Zustände die Werte ACTIVE, INACTIVE und ARCHIVED. Die Benutzer-Liste grenzt darauf ein — entweder über den Parameter ?status=ACTIVE|INACTIVE|ARCHIVED oder über das Filterfeld f.accountStatus=eq:ACTIVE, das mit in: auch mehrere Stufen auf einmal nimmt (f.accountStatus=in:INACTIVE,ARCHIVED). Die Schreibweise ist verbindlich: ein abweichender Wert ist 400. Denselben Wert trägt customer.accountStatus in den Ticket-Antworten.

Ein gesperrtes oder archiviertes Konto kann nicht Kunde eines neuen Tickets werden und auch nicht Nachfolger beim Archivieren (400 SUCCESSOR_NOT_ACTIVE). Eine eingehende E-Mail an ein archiviertes Konto ändert seinen Status NICHT — sie verschiebt nur die Löschfrist, denn ein Statuswechsel ist eine Verwaltungsentscheidung: Er erfordert eine Berechtigung, wird auditiert und kann Vorgesetzten-Beziehungen übertragen.

Ein gesperrtes Konto nennt die Herkunft seiner Sperre: managedProfile.lockSource ist ADMIN (Verwaltung), ENTRA_SYNC (Verzeichnis-Sync) oder SYSTEM. Bei einem aktiven Konto ist das Feld null. Es beantwortet die Frage, wer die Sperre wieder aufheben kann — der Verzeichnis-Sync hebt nur seine eigenen Sperren auf.

Eine Statusänderung wirkt sofort: Mit der Sperre enden alle Zugänge des Kontos — laufende Sitzungen, Refresh-Token, Push-Abos und offene Echtzeit-Verbindungen; der Rechte-Cache wird geleert. Das gilt für jeden Weg, der den Status schreibt: Anlegen, Bearbeiten, Profil, Archivieren mit Nachfolger, Verzeichnis-Sync und Anonymisierung. Einladung und Beförderung verlangen deshalb ein aktives Konto (400 INVITATION_ACCOUNT_NOT_ACTIVE bzw. PROMOTE_ACCOUNT_NOT_ACTIVE) — ein Einrichtungs-Link an ein gesperrtes Konto würde ins Leere laufen.

Zweiter Faktor am Konto: Jede Benutzer-Antwort trägt secondFactor mit genau drei Werten: LOCAL (am Konto ist ein zweiter Faktor eingerichtet), ENTRA (die Anmeldung läuft über Microsoft — ein lokaler zweiter Faktor ist dort nicht möglich) und NONE (lokal möglich, aber nicht eingerichtet). Gefiltert wird mit f.secondFactor=eq:LOCAL, mehrere Werte mit in:. Die Benutzer-Liste kann den zweiten Faktor als eigene Spalte zeigen; sie ist nicht voreingestellt und wird über die Spaltenauswahl eingeblendet.

Die mitgelieferte Sicherheits-Ansicht „Ohne 2FA" zeigt die aktiven Anmeldekonten mit NONE; reine E-Mail-Kontakte bleiben außen vor. Konten mit Microsoft-Anmeldung stehen nicht darin: Bei ihnen kann lokal nichts fehlen, der zweite Faktor liegt im Verzeichnis.

Geschützte Konten: Zwei Konten hält die Plattform für sich selbst: das interne System-Konto, unter dem automatisierte Vorgänge laufen, und den lokalen Notzugang, über den die Verwaltung auch bei einem Ausfall der Microsoft-Anmeldung hereinkommt. Beide lassen sich nicht sperren, nicht archivieren, nicht anonymisieren und nicht mit einer Lösch-Sperre versehen; ihre Rolle ist fest. Solche Eingriffe antworten 403 PROTECTED_ACCOUNT, und details.operation nennt den abgelehnten Eingriff (status, archive, role oder erase). Der Verzeichnis-Sync verknüpft beide Konten nie (Konfliktcode PROTECTED_ACCOUNT), und das System-Konto meldet sich auf keinem Weg an. Die Oberfläche kennzeichnet diese Konten und bietet die gesperrten Aktionen gar nicht erst an. Profildaten, Passwort und Zwei-Faktor-Anmeldung des Notzugangs bleiben änderbar.

Rollen-Zuweisung am Konto: Eine roleId setzen POST /, PATCH /:id und /:id/promote — dabei gelten drei Grenzen. Die Rolle eines synchronisierten Kontos gehört dem Verzeichnis: Ein Rollenwechsel wird mit 403 ROLE_MANAGED_BY_ENTRA_ID abgewiesen, solange das Konto in einer zugeordneten Rollen-Gruppe steht (bei entraIDConflict = true bleibt sie manuell setzbar, weil der Sync sie dort nicht überschreibt). Eine Rolle ohne nutzbare Rechte — deaktiviert oder mit ungültiger Rechte-Matrix — lässt sich nicht zuweisen: 400 ROLE_NOT_ASSIGNABLE mit details.roleName, denn das Konto wäre danach an jeder Stelle abgewiesen, ohne dass es gesperrt wäre. Und niemand vergibt eine Rolle mit höheren Privilegien als der eigenen (403).

Sichtbarkeit vor Handlungsrecht: Jede Route auf einen bestimmten Benutzer (PATCH /:id, /:id/profile, /:id/language, /:id/promote, /:id/resend-invitation, /:id/archival-check, /:id/archive-with-transfer, Manager-Routen, Hierarchie-Reads) prüft zuerst, ob der Aufrufer diesen Benutzer überhaupt sehen darf — das eigene Konto oder users.viewAll. Eine Rolle mit users.edit oder users.archive, aber ohne users.viewAll, wirkt damit ausschließlich auf das eigene Profil; alles andere ist 403.

Archivieren verlangt users.archive; nur wenn dabei wirklich Manager-Beziehungen übertragen werden, kommt users.manageManagers hinzu. users.archive und agents.manageGroups sind kritische Aktionen: Ihre Rechte werden frisch aus der Datenbank geprüft und Erfolge wie abgelehnte Versuche auditiert.

Kandidaten-Listen erfordern ein Recht an der Ziel-Domäne: /assignable verlangt ein Recht an der ZIEL-Domäne — viewAll, editAll oder assign der jeweiligen Entity-Art (bei WORKFLOW: editTemplates, createTemplates oder reassignSteps). editOwn genügt bewusst NICHT, sonst könnte jeder Endanwender die Agenten-Liste abfragen. /approvers verlangt das Genehmigungsrecht der Entity-Art (z.B. changes.approve, incidents.approveClosure) oder editAll/editOwn. Rollen ohne diese Rechte erhalten 403.

Manager-Hierarchie

MethodEndpointBeschreibung
GET/:id/managersManager eines Users
POST/:id/managersManager zuweisen
PATCH/:id/managers/:managerIdBeziehung aktualisieren
DELETE/:id/managers/:managerIdManager entfernen
GET/:id/subordinatesDirekte Untergebene
GET/:id/hierarchyVollständiges Organigramm (rekursiv)

Die Manager-Hierarchie ist Basis für Eskalationen (Assignee→Lead→Manager) und die Genehmigung von Abwesenheiten.

User erstellen

POST /api/users
{
  "email": "agent@company.com",
  "name": "John Support",
  "roleId": "clx-role-agent",
  "managedProfile": { "firstName": "John", "lastName": "Support", "department": "IT", "location": "Munich" }
  // without password → invitation flow (password setup via link); see Authentication
}

E-Mail-only-Kontakte (autoCreatedFromEmail/emailOnlyContact) entstehen automatisch beim E-Mail-Eingang (Sender-Policy AUTO_CREATE): ein Konto ohne Passwort und ohne Anmeldung. Wie viele solche Kontakte an einem Tag entstehen dürfen, steht als Feld am Postfach (Standard 100). Ist die Grenze erreicht, bleibt die Mail offen und wird nach Mitternacht (UTC) verarbeitet — abgelehnt wird sie nicht. Siehe E-Mail-System.

Rollen (RBAC) /api/roles

MethodEndpointBeschreibung
GET/Alle Rollen (mit Permission-Matrix; settings.manageRoles). page/limit werden geprüft: limit höchstens 200, unbrauchbare Werte sind 400
GET/assignableSchlanke Zuweisungs-Liste für den User-Editor (id/name/displayName/color); erfordert users.manageRoles; enthält nur aktive Rollen, die der Aufrufer vergeben darf (Privileg-Decke)
GET/:idRolle (mit Permission-Matrix)
POST/Custom-Rolle erstellen
PATCH/:idPermissions aktualisieren
DELETE/:idCustom-Rolle löschen → 204. Nicht möglich bei System-Rollen, bei Rollen mit Nutzern und bei Rollen, an denen ein AKTIVER API-Key hängt (der Key würde sonst ohne Rolle mit 403 API_KEY_NO_ROLE abgewiesen).
GET/permissions/schemaPermission-Schema (für UI)
POST/:id/moveRolle in der Prioritäts-Reihenfolge verschieben — GENAU eine Seite angeben (afterRoleId ODER beforeRoleId); beides oder nichts ist 400

Fehlercodes der Rollen-Verwaltung

errorCodeHTTPBedeutung
ROLE_NOT_FOUND404Keine Rolle mit dieser ID
ROLE_NAME_EXISTS409Der Name ist bereits vergeben
ROLE_IN_USE409Die Rolle hängt noch an Nutzern oder an aktiven API-Keys — details.users und details.activeApiKeys nennen die Zahlen
SYSTEM_ROLE_PROTECTED400System-Rollen lassen sich weder deaktivieren noch löschen noch verschieben
ROLE_PERMISSIONS_INVALID400Die Matrix enthält unbekannte Module oder Aktionen bzw. Nicht-Boolesche Werte
ROLE_LOCKOUT403settings.manageRoles darf nicht aus einer System-Rolle, der eigenen Rolle oder der LETZTEN Rolle entfernt werden, die es trägt — sonst wäre die Rollenverwaltung dauerhaft ausgesperrt. details.reason nennt den Fall.
ROLE_NOT_ASSIGNABLE403Privileg-Decke: niemand vergibt eine Rolle mit Rechten, die er selbst nicht hat. details.reason unterscheidet ROLE_NOT_FOUND und PERMISSION_NOT_HELD (mit details.permission).

Eine Rolle deaktivieren beendet den Zugang ihrer Nutzer: Mit dem Umschalten auf isActive: false verlieren alle Konten dieser Rolle sofort ihre laufenden Sitzungen, Refresh-Token, Push-Abos und offenen Echtzeit-Verbindungen; eine erneute Anmeldung antwortet 403 NO_USABLE_ROLE. Die Konten selbst bleiben aktiv — die Ursache liegt an der Rolle, und die Meldung sagt das auch so. Die Oberfläche verlangt deshalb eine Bestätigung, sobald die Rolle noch Nutzer trägt; sie nennt deren Anzahl und weist darauf hin, dass die Betroffenen keine Benachrichtigung darüber erhalten.

Eine Rolle trägt eine Permission-Matrix über 29 Module (tickets, problems, changes, incidents, assets, inventory, contracts, licenses, costCenters, knowledgeBase, elibrary, workflows, cronjobs, settings, users, agents, notifications, audit, analytics, absences, customReports, savedViews, …). Wie Rechte aufgelöst, gecacht (pro Rolle) und bei kritischen Aktionen frisch validiert werden, steht zentral unter Permissions & RBAC.

POST /api/roles
{
  "name": "level2-agent",
  "displayName": "Level 2 Agent",
  "description": "Agent with change approval",
  "priority": 45000,
  "permissions": {
    "tickets":  { "viewAll": true, "create": true, "editAll": true, "assign": true },
    "changes":  { "viewAll": true, "approve": true, "reject": true }
    // more modules …
  }
}

Agents /api/agents

Das Agent-Profil ergänzt einen User um Support-spezifische Daten (Workload, isActive, Specialties).

MethodEndpointBeschreibung
GET/api/agentsAgents auflisten ({data, pagination}); ?forEntityType=TICKET|PROBLEM|CHANGE|INCIDENT|WORKFLOW filtert auf die zuweisbaren
POST/api/agentsAgent-Profil anlegen ({userId, isActive})
PATCH/api/agents/:userIdAgent aktualisieren: isActive und/oder maxWorkload
DELETE/api/agents/:userIdAgent-Profil entfernen

Agents werden überall über die userId adressiert: in Pfaden, Eingaben und Responses. Eingaben werden strikt geprüft; unbekannte Felder und unbekannte Query-Werte (z.B. ein falscher forEntityType) ergeben 400.

Agent Groups

Gruppen routen Arbeit an Agents. applicableEntityTypes (Array) legt fest, für welche Entity-Arten die Gruppe als Queue dient, assignmentStrategy bestimmt die Auswahl. Mit Group-Access lässt sich pro Gruppe einschränken, wer sie sieht/zugewiesen bekommt.

AspektWerte
applicableEntityTypes (String[])TICKET, PROBLEM, CHANGE, INCIDENT, WORKFLOW (Default: alle fünf)
assignmentStrategyFIRST_AVAILABLE, ROUND_ROBIN, LEAST_LOADED, SKILL_BASED
MethodEndpoint
GET/api/agents/groups · /groups/:id
POST / PATCH/api/agents/groups · /groups/:id
POST/api/agents/groups/:id/archive · /restore
GET/api/agents/groups/:id/potential-members (Server-Suche: ?search=, ?take/skip, ?excludeAbsent, ?excludeInactive)
POST / DELETE / PATCH/api/agents/groups/:groupId/members/:userId (PATCH: isTeamLead und/oder isActive → 204)
GET / POST/api/agents/groups/:id/access (Zugriffsregeln)
DELETE/api/agents/groups/:id/access/:accessId
PUT/api/agents/groups/:id/restriction (Zugriff ein/aus)
  • Die Gruppen-Liste liefert per Default nur aktive, nicht archivierte Gruppen (für Auswahllisten). Die Verwaltung setzt ?includeInactive=true und bekommt inaktive und archivierte dazu; der Einzel-Lookup /groups/:id löst auch inaktive Gruppen auf, damit bestehende Zuweisungen sichtbar bleiben. Weitere Query-Params: ?forEntityType=, ?search=.
  • Berechtigungen: Gruppen lesen = users.viewAgents · Gruppen/Mitglieder/Specialties verwalten = agents.manageGroups · Zugriffsregeln = agents.manageGroupAccess. Jede Gruppe trägt in der Antwort canManageMembers für den anfragenden Benutzer (agents.manageGroups oder aktiver TeamLead dieser Gruppe) — die Mitglieder-Aktionen der UI hängen daran.
  • Ein Zugriffs-Eintrag gehört zu genau einer Gruppe: ein zweiter Grant für denselben Benutzer bzw. dieselbe Rolle ist 409 ACCESS_ALREADY_GRANTED, und ein DELETE über eine fremde Gruppen-URL ist 404.

Specialties /api/agents/specialties

Skills/Fachgebiete für SKILL_BASED-Routing. CRUD + Zuordnung zu Agents:

MethodEndpoint
GET/ (?includeInactive=true für die Verwaltung) · /:id · /agent/:userId
POST / PATCH / DELETE/ · /:id
POST / DELETE/:id/agents/:userId (Skill zuordnen/entfernen, proficiency 1–5)

Die eigenen Skills darf jeder lesen (/agent/:userId ohne users.viewAgents); fremde Skills verlangen users.viewAgents. Gepflegt werden Skills mit agents.manageGroups oder als aktiver TeamLead einer Gruppe, in der der Ziel-Agent Mitglied ist.

Ohne Pflege-Recht keine Auskunft über die Existenz: Beim Zuordnen eines Skills wird das Recht VOR der Existenzprüfung geprüft. Wer nicht pflegen darf, bekommt daher 403 — auch für eine Specialty, die es gar nicht gibt. Die Antwort verrät so nicht, welche Skills im System angelegt sind. Dasselbe gilt beim Ändern eines Agenten: ohne jede Pflege-Fähigkeit antwortet die Route 403, bevor sie nach dem Agenten sucht.

Fehlercodes der Agent-Verwaltung

Jeder Code steht auf der obersten Ebene der Antwort als errorCode. Bei den 403 der Handler-Gates — Agent ändern, Workload-Grenze, TeamLead vergeben, Mitglied pausieren, Skills pflegen — nennt details.required das verlangte Recht (bzw. die verlangte TeamLead-Beziehung).

errorCodeHTTPBedeutung
AGENT_NOT_FOUND404Kein Agent zu dieser userId — beim Ändern und Entfernen des Profils, beim Entfernen aus einer Gruppe und beim Entziehen eines Skills
AGENT_GROUP_NOT_FOUND404Gruppe unbekannt — beim Einzel-Lookup, den Kandidaten, den Zugriffsregeln, der Zugriffs-Sperre und beim Aufnehmen eines Mitglieds
AGENT_GROUP_MEMBER_NOT_FOUND404Der Agent ist in dieser Gruppe kein Mitglied (Mitglieds-Einstellungen ändern)
AGENT_GROUP_ACCESS_NOT_FOUND404Zugriffs-Eintrag unbekannt — auch dann, wenn er zu einer anderen Gruppe gehört
AGENT_SPECIALTY_NOT_FOUND404Specialty unbekannt — beim Einzel-Lookup und beim Zuordnen eines Skills
NOT_FOUND404Der allgemeine Code: Gruppe ändern, archivieren oder wiederherstellen sowie Specialty ändern oder löschen antworten mit ihm, wenn das Ziel nicht existiert
AGENT_ALREADY_EXISTS409Für diesen Benutzer gibt es bereits ein Agent-Profil
ACCESS_ALREADY_GRANTED409Dieser Benutzer bzw. diese Rolle hat für die Gruppe schon einen Zugriffs-Eintrag
DUPLICATE_ENTRY409Gruppen- und Specialty-Namen sind eindeutig
ENTITY_TYPE_REMOVAL_BLOCKED409Eine Entity-Art lässt sich nicht aus der Gruppe nehmen, solange offene Vorgänge dieser Art der Gruppe zugewiesen sind — details.conflicts nennt Art und Anzahl
AGENT_HAS_TICKETS400Das Profil trägt noch zugewiesene Tickets (details.ticketCount)
USER_NEEDS_AGENT_PERMISSIONS400Ein Agent braucht ein Zuweisungs-Recht (tickets.assign oder problems.assign); ohne das gibt es weder Profil noch Mitgliedschaft
FORBIDDEN403Ein Handler-Gate hat abgelehnt; details.required nennt das verlangte Recht

Verweigerte Gates der Agent-Verwaltung, die am kritischen Recht agents.manageGroups hängen — TeamLead vergeben, Mitglied pausieren, Workload-Grenze, Skill-Zuordnung —, werden zusätzlich auditiert.

Abwesenheit & Verfügbarkeit

Zuweisbarkeit berücksichtigt Abwesenheiten: Die Kandidaten-Listen markieren abwesende Agents (isAbsent; der Abwesenheitsgrund wird nicht ausgegeben, da er Gesundheitsdaten enthalten kann), und ist ein Ziel-Agent abwesend, greift die Vertreter-Umleitung (Substitute) zum Zuweisungszeitpunkt (override per ignoreSubstitution). Deaktivierte und archivierte Konten sind nie Kandidaten. Verwaltung der Abwesenheiten (inkl. Manager-Genehmigung) auf der eigenen Seite: Absences API.

👥
Kernprinzipien
  • ✓ Frei definierbare Rollen mit Priorität
  • ✓ Manager-Hierarchie & Organigramm
  • ✓ Agent-Groups: Queue, Zuweisungsstrategie, Zugriffsregeln
  • ✓ Archivieren mit Übertragung an einen Nachfolger
🔐
Berechtigungen (RBAC)
  • users.viewAll / create / edit / manageRoles
  • settings.manageRoles – Rollen/Permissions
  • agents.* – Agents & Groups

Auth-/Rollenmodell: Permissions & RBAC

Verwandte Dokumentation