From a953c51c10b9fa15825e24731752b5c0c14f23b9 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Sun, 7 Dec 2025 13:48:52 +0100
Subject: [PATCH] refactored uam to rbac
---
appdoc/doc_gateway_import_map.drawio | 2 +-
appdoc/doc_security_role_based_access.md | 768 +++++++++++++-----
...y_role_based_access_implementation_plan.md | 574 +++++++++++++
3 files changed, 1150 insertions(+), 194 deletions(-)
create mode 100644 appdoc/doc_security_role_based_access_implementation_plan.md
diff --git a/appdoc/doc_gateway_import_map.drawio b/appdoc/doc_gateway_import_map.drawio
index 5d0f1ad..b79bd96 100644
--- a/appdoc/doc_gateway_import_map.drawio
+++ b/appdoc/doc_gateway_import_map.drawio
@@ -1 +1 @@
-5Vldk5owFP01Pm4nEBT3cVf3ozPdJ6fT9jGGi7BG4sSg0l/fsCaaALYda8FRXuCem5DknOTey9DDo8X2RZBl8sYjYD0fRdseHvd83wuDgbqVSLFD/BDf75CZSCPd6gBM0p+gQaTRPI1g5TSUnDOZLl2Q8iwDKh2MCME3brOYM3fUJZlBDZhQwurotzSSiUYDhA6OV0hniRkaGc+CmNYaWCUk4hsLwk89PBKcy93TYjsCVtJniNn1ez7i3c9MQCb/pgNJKRew67UmLAcXftazlIVZu+B5FkHZ2+vhx02SSpgsCS29GyW3whK5YNodp4yNOOPioy+O4xgDUvhKCj4HywODviJp7zGs+uU7eCYnenzP2Lst4QXKrq9Yk7AGIWFrQZqBF+ALkKJQTYzXG2o59I7EWNsbS14jWWIpO9AY0Ttqtn/3gXP1oGlvlmAFYp1StZ+rIhwc55UhGiIU4iYZHvoIBafJUNqu1Oo6jzz3yFXHb1OdNJMgYtKkj+26bYWC0FUoHLSo0PwtGMsB+fw6HxZfKY2meZzf9Wt6QKRiuDYznqnboysRFzLhM54R9oXzpQbfQcpCs0hyyV3ZFGOi+K4MZIwfpfGpb8zx1naOC225skYQk5zJj1bRQ5mfFDhlnM4bdVaNnlNmprBbZ7m4oxlAQyueC7oPLTQXqSx08iRiBrIejep6C2BEpmt3rH8LfvZEnOBnHOfOQTAFaDpa09CjHu0qB/X77hHyUItHKAYic9EQ4g6O2w5wQ89V5y5oUZ0NF/OYlVVrVR7Lc159AMV+7DXpo9SJTtTnf1RqrR4TxahsOCQGPnOgohAAbZJgOEQQxF1JEODKUfDblKBMdIOaAn8g/oTM3ph2q7nZzcTv+WJpuCeC/o5tNxXb5b+diu1vs0qCbyEzlyMOb4TpapHfDdued1V0V0m9rK3tXdvePlbQX8beNuxeCd1uwXzs+6kzsoMbIbtSGXfEdv+q2K5wellR2w9vhetLiCOm0r8Stu3PN5tqN750RPV11X7HqL6MYgRfVzFyjGy3JuyIanwjVLcarZV5+EX84bN+teOnXw==
\ No newline at end of file
+7Zpbc9o6EMc/DXOe2pHxBfKYQC+Z0860k/Zc+tIR0hq7CIvKcoB++koggS+iTVrHcOA4D0G7siz/f9JqZbvnj+arVwIvkrecAuv1EV31/HGv3/e8KFD/tGVtLeHV1jIVKTW2veEu/QbGiIy1SCnklYqScybTRdVIeJYBkRUbFoIvq9VizqpXXeApNAx3BLOm9e+UysRYA4T2jteQThN7aWQ9c2xrG0OeYMqXJZP/ouePBOdy+2u+GgHT8llhtue9PODd9UxAJh9ywugr//yJfi7e/3kl3/8lrpMP3tdn/W0r95gV5o6Nklzkuqltz+Xa6iF4kVHQLXo9/2aZpBLuFpho71INAWVL5JwZd5wyNuKMi825Png0hIGy51LwGZQ8V9HAx9HOY5Xu6zZ4Ju/M9T1b3g4TL1Bl038QElYHhfF2cquRCnwOUqxVFXPCDqYZpEFgyssScUsxKcGOjA2bQTbdNb3HoH4YEo+g4jWofLz9I28VBsUwjIkLRkSGMIlPBUa/QxY4JVxAQ3trbnc2xDFMAFwAJgOPeOQ3ADTUdjA5CGAfwdY1Il0gyEHcpwTyBoS9o+Wg5JOhukEHhht0FZY8j8Ggy6WW0OZoB8+wPj/8DumkmQQRYxefsqtdQhFGKI5dhPwBQqNRG4TizdEOofCY82f2NhjLCN++ng3XHwmhkyIunoUNHkBVlmOKGc90GKoi4kImfMozzN5wvjDGLyDl2qiIC8mr2JRiYv2PKiBb+FcXnoe2OF6VneO1KVWxUohxweSmFr3WGZwyThgnMydnVellymwXDtLLeSHILpKQQqRyKyuSWExBuoKP1uiHvAUwLNP7aqb4e8Gv3LNK8LOOy1iDomMGuRiwLIQjxO0dlx3gGhlC1CGdJRezmOl9XR1PyXPZKUKDT6fTRyktHZPHmttFg1CIwDl1EPLGNyc3deq5QZczR69nUYPLT3D8Qh7gXKTrK3l13f5SzBeWCBbk4St5eb0ur+TlnVz367i+4vBClK5vCY6jttd8YvJflrsu6mkNbe/cxvah/cBpjG2r7pnIXU2vT2n7tRE7uBCxa3n0kdQOz0rtmqanFbX7g0vR+hTiiN1xnYna5U1dWepqfDmS1OeV+x2S+jSSEf+8kpFDYldzwiNJ7V+I1MeN1s4X8E3pKZZ4rr9vaf0ZVhzqP9czrGhztPEMa3v0nuQNfeh4RT/o9HOJZs6eJ+p26P+k6k8bj03qAfm+aiVd5KC1TPBCGwnjBf05rCcQLHAM7cihV/BUejVz9ut3tz+QrAOJhrXZ31QodCjkP14hVdx/HLfxlT4y9F98Bw==
\ No newline at end of file
diff --git a/appdoc/doc_security_role_based_access.md b/appdoc/doc_security_role_based_access.md
index 34864c1..f68f194 100644
--- a/appdoc/doc_security_role_based_access.md
+++ b/appdoc/doc_security_role_based_access.md
@@ -4,6 +4,13 @@
This document describes the implementation of a comprehensive Role-Based Access Control (RBAC) system that addresses the critical database efficiency issues identified in the [Database Efficiency Analysis](../DATABASE_EFFICIENCY_ANALYSIS.md). The new system moves access control logic from Python to the database level, providing granular permissions while dramatically improving performance.
+The RBAC system extends beyond data access control to include:
+- **Data Access Control**: Table and field-level permissions for database operations
+- **UI Access Control**: Component and feature visibility management
+- **Resource Access Control**: System resource availability (AI models, actions, etc.)
+
+Users can have multiple roles that are combined using opening (union) logic, where permissions from all roles are combined and the most permissive access is granted.
+
## Problem Statement
The current User Access Management (UAM) system has significant performance bottlenecks:
@@ -17,7 +24,9 @@ The current User Access Management (UAM) system has significant performance bott
The new RBAC system implements a **matrix-based access model** with database-level filtering, providing:
-- **Granular Permissions**: Table and field-level access control
+- **Granular Permissions**: Table and field-level access control for data
+- **UI Access Control**: Fine-grained control over UI elements and features
+- **Resource Access Control**: Manage access to system resources (e.g., AI models, actions)
- **Role-Based Security**: Centralized permission management
- **Database Optimization**: Filtering at database level
- **Mandate Isolation**: Secure multi-tenant access
@@ -27,16 +36,52 @@ The new RBAC system implements a **matrix-based access model** with database-lev
### Core Components
-1. **Role Management**: Define roles with mandate scope
-2. **Access Rules**: Matrix of permissions per role/table/field
-3. **Database Integration**: Native filtering in SQL queries
-4. **Migration Strategy**: Seamless transition from current UAM
+1. **Role Management**: Define roles with mandate scope (users can have multiple roles)
+2. **Access Rules**: Matrix of permissions per role/context/item
+3. **Context Types**: DATA (database tables/fields), UI (interface elements), RESOURCE (system resources)
+4. **Database Integration**: Native filtering in SQL queries for DATA context
+5. **UI Integration**: Component visibility and feature access control
+6. **Migration Strategy**: Seamless transition from current UAM
## Data Models
+### Frontend Options Format
+
+The `frontend_options` attribute in Field definitions supports two formats:
+
+1. **Static List** (for basic data types): A list of option dictionaries
+ ```python
+ frontend_options=[
+ {"value": "a", "label": {"en": "All Records", "fr": "Tous les enregistrements"}},
+ {"value": "m", "label": {"en": "My Records", "fr": "Mes enregistrements"}}
+ ]
+ ```
+
+2. **String Reference** (for custom types): A string identifier that references dynamic options
+ ```python
+ frontend_options="user.role" # Frontend fetches from /api/options/user.role
+ ```
+
+**Dynamic Options API**: When `frontend_options` is a string reference, the frontend must fetch options from `/api/options/{optionsName}`. This allows for:
+- Database-driven options (e.g., user connections loaded from database)
+- Context-aware options (e.g., options filtered by current user's permissions)
+- Centralized option management (e.g., role definitions managed in one place)
+
+**Available Option Names**:
+- `"user.role"` - User role options (sysadmin, admin, user, viewer)
+- `"user.connection"` - User connection types
+- `"auth.authority"` - Authentication authorities
+- `"connection.status"` - Connection statuses
+
### Access Rule Model
```python
+class AccessRuleContext(str, Enum):
+ """Context type enumeration"""
+ DATA = "DATA" # Database tables and fields
+ UI = "UI" # UI elements and features
+ RESOURCE = "RESOURCE" # System resources (AI models, actions, etc.)
+
class AccessRule(BaseModel, ModelMixin):
"""Data model for access control rules"""
id: str = Field(
@@ -51,72 +96,82 @@ class AccessRule(BaseModel, ModelMixin):
frontend_type="select",
frontend_readonly=False,
frontend_required=True,
+ frontend_options="user.role"
+ )
+ context: AccessRuleContext = Field(
+ description="Context type: DATA (database), UI (interface), RESOURCE (system resources)",
+ frontend_type="select",
+ frontend_readonly=False,
+ frontend_required=True,
frontend_options=[
- {"value": "sysadmin", "label": {"en": "System Administrator", "fr": "Administrateur système"}},
- {"value": "admin", "label": {"en": "Administrator", "fr": "Administrateur"}},
- {"value": "user", "label": {"en": "User", "fr": "Utilisateur"}},
- {"value": "viewer", "label": {"en": "Viewer", "fr": "Observateur"}}
+ {"value": "DATA", "label": {"en": "Data", "fr": "Données"}},
+ {"value": "UI", "label": {"en": "UI", "fr": "Interface"}},
+ {"value": "RESOURCE", "label": {"en": "Resource", "fr": "Ressource"}}
]
)
- tableName: Optional[str] = Field(
+ item: Optional[str] = Field(
None,
- description="Name of the database table (null = all tables)",
+ description="Item identifier (null = all items in context). Format: DATA: '' or '.', UI: cascading string (e.g., 'playground.voice.settings'), RESOURCE: cascading string (e.g., 'ai.model.anthropic')",
frontend_type="text",
frontend_readonly=False,
frontend_required=False
)
- fieldName: Optional[str] = Field(
+ view: bool = Field(
+ False,
+ description="View permission: if true, item is visible/enabled. Only objects with view=true are shown.",
+ frontend_type="checkbox",
+ frontend_readonly=False,
+ frontend_required=True
+ )
+ read: Optional[AccessLevel] = Field(
None,
- description="Specific field name (null = entire table, requires tableName)",
- frontend_type="text",
- frontend_readonly=False,
- frontend_required=False
- )
- read: AccessLevel = Field(
- description="Read permission level",
+ description="Read permission level (only for DATA context)",
frontend_type="select",
frontend_readonly=False,
- frontend_required=True,
+ frontend_required=False,
frontend_options=[
{"value": "a", "label": {"en": "All Records", "fr": "Tous les enregistrements"}},
{"value": "m", "label": {"en": "My Records", "fr": "Mes enregistrements"}},
- {"value": "g", "label": {"en": "Mandate Records", "fr": "Enregistrements du mandat"}},
+ {"value": "g", "label": {"en": "Group Records", "fr": "Enregistrements du groupe"}},
{"value": "n", "label": {"en": "No Access", "fr": "Aucun accès"}}
]
)
- create: AccessLevel = Field(
- description="Create permission level",
+ create: Optional[AccessLevel] = Field(
+ None,
+ description="Create permission level (only for DATA context)",
frontend_type="select",
frontend_readonly=False,
- frontend_required=True,
+ frontend_required=False,
frontend_options=[
{"value": "a", "label": {"en": "All Records", "fr": "Tous les enregistrements"}},
{"value": "m", "label": {"en": "My Records", "fr": "Mes enregistrements"}},
- {"value": "g", "label": {"en": "Mandate Records", "fr": "Enregistrements du mandat"}},
+ {"value": "g", "label": {"en": "Group Records", "fr": "Enregistrements du groupe"}},
{"value": "n", "label": {"en": "No Access", "fr": "Aucun accès"}}
]
)
- update: AccessLevel = Field(
- description="Update permission level",
+ update: Optional[AccessLevel] = Field(
+ None,
+ description="Update permission level (only for DATA context)",
frontend_type="select",
frontend_readonly=False,
- frontend_required=True,
+ frontend_required=False,
frontend_options=[
{"value": "a", "label": {"en": "All Records", "fr": "Tous les enregistrements"}},
{"value": "m", "label": {"en": "My Records", "fr": "Mes enregistrements"}},
- {"value": "g", "label": {"en": "Mandate Records", "fr": "Enregistrements du mandat"}},
+ {"value": "g", "label": {"en": "Group Records", "fr": "Enregistrements du groupe"}},
{"value": "n", "label": {"en": "No Access", "fr": "Aucun accès"}}
]
)
- delete: AccessLevel = Field(
- description="Delete permission level",
+ delete: Optional[AccessLevel] = Field(
+ None,
+ description="Delete permission level (only for DATA context)",
frontend_type="select",
frontend_readonly=False,
- frontend_required=True,
+ frontend_required=False,
frontend_options=[
{"value": "a", "label": {"en": "All Records", "fr": "Tous les enregistrements"}},
{"value": "m", "label": {"en": "My Records", "fr": "Mes enregistrements"}},
- {"value": "g", "label": {"en": "Mandate Records", "fr": "Enregistrements du mandat"}},
+ {"value": "g", "label": {"en": "Group Records", "fr": "Enregistrements du groupe"}},
{"value": "n", "label": {"en": "No Access", "fr": "Aucun accès"}}
]
)
@@ -129,64 +184,130 @@ class AccessLevel(str, Enum):
"""Access level enumeration"""
ALL = "a" # All records
MY = "m" # My records (created by me)
- MANDATE = "g" # Mandate records (my mandate)
+ GROUP = "g" # Group records (group context is the mandate)
NONE = "n" # No access
```
+### User Permissions Model
+
+```python
+class UserPermissions(BaseModel):
+ """User permissions model for RBAC"""
+ view: bool = Field(
+ default=False,
+ description="View permission: if true, item is visible/enabled"
+ )
+ read: AccessLevel = Field(
+ default=AccessLevel.NONE,
+ description="Read permission level"
+ )
+ create: AccessLevel = Field(
+ default=AccessLevel.NONE,
+ description="Create permission level"
+ )
+ update: AccessLevel = Field(
+ default=AccessLevel.NONE,
+ description="Update permission level"
+ )
+ delete: AccessLevel = Field(
+ default=AccessLevel.NONE,
+ description="Delete permission level"
+ )
+```
+
### Updated User Model
```python
class User(BaseModel, ModelMixin):
# ... existing fields ...
- roleLabel: str = Field(
- description="Role label assigned to this user",
- frontend_type="select",
+ roleLabels: List[str] = Field(
+ default_factory=list,
+ description="List of role labels assigned to this user. All roles are opening roles (union) - if one role enables something, it is enabled.",
+ frontend_type="multiselect",
frontend_readonly=False,
frontend_required=True,
- frontend_options=[
- {"value": "sysadmin", "label": {"en": "System Administrator", "fr": "Administrateur système"}},
- {"value": "admin", "label": {"en": "Administrator", "fr": "Administrateur"}},
- {"value": "user", "label": {"en": "User", "fr": "Utilisateur"}},
- {"value": "viewer", "label": {"en": "Viewer", "fr": "Observateur"}}
- ]
+ frontend_options="user.role"
)
# ... rest of existing fields ...
```
+**Note on `frontend_options`**: The `frontend_options` attribute can be either:
+- **Static list** (for basic data types): A list of option dictionaries with `value` and `label` keys
+- **String reference** (for custom types): A string identifier (e.g., `"user.role"`, `"user.connection"`) that references dynamic options loaded from the API
+
+For custom types like `"user.role"` or `"user.connection"`, the frontend must fetch the options from the API endpoint `/api/options/{optionsName}`. The API will return the options list dynamically, allowing for:
+- Database-driven options (e.g., user connections loaded from database)
+- Context-aware options (e.g., options filtered by current user's permissions)
+- Centralized option management (e.g., role definitions managed in one place)
+
## Access Control Logic
### Rule Hierarchy and Specificity
-The AccessRule system supports a three-level hierarchy for maximum flexibility:
+The AccessRule system supports a cascading hierarchy based on the `item` field:
-1. **Generic Rules** (`tableName = null`, `fieldName = null`): Apply to all tables and fields
-2. **Table Rules** (`tableName = "UserInDB"`, `fieldName = null`): Apply to all fields in a specific table
-3. **Field Rules** (`tableName = "UserInDB"`, `fieldName = "email"`): Apply to a specific field in a specific table
+#### For DATA Context:
+1. **Generic Rules** (`item = null`): Apply to all tables and fields
+2. **Table Rules** (`item = "UserInDB"`): Apply to all fields in a specific table
+3. **Field Rules** (`item = "UserInDB.email"`): Apply to a specific field in a specific table
-**Rule Resolution Order** (most specific wins):
-1. Field-specific rule for the exact table and field
-2. Table-specific rule for the exact table
-3. Generic rule for all tables
+#### For UI Context:
+1. **Generic Rules** (`item = null`): Apply to all UI elements
+2. **Component Rules** (`item = "playground"`): Apply to entire component
+3. **Feature Rules** (`item = "playground.voice"`): Apply to feature within component
+4. **Element Rules** (`item = "playground.voice.settings"`): Apply to specific UI element
+
+#### For RESOURCE Context:
+1. **Generic Rules** (`item = null`): Apply to all resources
+2. **Category Rules** (`item = "ai"`): Apply to resource category
+3. **Type Rules** (`item = "ai.model"`): Apply to resource type
+4. **Specific Rules** (`item = "ai.model.anthropic"`): Apply to specific resource
+
+**Rule Resolution Order** (most specific wins within a role):
+1. Most specific item match (longest matching prefix) - **This overrides generic rules**
+2. Generic rule for the context (`item = null`) - **Only applies if no specific rule exists**
+
+**Important Logic**: Within a single role, the most specific rule always wins. If a generic rule has `view: true` but a specific rule has `view: false`, then `view: false` applies (the specific rule overrides the generic).
**Examples:**
-- Generic rule: `{roleLabel: "viewer", tableName: null, fieldName: null, read: "g"}` - Viewers can read mandate records in all tables
-- Table rule: `{roleLabel: "admin", tableName: "UserInDB", fieldName: null, read: "a"}` - Admins can read all users
-- Field rule: `{roleLabel: "user", tableName: "UserInDB", fieldName: "email", read: "m"}` - Users can only read their own email
+- DATA Generic: `{roleLabel: "viewer", context: "DATA", item: null, read: "g"}` - Viewers can read group records in all tables (group context is the mandate)
+- DATA Table: `{roleLabel: "admin", context: "DATA", item: "UserInDB", read: "a"}` - Admins can read all users (overrides generic rule for UserInDB table)
+- DATA Field: `{roleLabel: "user", context: "DATA", item: "UserInDB.email", read: "m"}` - Users can only read their own email (overrides table-level rule for email field)
+- UI Component: `{roleLabel: "user", context: "UI", item: "playground", view: true}` - Users can view playground component
+- UI Feature Override: `{roleLabel: "user", context: "UI", item: null, view: true}` + `{roleLabel: "user", context: "UI", item: "playground.voice.settings", view: false}` - Generic allows all UI, but specific rule hides voice settings (specific wins: `view: false`)
+- RESOURCE: `{roleLabel: "user", context: "RESOURCE", item: "ai.model.anthropic", view: true}` - Users can access Anthropic AI model
-### Opening Rights Principle
+### View Attribute
-The system implements **opening rights** where read permission (`R`) is a prerequisite for create/update/delete operations (`CUD`):
+The `view` attribute controls visibility and enablement across all contexts:
+
+- **For DATA Context**: Controls whether the table/field is accessible (in addition to read/create/update/delete permissions)
+- **For UI Context**: Controls whether UI elements are visible/enabled. Only objects with `view: true` are shown.
+- **For RESOURCE Context**: Controls whether resources are accessible. Only resources with `view: true` are available.
+
+**Key Rule**: Only objects with `view: true` are enabled/visible. If `view: false`, the item is hidden regardless of other permissions.
+
+**Rule Specificity Within a Role**:
+- Within a single role, the most specific rule wins
+- If generic rule has `view: true` but specific rule has `view: false`, then `view: false` applies (specific overrides generic)
+- If generic rule has `view: false` but specific rule has `view: true`, then `view: true` applies (specific overrides generic)
+
+**Multiple Roles**: If a user has multiple roles, `view` uses opening (union) logic - if ANY role has `view: true` (after applying rule specificity within that role), the item is visible.
+
+### Opening Rights Principle (DATA Context Only)
+
+For DATA context, the system implements **opening rights** where read permission (`R`) is a prerequisite for create/update/delete operations (`CUD`):
- **If Read = "n"**: No CUD operations allowed
- **If Read = "m"**: CUD operations limited to "m" or "n"
- **If Read = "g"**: CUD operations limited to "g", "m", or "n"
- **If Read = "a"**: CUD operations can be "a", "g", "m", or "n"
-**Key Rule**: You can ONLY create/update/delete (CUD) if you have read (R) right.
+**Key Rule**: You can ONLY create/update/delete (CUD) if you have read (R) right. This principle applies only to DATA context.
-### System Field Protection
+### System Field Protection (DATA Context Only)
-**Critical Security Rule**: System fields are automatically protected and cannot be modified by users:
+**Critical Security Rule**: System fields are automatically protected and cannot be modified by users (applies only to DATA context):
- **ID Fields**: All `id` fields are read-only for all roles
- **System Fields**: All fields starting with `_` (underscore) are read-only for all roles
@@ -203,40 +324,139 @@ The system implements **opening rights** where read permission (`R`) is a prereq
**Access Rule Override**: Even if an AccessRule grants CUD permissions to system fields, the database connector will automatically restrict these operations to read-only.
+**Item Format for System Fields**: When referencing system fields in DATA context, use format `"."` (e.g., `"UserInDB._createdAt"`).
+
### Role-Based Access Logic
-Each user has **one role label** that directly maps to a set of access rules:
+The RBAC system uses a **two-level resolution** approach:
-- **Simple Assignment**: User.roleLabel → AccessRule.roleLabel
-- **Direct Mapping**: No complex role combinations
-- **Clear Permissions**: Each role has well-defined access patterns
-- **Easy Debugging**: Clear trace from user to permissions
+#### Level 1: Rule Specificity Within a Role (Most Specific Wins)
+- **Within a single role**, the most specific rule always wins
+- If generic rule (`item = null`) has `view: true` but specific rule (`item = "playground.voice.settings"`) has `view: false`, then `view: false` applies
+- Specific rules override generic rules within the same role
+- Resolution: Find longest matching prefix for the item, or use generic rule if no match
+
+#### Level 2: Multiple Roles (Opening/Union Logic)
+- **Across multiple roles**, opening (union) logic applies
+- If ANY role enables something (after Level 1 resolution), it is enabled
+- Permissions from all roles are combined (OR logic)
+- Most permissive access level wins for DATA context
+
+**Resolution Process:**
+1. **For each role**: Find the most specific matching rule (Level 1)
+2. **Across all roles**: Combine using union logic (Level 2)
+
+**Example:**
+- User has roles: `["user", "viewer"]`
+- Rule 1: `{roleLabel: "user", context: "UI", item: "playground", view: false}` - User role hides playground
+- Rule 2: `{roleLabel: "viewer", context: "UI", item: "playground", view: true}` - Viewer role shows playground
+- **Level 1 Resolution**:
+ - "user" role → most specific rule for "playground" → `view: false`
+ - "viewer" role → most specific rule for "playground" → `view: true`
+- **Level 2 Resolution**: Union logic → `view: true` OR `view: false` → `view: true`
+- **Result**: Playground is visible (viewer role enables it)
### Permission Validation
```python
-def validate_access_rule(rule: AccessRule) -> bool:
- """Validate that CUD permissions are allowed by read permission level"""
- read_level = AccessLevel(rule.read)
+def validateAccessRule(rule: AccessRule) -> bool:
+ """Validate that CUD permissions are allowed by read permission level (only for DATA context)"""
+ if rule.context != AccessRuleContext.DATA:
+ # For UI and RESOURCE contexts, only view is relevant
+ return True
+
+ if rule.read is None:
+ return False # DATA context requires read permission
+
+ readLevel = AccessLevel(rule.read)
# CUD operations are only allowed if read permission exists
for operation in [rule.create, rule.update, rule.delete]:
- if operation == "n":
+ if operation is None or operation == "n":
continue # No access is always valid
- if read_level == AccessLevel.NONE:
+ if readLevel == AccessLevel.NONE:
return False # No CUD allowed if no read access
- if read_level == AccessLevel.MY and operation not in ["n", "m"]:
+ if readLevel == AccessLevel.MY and operation not in ["n", "m"]:
return False
- if read_level == AccessLevel.MANDATE and operation not in ["n", "m", "g"]:
+ if readLevel == AccessLevel.GROUP and operation not in ["n", "m", "g"]:
return False
return True
-def validate_rule_hierarchy(rule: AccessRule) -> bool:
- """Validate that field rules require table rules"""
- if rule.fieldName is not None and rule.tableName is None:
- return False # Field rules must have a table
- return True
+def getUserPermissions(user: User, context: AccessRuleContext, item: str) -> UserPermissions:
+ """Get combined permissions for a user across all their roles"""
+ permissions = UserPermissions(
+ view=False,
+ read=AccessLevel.NONE,
+ create=AccessLevel.NONE,
+ update=AccessLevel.NONE,
+ delete=AccessLevel.NONE
+ )
+
+ # Step 1: For each role, find the most specific matching rule (most specific wins within role)
+ rolePermissions = {}
+ for roleLabel in user.roleLabels:
+ # Get all rules for this role and context
+ allRules = getRulesForRole(roleLabel, context)
+
+ # Find most specific rule for this item (longest matching prefix)
+ mostSpecificRule = findMostSpecificRule(allRules, item)
+
+ if mostSpecificRule:
+ rolePermissions[roleLabel] = mostSpecificRule
+
+ # Step 2: Combine permissions across roles using opening (union) logic
+ for roleLabel, rule in rolePermissions.items():
+ # View: union logic - if ANY role has view=true, then view=true
+ if rule.view:
+ permissions.view = True
+
+ if context == AccessRuleContext.DATA:
+ # For DATA context, use most permissive access level across roles
+ if rule.read and _isMorePermissive(rule.read, permissions.read):
+ permissions.read = rule.read
+ if rule.create and _isMorePermissive(rule.create, permissions.create):
+ permissions.create = rule.create
+ if rule.update and _isMorePermissive(rule.update, permissions.update):
+ permissions.update = rule.update
+ if rule.delete and _isMorePermissive(rule.delete, permissions.delete):
+ permissions.delete = rule.delete
+
+ return permissions
+
+def findMostSpecificRule(rules: List[AccessRule], item: str) -> Optional[AccessRule]:
+ """Find the most specific rule for an item (longest matching prefix wins)"""
+ if not item:
+ # If no item specified, return generic rule (item = null)
+ genericRules = [r for r in rules if r.item is None]
+ return genericRules[0] if genericRules else None
+
+ # Find longest matching prefix
+ itemParts = item.split(".")
+ bestMatch = None
+ bestMatchLength = -1
+
+ for rule in rules:
+ if rule.item is None:
+ # Generic rule - use as fallback if no specific match found
+ if bestMatch is None:
+ bestMatch = rule
+ elif rule.item == item:
+ # Exact match - most specific
+ return rule
+ elif item.startswith(rule.item + "."):
+ # Prefix match - check if it's longer than current best
+ matchLength = len(rule.item.split("."))
+ if matchLength > bestMatchLength:
+ bestMatch = rule
+ bestMatchLength = matchLength
+
+ return bestMatch
+
+def _isMorePermissive(level1: AccessLevel, level2: AccessLevel) -> bool:
+ """Check if level1 is more permissive than level2"""
+ hierarchy = {AccessLevel.NONE: 0, AccessLevel.MY: 1, AccessLevel.GROUP: 2, AccessLevel.ALL: 3}
+ return hierarchy.get(level1, 0) > hierarchy.get(level2, 0)
```
## Database Integration
@@ -248,77 +468,102 @@ The database connector will be extended to support RBAC filtering:
```python
class DatabaseConnector:
def getRecordsetWithRBAC(self,
- model_class: Type[BaseModel],
- current_user: User,
- record_filter: Dict = None,
- order_by: str = None,
+ modelClass: Type[BaseModel],
+ currentUser: User,
+ recordFilter: Dict = None,
+ orderBy: str = None,
limit: int = None) -> List[Dict]:
"""Get records with RBAC filtering applied at database level"""
- # Get access rules for user's role
- access_rules = self.getAccessRulesForRole(current_user.roleLabel, model_class.__tablename__)
+ # Get access rules for user's roles
+ accessRules = self.getAccessRulesForRoles(
+ currentUser.roleLabels,
+ AccessRuleContext.DATA,
+ modelClass.__tablename__
+ )
# Build SQL query with RBAC WHERE clause
- where_clause = self.build_rbac_where_clause(access_rules, current_user)
+ whereClause = self.buildRbacWhereClause(accessRules, currentUser)
# Execute optimized query
- return self.execute_query_with_rbac(
- model_class,
- record_filter,
- where_clause,
- order_by,
+ return self.executeQueryWithRbac(
+ modelClass,
+ recordFilter,
+ whereClause,
+ orderBy,
limit
)
- def getAccessRulesForRole(self, role_label: str, table_name: str) -> List[AccessRule]:
- """Get access rules for a specific role and table"""
- # Get both table-specific and generic rules
- table_rules = self.getRecordset(AccessRule,
- recordFilter={
- "roleLabel": role_label,
- "tableName": table_name
- }
- )
- generic_rules = self.getRecordset(AccessRule,
- recordFilter={
- "roleLabel": role_label,
- "tableName": None
- }
- )
- return table_rules + generic_rules
+ def getAccessRulesForRoles(self, roleLabels: List[str], context: AccessRuleContext, item: str) -> List[AccessRule]:
+ """Get access rules for multiple roles, context, and item"""
+ # Get most specific matching rules for each role
+ allRules = []
+
+ for roleLabel in roleLabels:
+ # Get rules matching the role and context
+ rules = self.getRecordset(AccessRule,
+ recordFilter={
+ "roleLabel": roleLabel,
+ "context": context.value
+ }
+ )
+
+ # Find most specific match for item (longest matching prefix)
+ matchingRules = []
+ if item:
+ # Try to find exact match or longest prefix match
+ itemParts = item.split(".")
+ for i in range(len(itemParts), 0, -1):
+ prefix = ".".join(itemParts[:i])
+ matching = [r for r in rules if r.item == prefix]
+ if matching:
+ matchingRules.extend(matching)
+ break
+ # Also include generic rules (item = null)
+ matchingRules.extend([r for r in rules if r.item is None])
+ else:
+ # Include all rules for this role/context
+ matchingRules.extend(rules)
+
+ allRules.extend(matchingRules)
+
+ return allRules
- def is_system_field(self, field_name: str) -> bool:
+ def isSystemField(self, fieldName: str) -> bool:
"""Check if a field is a protected system field"""
- return field_name == "id" or field_name.startswith("_")
+ return fieldName == "id" or fieldName.startswith("_")
- def enforce_system_field_protection(self, data: Dict, operation: str) -> Dict:
+ def enforceSystemFieldProtection(self, data: Dict, operation: str) -> Dict:
"""Remove system fields from CUD operations"""
if operation == "read":
return data # Read operations can access system fields
# For CUD operations, remove system fields
- protected_data = {}
+ protectedData = {}
for key, value in data.items():
- if not self.is_system_field(key):
- protected_data[key] = value
+ if not self.isSystemField(key):
+ protectedData[key] = value
- return protected_data
+ return protectedData
```
### SQL Query Generation
```sql
--- Example: Get workflows with RBAC filtering for single role
+-- Example: Get workflows with RBAC filtering for multiple roles
SELECT w.*
FROM "ChatWorkflow" w
-JOIN "AccessRule" ar ON ar.roleLabel = %s AND ar.tableName = 'ChatWorkflow'
+JOIN "AccessRule" ar ON
+ ar.roleLabel = ANY(%s) -- Array of role labels
+ AND ar.context = 'DATA'
+ AND (ar.item = 'ChatWorkflow' OR ar.item IS NULL)
WHERE
- -- User access control based on role permissions
+ -- User access control based on role permissions (opening/union logic)
(
-- All records access
(ar.read = 'a')
OR
- -- Mandate records access
+ -- Group records access (group context is the mandate)
(ar.read = 'g' AND w.mandateId = %s)
OR
-- My records access
@@ -333,14 +578,17 @@ LIMIT 100;
## Migration Strategy
### Phase 1: Database Schema
-1. Create `AccessRule` table
-2. Add `roleLabel` column to `User` table
-3. Create indexes for performance
+1. Create `AccessRule` table with `context`, `item`, `view` fields
+2. Add `roleLabels` column (array) to `User` table
+3. Create indexes for performance (roleLabel, context, item)
+4. Migrate existing `tableName`/`fieldName` to `item` format
### Phase 2: Data Migration
-1. Create default access rules for each role label
-2. Migrate existing users to appropriate role labels
+1. Create default access rules for each role label across all contexts (DATA, UI, RESOURCE)
+2. Migrate existing users to appropriate role labels (convert single roleLabel to roleLabels array)
3. Create access rules based on current UAM logic
+4. Migrate tableName/fieldName to item format for DATA context
+5. Create UI and RESOURCE access rules as needed
### Phase 3: Code Migration
1. Update database connector with RBAC support
@@ -388,28 +636,6 @@ LIMIT 100;
- Permission changes tracked
- Security events monitored
-## Implementation Timeline
-
-### Week 1-2: Database Schema
-- Create tables and indexes
-- Implement data models
-- Set up migration scripts
-
-### Week 3-4: Core RBAC Logic
-- Implement access rule validation
-- Build database connector extensions
-- Create permission checking utilities
-
-### Week 5-6: Interface Migration
-- Update interfaceAppObjects
-- Update interfaceChatObjects
-- Update interfaceComponentObjects
-
-### Week 7-8: Testing & Optimization
-- Performance testing
-- Security validation
-- Query optimization
-- Documentation updates
## Default Roles
@@ -424,18 +650,25 @@ LIMIT 100;
## Role Management
-### Simple Role Assignment
+### Multiple Role Assignment
-Users have a single role label that directly maps to access rules:
+Users can have multiple role labels that are combined using opening (union) logic:
```json
{
"userId": "user-123",
- "roleLabel": "admin",
+ "roleLabels": ["admin", "viewer"],
"mandateId": "mandate-456"
}
```
+**Role Combination Logic:**
+- All roles are **opening roles** (union)
+- If ANY role enables something, it is enabled
+- Permissions from all roles are combined
+- Most permissive access level wins for DATA context
+- View permission is true if ANY role has view=true
+
### Role Label Options
- **sysadmin**: System administrator with full access
- **admin**: Administrator with mandate-level access
@@ -444,30 +677,30 @@ Users have a single role label that directly maps to access rules:
## Access Rule Examples
-### Generic Rules (All Tables)
-
-Generic rules provide a powerful way to set default permissions that apply across all tables:
+### DATA Context Examples
#### Example 1: Viewer Role - Read-Only Access to All Tables
```json
{
"roleLabel": "viewer",
- "tableName": null,
- "fieldName": null,
+ "context": "DATA",
+ "item": null,
+ "view": true,
"read": "g",
"create": "n",
"update": "n",
"delete": "n"
}
```
-**Effect**: Viewers can read mandate records in ALL tables, but cannot create, update, or delete anything.
+**Effect**: Viewers can read group records in ALL tables (group context is the mandate), but cannot create, update, or delete anything.
#### Example 2: SysAdmin Role - Full Access to All Tables
```json
{
"roleLabel": "sysadmin",
- "tableName": null,
- "fieldName": null,
+ "context": "DATA",
+ "item": null,
+ "view": true,
"read": "a",
"create": "a",
"update": "a",
@@ -480,8 +713,9 @@ Generic rules provide a powerful way to set default permissions that apply acros
```json
{
"roleLabel": "user",
- "tableName": null,
- "fieldName": null,
+ "context": "DATA",
+ "item": null,
+ "view": true,
"read": "m",
"create": "m",
"update": "m",
@@ -490,16 +724,13 @@ Generic rules provide a powerful way to set default permissions that apply acros
```
**Effect**: Users can only access their own records in ALL tables (where `_createdBy` matches their user ID).
-### Table-Specific Rules
-
-Table-specific rules override generic rules for particular tables:
-
#### Example 4: Admin Role - User Table Access
```json
{
"roleLabel": "admin",
- "tableName": "UserInDB",
- "fieldName": null,
+ "context": "DATA",
+ "item": "UserInDB",
+ "view": true,
"read": "g",
"create": "g",
"update": "g",
@@ -511,8 +742,9 @@ Table-specific rules override generic rules for particular tables:
```json
{
"roleLabel": "user",
- "tableName": "FileItem",
- "fieldName": null,
+ "context": "DATA",
+ "item": "FileItem",
+ "view": true,
"read": "g",
"create": "g",
"update": "g",
@@ -521,30 +753,13 @@ Table-specific rules override generic rules for particular tables:
```
**Effect**: Users can access all files in their mandate (overrides the generic "own records only" rule).
-#### Example 6: Viewer Role - Workflow Access (Override Generic Rule)
-```json
-{
- "roleLabel": "viewer",
- "tableName": "ChatWorkflow",
- "fieldName": null,
- "read": "a",
- "create": "n",
- "update": "n",
- "delete": "n"
-}
-```
-**Effect**: Viewers can read ALL workflows (overrides the generic "mandate records only" rule).
-
-### Field-Specific Rules
-
-Field-specific rules provide the most granular control:
-
-#### Example 7: User Role - Email Field Access
+#### Example 6: User Role - Email Field Access
```json
{
"roleLabel": "user",
- "tableName": "UserInDB",
- "fieldName": "email",
+ "context": "DATA",
+ "item": "UserInDB.email",
+ "view": true,
"read": "a",
"create": "a",
"update": "a",
@@ -553,28 +768,194 @@ Field-specific rules provide the most granular control:
```
**Effect**: Users can read and modify email addresses of all users, but cannot delete them.
-## Benefits of Generic Rules
+### UI Context Examples
+
+#### Example 7: User Role - Playground Component Access
+```json
+{
+ "roleLabel": "user",
+ "context": "UI",
+ "item": "playground",
+ "view": true
+}
+```
+**Effect**: Users can view the playground component.
+
+#### Example 8: Admin Role - Voice Settings Access
+```json
+{
+ "roleLabel": "admin",
+ "context": "UI",
+ "item": "playground.voice.settings",
+ "view": true
+}
+```
+**Effect**: Admins can view voice settings in the playground.
+
+#### Example 9: Viewer Role - Hide Search Feature
+```json
+{
+ "roleLabel": "viewer",
+ "context": "UI",
+ "item": "chatbot.search",
+ "view": false
+}
+```
+**Effect**: Viewers cannot see the search feature in the chatbot.
+
+#### Example 9b: Rule Specificity - Generic Allows, Specific Denies
+```json
+// Generic rule: Allow all UI
+{
+ "roleLabel": "user",
+ "context": "UI",
+ "item": null,
+ "view": true
+}
+
+// Specific rule: Hide voice settings (overrides generic)
+{
+ "roleLabel": "user",
+ "context": "UI",
+ "item": "playground.voice.settings",
+ "view": false
+}
+```
+**Effect**: Users can view all UI elements EXCEPT `playground.voice.settings` (specific rule overrides generic - most specific wins).
+
+### RESOURCE Context Examples
+
+#### Example 10: User Role - Anthropic AI Model Access
+```json
+{
+ "roleLabel": "user",
+ "context": "RESOURCE",
+ "item": "ai.model.anthropic",
+ "view": true
+}
+```
+**Effect**: Users can access the Anthropic AI model.
+
+#### Example 11: Admin Role - Jira Action Access
+```json
+{
+ "roleLabel": "admin",
+ "context": "RESOURCE",
+ "item": "ai.action.jira",
+ "view": true
+}
+```
+**Effect**: Admins can access the Jira action resource.
+
+#### Example 12: Viewer Role - Hide All AI Models
+```json
+{
+ "roleLabel": "viewer",
+ "context": "RESOURCE",
+ "item": "ai.model",
+ "view": false
+}
+```
+**Effect**: Viewers cannot access any AI models.
+
+### Multiple Roles Example
+
+**User Configuration:**
+```json
+{
+ "userId": "user-123",
+ "roleLabels": ["user", "viewer"]
+}
+```
+
+**Rules:**
+- Rule 1: `{roleLabel: "user", context: "UI", item: "playground", view: false}` - User role hides playground
+- Rule 2: `{roleLabel: "viewer", context: "UI", item: "playground", view: true}` - Viewer role shows playground
+
+**Resolution Process:**
+1. **Within "user" role**: Most specific rule for "playground" is `view: false`
+2. **Within "viewer" role**: Most specific rule for "playground" is `view: true`
+3. **Across roles**: Union logic applies - if ANY role has `view: true`, then `view: true`
+
+**Result**: Playground is visible (viewer role enables it - opening/union logic across roles)
+
+### Rule Specificity Example
+
+**User Configuration:**
+```json
+{
+ "userId": "user-456",
+ "roleLabels": ["user"]
+}
+```
+
+**Rules for "user" role:**
+- Generic: `{roleLabel: "user", context: "UI", item: null, view: true}` - Allow all UI
+- Specific: `{roleLabel: "user", context: "UI", item: "playground.voice.settings", view: false}` - Hide voice settings
+
+**Resolution Process:**
+1. **For item "playground.voice.settings"**: Find most specific matching rule
+2. **Specific rule found**: `item: "playground.voice.settings"` with `view: false`
+3. **Generic rule ignored**: Even though generic has `view: true`, specific rule wins
+
+**Result**: Voice settings are hidden (specific rule overrides generic - most specific wins within role)
+
+## Context-Specific Behavior
+
+### DATA Context
+
+- **Item Format**: `` or `.` (e.g., `"UserInDB"`, `"UserInDB.email"`)
+- **Permissions**: Uses `read`, `create`, `update`, `delete` access levels
+- **View Attribute**: Controls table/field accessibility
+- **Opening Rights**: Read permission is prerequisite for CUD operations
+- **System Field Protection**: Automatic protection for `id` and `_*` fields
+
+### UI Context
+
+- **Item Format**: Cascading string starting with UI name (e.g., `"playground"`, `"playground.voice"`, `"playground.voice.settings"`, `"chatbot.search"`)
+- **Permissions**: Only uses `view` attribute (boolean)
+- **View Attribute**: Controls visibility - only objects with `view: true` are shown
+- **Hierarchical**: Supports component → feature → element hierarchy
+- **No Opening Rights**: Not applicable to UI context
+
+### RESOURCE Context
+
+- **Item Format**: Cascading string (e.g., `"ai"`, `"ai.model"`, `"ai.model.anthropic"`, `"ai.action.jira"`)
+- **Permissions**: Only uses `view` attribute (boolean)
+- **View Attribute**: Controls accessibility - only resources with `view: true` are available
+- **Hierarchical**: Supports category → type → specific resource hierarchy
+- **No Opening Rights**: Not applicable to RESOURCE context
+
+## Benefits of Generic Rules and Context-Based System
### Simplified Access Management
Generic rules dramatically reduce the number of access rules needed:
**Without Generic Rules:**
-- Need separate rules for each table (UserInDB, ChatWorkflow, FileItem, etc.)
-- 10 tables × 4 roles = 40+ access rules
+- Need separate rules for each table/UI element/resource
+- 10 tables × 4 roles × 3 contexts = 120+ access rules
- Difficult to maintain and prone to inconsistencies
**With Generic Rules:**
-- 1 generic rule per role = 4 access rules
+- 1 generic rule per role per context = 12 access rules (4 roles × 3 contexts)
- Override with specific rules only when needed
- Much easier to maintain and understand
+### Context Separation Benefits
+
+1. **Clear Separation**: DATA, UI, and RESOURCE contexts are clearly separated
+2. **Unified Model**: Same rule structure for all contexts
+3. **Flexible Item Naming**: Cascading item names support hierarchical access control
+4. **View-Based UI Control**: Simple boolean `view` attribute controls UI visibility
+
### Common Use Cases for Generic Rules
-1. **Default Permissions**: Set baseline permissions for all tables
-2. **New Table Support**: Automatically apply permissions to new tables
-3. **Bulk Permission Changes**: Update permissions across all tables with one rule
+1. **Default Permissions**: Set baseline permissions for all items in a context
+2. **New Item Support**: Automatically apply permissions to new tables/UI elements/resources
+3. **Bulk Permission Changes**: Update permissions across all items with one rule
4. **Role Templates**: Create role templates that work out-of-the-box
+5. **UI Feature Flags**: Use view attribute to enable/disable features per role
### Rule Management Best Practices
@@ -606,8 +987,9 @@ protected_data = db_connector.enforce_system_field_protection(user_data, "update
```json
{
"roleLabel": "admin",
- "tableName": "UserInDB",
- "fieldName": "id",
+ "context": "DATA",
+ "item": "UserInDB.id",
+ "view": true,
"read": "a",
"create": "a", // ❌ Ignored - system field protection
"update": "a", // ❌ Ignored - system field protection
diff --git a/appdoc/doc_security_role_based_access_implementation_plan.md b/appdoc/doc_security_role_based_access_implementation_plan.md
new file mode 100644
index 0000000..0d0d5cc
--- /dev/null
+++ b/appdoc/doc_security_role_based_access_implementation_plan.md
@@ -0,0 +1,574 @@
+# RBAC Implementation Plan
+
+## Overview
+
+This document outlines the implementation plan for migrating from the current User Access Management (UAM) system to the new Role-Based Access Control (RBAC) system as specified in `doc_security_role_based_access.md`.
+
+## Implementation Phases
+
+### Phase 1: Database Schema and Data Models
+
+#### 1.1 Create RBAC Data Models
+**File**: `gateway/modules/datamodels/datamodelRbac.py`
+
+**New Models**:
+- `AccessRuleContext` (Enum): DATA, UI, RESOURCE
+- `AccessRule` (BaseModel): Complete RBAC rule model with context, item, view, read, create, update, delete
+- `AccessLevel` (Enum): Already exists in `datamodelUam.py` - verify and ensure consistency
+
+**Dependencies**:
+- Import from `datamodelUam.py`: `AccessLevel`, `User`
+- Use `ModelMixin` pattern from existing models
+- Register model labels using `registerModelLabels()`
+
+**Status**: ✅ `AccessLevel` already exists in `datamodelUam.py`
+**Action**: Create `datamodelRbac.py` with `AccessRule` and `AccessRuleContext`
+
+#### 1.2 Update User Model
+**File**: `gateway/modules/datamodels/datamodelUam.py`
+
+**Changes**:
+- Replace `privilege: UserPrivilege` with `roleLabels: List[str]`
+- Update `frontend_options` to use `"user.role"` string reference
+- Keep `UserPrivilege` enum for backward compatibility during migration
+
+**Migration Strategy**:
+- Add `roleLabels` field alongside `privilege` during transition
+- Migration script will populate `roleLabels` from `privilege`
+- After migration, `privilege` can be deprecated
+
+**Status**: ⚠️ Partial - `AccessLevel` exists, `roleLabels` needs to be added
+
+#### 1.3 Database Schema Migration
+**File**: Database migration script (to be created)
+
+**Schema Changes**:
+1. Create `AccessRule` table:
+ - `id` (UUID, primary key)
+ - `roleLabel` (string, indexed)
+ - `context` (enum: DATA, UI, RESOURCE, indexed)
+ - `item` (string, nullable, indexed)
+ - `view` (boolean)
+ - `read` (AccessLevel enum, nullable)
+ - `create` (AccessLevel enum, nullable)
+ - `update` (AccessLevel enum, nullable)
+ - `delete` (AccessLevel enum, nullable)
+ - Standard fields: `_createdAt`, `_createdBy`, `_updatedAt`, `_updatedBy`
+
+2. Update `User` table:
+ - Add `roleLabels` column (array of strings)
+ - Keep `privilege` column for backward compatibility
+
+3. Create indexes:
+ - `AccessRule(roleLabel, context, item)` - composite index for rule lookups
+ - `AccessRule(context, item)` - for context/item queries
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 2: RBAC Interface and Core Logic
+
+#### 2.1 Create RBAC Interface
+**File**: `gateway/modules/interfaces/interfaceRbac.py`
+
+**Purpose**: Centralized RBAC logic and permission resolution
+
+**Key Functions**:
+- `getUserPermissions(user: User, context: AccessRuleContext, item: str) -> UserPermissions`
+- `findMostSpecificRule(rules: List[AccessRule], item: str) -> Optional[AccessRule]`
+- `validateAccessRule(rule: AccessRule) -> bool`
+- `_isMorePermissive(level1: AccessLevel, level2: AccessLevel) -> bool`
+
+**Dependencies**:
+- `datamodelRbac.py`: `AccessRule`, `AccessRuleContext`
+- `datamodelUam.py`: `User`, `UserPermissions`, `AccessLevel`
+- `connectorDbPostgre.py`: Database connector for rule queries
+
+**References Check**: ✅
+- Can import from `datamodelUam.py` and `datamodelRbac.py`
+- Can use database connector from `interfaceDbAppObjects.py` pattern
+- Follows same pattern as `interfaceDbAppAccess.py`
+
+**Status**: 📝 To be implemented
+
+#### 2.2 Integrate RBAC CRUD into AppObjects Interface
+**File**: `gateway/modules/interfaces/interfaceDbAppObjects.py`
+
+**New Methods** (camelCase):
+- `createAccessRule(accessRule: AccessRule) -> AccessRule`
+- `getAccessRule(ruleId: str) -> Optional[AccessRule]`
+- `updateAccessRule(ruleId: str, accessRule: AccessRule) -> AccessRule`
+- `deleteAccessRule(ruleId: str) -> bool`
+- `getAccessRules(roleLabel: Optional[str] = None, context: Optional[AccessRuleContext] = None, item: Optional[str] = None) -> List[AccessRule]`
+- `getAccessRulesForRoles(roleLabels: List[str], context: AccessRuleContext, item: str) -> List[AccessRule]`
+
+**Integration Points**:
+- Use existing `self.db.recordCreate()`, `self.db.recordUpdate()`, `self.db.recordDelete()`, `self.db.getRecordset()` methods
+- Follow same pattern as existing CRUD methods (e.g., `createUser()`, `updateUser()`)
+- Add RBAC permission checks using `interfaceRbac.getUserPermissions()`
+
+**References Check**: ✅
+- Can use `self.db` database connector (already initialized)
+- Can import `AccessRule` from `datamodelRbac.py`
+- Follows existing interface pattern
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 3: Database Bootstrap and Initialization
+
+#### 3.1 Create Centralized Bootstrap Interface
+**File**: `gateway/modules/interfaces/interfaceBootstrap.py`
+
+**Purpose**: Centralized bootstrap module containing all initialization logic, specific data (roles, user names, mandate profiles), and RBAC rules converted from existing UAM logic.
+
+**Key Functions**:
+- `initBootstrap(db: DatabaseConnector) -> None` - Main bootstrap entry point
+- `initRootMandate(db: DatabaseConnector) -> str` - Creates root mandate, returns mandateId
+- `initAdminUser(db: DatabaseConnector, mandateId: str) -> str` - Creates admin user, returns userId
+- `initEventUser(db: DatabaseConnector, mandateId: str) -> str` - Creates event user, returns userId
+- `initRbacRules(db: DatabaseConnector) -> None` - Creates all RBAC rules from UAM logic
+- `createDefaultRoleRules(db: DatabaseConnector) -> None` - Creates default role rules
+- `createTableSpecificRules(db: DatabaseConnector) -> None` - Creates table-specific rules from UAM logic
+- `assignInitialUserRoles(db: DatabaseConnector, adminUserId: str, eventUserId: str) -> None` - Assigns roles to initial users
+
+**Bootstrap Data Configuration**:
+- **Root Mandate**: name="Root", language="en", enabled=True
+- **Admin User**: username="admin", email="admin@example.com", fullName="Administrator", roleLabels=["sysadmin"]
+- **Event User**: username="event", email="event@example.com", fullName="Event", roleLabels=["sysadmin"]
+- **Roles**: sysadmin, admin, user, viewer
+
+**RBAC Rules to Create** (converted from `interfaceDbAppAccess.py` logic):
+
+1. **Generic Role Rules** (context: DATA, item: null):
+ - **sysadmin**: view=true, read="a", create="a", update="a", delete="a"
+ - **admin**: view=true, read="g", create="g", update="g", delete="n"
+ - **user**: view=true, read="m", create="m", update="m", delete="m"
+ - **viewer**: view=true, read="g", create="n", update="n", delete="n"
+
+2. **Table-Specific Rules** (context: DATA, item: ``):
+ - **Mandate**:
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin/user/viewer: view=false (no access)
+
+ - **UserInDB**:
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin: view=true, read="g", create="g", update="g", delete="g" (mandate scope)
+ - user/viewer: view=true, read="m", create="n", update="m", delete="n" (own records only)
+
+ - **UserConnection**:
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin: view=true, read="g", create="g", update="g", delete="g" (users in mandate)
+ - user/viewer: view=true, read="m", create="m", update="m", delete="m" (own connections)
+
+ - **DataNeutraliserConfig**:
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin: view=true, read="g", create="g", update="g", delete="g" (mandate scope)
+ - user/viewer: view=true, read="m", create="m", update="m", delete="m" (own configs)
+
+ - **DataNeutralizerAttributes**:
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin: view=true, read="g", create="g", update="g", delete="g" (mandate scope)
+ - user/viewer: view=true, read="m", create="m", update="m", delete="m" (own attributes)
+
+ - **AuthEvent**:
+ - sysadmin/admin: view=true, read="a", create="n", update="n", delete="a"
+ - user/viewer: view=true, read="m", create="n", update="n", delete="n" (own events only)
+
+ - **Default Tables** (all other tables):
+ - sysadmin: view=true, read="a", create="a", update="a", delete="a"
+ - admin: view=true, read="g", create="g", update="g", delete="g" (mandate scope)
+ - user/viewer: view=true, read="m", create="m", update="m", delete="m" (own records)
+
+3. **UI Context Rules** (context: UI):
+ - Generic UI access for all roles (to be defined based on requirements)
+ - Component-specific rules as needed
+
+4. **RESOURCE Context Rules** (context: RESOURCE):
+ - AI model access rules (to be defined based on requirements)
+ - Action access rules (to be defined based on requirements)
+
+**Integration with AppObjects Interface**:
+**File**: `gateway/modules/interfaces/interfaceDbAppObjects.py`
+
+**Replace `_initRecords()` method**:
+```python
+def _initRecords(self):
+ """Initialize standard records if they don't exist."""
+ from modules.interfaces.interfaceBootstrap import initBootstrap
+ initBootstrap(self.db)
+```
+
+**Remove Methods** (moved to `interfaceBootstrap.py`):
+- `_initRootMandate()` → `interfaceBootstrap.initRootMandate()`
+- `_initAdminUser()` → `interfaceBootstrap.initAdminUser()`
+- `_initEventUser()` → `interfaceBootstrap.initEventUser()`
+
+**Status**: 📝 To be implemented
+
+#### 3.2 UAM Logic to RBAC Rules Conversion
+
+**Source Files to Analyze**:
+- `gateway/modules/interfaces/interfaceDbAppAccess.py`
+- `gateway/modules/interfaces/interfaceDbChatAccess.py`
+- `gateway/modules/interfaces/interfaceDbComponentAccess.py`
+
+**Conversion Mapping**:
+
+| UAM Logic (interfaceDbAppAccess.py) | RBAC Rule (context: DATA) |
+|-------------------------------------|---------------------------|
+| `table_name == "Mandate"` + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item="Mandate"`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| `table_name == "UserInDB"` + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item="UserInDB"`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| `table_name == "UserInDB"` + `privilege == ADMIN` | `roleLabel="admin"`, `item="UserInDB"`, `view=true`, `read="g"`, `create="g"`, `update="g"`, `delete="g"` |
+| `table_name == "UserInDB"` + `privilege == USER` | `roleLabel="user"`, `item="UserInDB"`, `view=true`, `read="m"`, `create="n"`, `update="m"`, `delete="n"` |
+| `table_name == "UserConnection"` + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item="UserConnection"`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| `table_name == "UserConnection"` + `privilege == ADMIN` | `roleLabel="admin"`, `item="UserConnection"`, `view=true`, `read="g"`, `create="g"`, `update="g"`, `delete="g"` |
+| `table_name == "UserConnection"` + `privilege == USER` | `roleLabel="user"`, `item="UserConnection"`, `view=true`, `read="m"`, `create="m"`, `update="m"`, `delete="m"` |
+| `table_name == "DataNeutraliserConfig"` + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item="DataNeutraliserConfig"`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| `table_name == "DataNeutraliserConfig"` + `privilege == ADMIN` | `roleLabel="admin"`, `item="DataNeutraliserConfig"`, `view=true`, `read="g"`, `create="g"`, `update="g"`, `delete="g"` |
+| `table_name == "DataNeutraliserConfig"` + `privilege == USER` | `roleLabel="user"`, `item="DataNeutraliserConfig"`, `view=true`, `read="m"`, `create="m"`, `update="m"`, `delete="m"` |
+| `table_name == "DataNeutralizerAttributes"` + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item="DataNeutralizerAttributes"`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| `table_name == "DataNeutralizerAttributes"` + `privilege == ADMIN` | `roleLabel="admin"`, `item="DataNeutralizerAttributes"`, `view=true`, `read="g"`, `create="g"`, `update="g"`, `delete="g"` |
+| `table_name == "DataNeutralizerAttributes"` + `privilege == USER` | `roleLabel="user"`, `item="DataNeutralizerAttributes"`, `view=true`, `read="m"`, `create="m"`, `update="m"`, `delete="m"` |
+| `table_name == "AuthEvent"` + `privilege in [SYSADMIN, ADMIN]` | `roleLabel="sysadmin"`/`"admin"`, `item="AuthEvent"`, `view=true`, `read="a"`, `create="n"`, `update="n"`, `delete="a"` |
+| `table_name == "AuthEvent"` + `privilege == USER` | `roleLabel="user"`, `item="AuthEvent"`, `view=true`, `read="m"`, `create="n"`, `update="n"`, `delete="n"` |
+| Default tables + `privilege == SYSADMIN` | `roleLabel="sysadmin"`, `item=null`, `view=true`, `read="a"`, `create="a"`, `update="a"`, `delete="a"` |
+| Default tables + `privilege == ADMIN` | `roleLabel="admin"`, `item=null`, `view=true`, `read="g"`, `create="g"`, `update="g"`, `delete="g"` |
+| Default tables + `privilege == USER` | `roleLabel="user"`, `item=null`, `view=true`, `read="m"`, `create="m"`, `update="m"`, `delete="m"` |
+
+**Implementation Steps**:
+1. Read `interfaceDbAppAccess.py` and extract all `uam()` logic
+2. Read `interfaceDbChatAccess.py` and extract all `uam()` logic
+3. Read `interfaceDbComponentAccess.py` and extract all `uam()` logic
+4. Map each permission check to RBAC rule format
+5. Create `AccessRule` entries in `interfaceBootstrap.createTableSpecificRules()`
+6. Test that RBAC rules produce same results as UAM logic
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 4: Database Connector RBAC Support
+
+#### 4.1 Extend Database Connector
+**File**: `gateway/modules/connectors/connectorDbPostgre.py`
+
+**New Methods**:
+- `getRecordsetWithRBAC(modelClass: Type[BaseModel], currentUser: User, recordFilter: Dict = None, orderBy: str = None, limit: int = None) -> List[Dict]`
+- `buildRbacWhereClause(accessRules: List[AccessRule], currentUser: User) -> str`
+- `executeQueryWithRbac(...) -> List[Dict]`
+
+**SQL Query Enhancement**:
+- Modify SQL generation to include RBAC WHERE clauses
+- Support multiple roles with UNION logic
+- Optimize queries with proper indexes
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 5: Migration from UAM to RBAC
+
+#### 5.1 Create Migration Script
+**File**: `gateway/modules/migration/migrateUamToRbac.py`
+
+**Migration Steps**:
+1. **Schema Migration**:
+ - Create `AccessRule` table
+ - Add `roleLabels` column to `User` table
+ - Create indexes
+
+2. **Data Migration**:
+ - Convert `User.privilege` → `User.roleLabels`:
+ - `UserPrivilege.SYSADMIN` → `["sysadmin"]`
+ - `UserPrivilege.ADMIN` → `["admin"]`
+ - `UserPrivilege.USER` → `["user"]`
+ - Create default access rules based on current UAM logic
+ - Map existing table-specific permissions to RBAC rules
+
+3. **Validation**:
+ - Verify all users have roleLabels assigned
+ - Verify access rules match current UAM behavior
+ - Test permission resolution
+
+**Status**: 📝 To be implemented
+
+#### 5.2 Update Interface Methods
+**Files to Update**:
+- `gateway/modules/interfaces/interfaceDbAppObjects.py`
+- `gateway/modules/interfaces/interfaceDbChatObjects.py`
+- `gateway/modules/interfaces/interfaceDbComponentObjects.py`
+
+**Changes**:
+- Replace `_uam()` calls with `getRecordsetWithRBAC()`
+- Replace `_canModify()` checks with RBAC permission checks
+- Update all `getRecordset()` calls to use RBAC filtering
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 6: UI and Resource Access Control
+
+#### 6.1 UI Access Control Integration
+**Files**: Frontend integration (out of scope for backend)
+
+**Backend Support**:
+- Ensure `getUserPermissions()` works for UI context
+- Create API endpoint: `GET /api/rbac/permissions?context=UI&item=playground.voice.settings`
+- Return `UserPermissions` model with `view` attribute
+
+**Status**: 📝 To be implemented
+
+#### 6.2 Resource Access Control Integration
+**Files**: Feature modules that use resources
+
+**Integration Points**:
+- AI model selection: Check `getUserPermissions(context=RESOURCE, item="ai.model.anthropic")`
+- Action execution: Check permissions before allowing action execution
+- Create helper functions in feature modules
+
+**Status**: 📝 To be implemented
+
+---
+
+### Phase 7: Testing and Validation
+
+#### 7.1 Unit Tests
+**Files**: `gateway/tests/unit/rbac/`
+
+**Test Cases**:
+- Permission resolution (single role, multiple roles)
+- Rule specificity (generic vs specific)
+- Opening rights principle
+- System field protection
+- Bootstrap initialization
+
+**Status**: 📝 To be implemented
+
+#### 7.2 Integration Tests
+**Files**: `gateway/tests/integration/rbac/`
+
+**Test Cases**:
+- Database queries with RBAC filtering
+- User CRUD operations with RBAC
+- Multi-role permission combination
+- Migration from UAM to RBAC
+
+**Status**: 📝 To be implemented
+
+#### 7.3 Performance Tests
+**Test Cases**:
+- Query performance with RBAC (compare to current UAM)
+- Memory usage reduction
+- Database load reduction
+
+**Status**: 📝 To be implemented
+
+---
+
+## Module Adaptation Summary
+
+### Modules to Create
+
+1. **`gateway/modules/datamodels/datamodelRbac.py`**
+ - `AccessRule` model
+ - `AccessRuleContext` enum
+ - Model label registration
+
+2. **`gateway/modules/interfaces/interfaceRbac.py`**
+ - RBAC core logic
+ - Permission resolution functions
+ - Rule validation functions
+
+3. **`gateway/modules/interfaces/interfaceBootstrap.py`** ⭐ **NEW**
+ - Centralized bootstrap interface
+ - All initialization logic (mandate, users, RBAC rules)
+ - Bootstrap data configuration (roles, user names, mandate profiles)
+ - RBAC rules converted from UAM logic (`interfaceDbAppAccess.py`, `interfaceDbChatAccess.py`, `interfaceDbComponentAccess.py`)
+
+4. **`gateway/modules/migration/migrateUamToRbac.py`**
+ - Migration script
+ - Data transformation logic
+ - Validation functions
+
+### Modules to Adapt
+
+1. **`gateway/modules/datamodels/datamodelUam.py`** ⚠️ **KEEP - Still Needed**
+ - ✅ Add `AccessLevel` enum (already done)
+ - ✅ Add `UserPermissions` model (already done)
+ - 📝 Add `roleLabels: List[str]` to `User` model
+ - 📝 Update `frontend_options` to use string references
+ - ⚠️ **Keep**: `User`, `Mandate`, `UserConnection` models (core data structures)
+ - ⚠️ **Deprecate**: `UserPrivilege` enum (replaced by `roleLabels` with RBAC)
+
+2. **`gateway/modules/interfaces/interfaceDbAppObjects.py`**
+ - 📝 Add RBAC CRUD methods
+ - 📝 Replace `_initRecords()` to call `interfaceBootstrap.initBootstrap()`
+ - 📝 Remove `_initRootMandate()`, `_initAdminUser()`, `_initEventUser()` (moved to `interfaceBootstrap.py`)
+ - 📝 Replace `_uam()` with RBAC-based filtering (Phase 5)
+ - 📝 Remove `self.access` initialization (no longer needed after RBAC migration)
+
+3. **`gateway/modules/connectors/connectorDbPostgre.py`**
+ - 📝 Add `getRecordsetWithRBAC()` method
+ - 📝 Add `buildRbacWhereClause()` method
+ - 📝 Add `executeQueryWithRbac()` method
+ - 📝 Enhance SQL generation for RBAC
+
+4. **`gateway/modules/interfaces/interfaceDbChatObjects.py`**
+ - 📝 Replace `_uam()` calls with RBAC filtering
+ - 📝 Update permission checks to use RBAC
+
+5. **`gateway/modules/interfaces/interfaceDbComponentObjects.py`**
+ - 📝 Replace `_uam()` calls with RBAC filtering
+ - 📝 Update permission checks to use RBAC
+
+6. **`gateway/modules/features/options/mainOptions.py`** (if created)
+ - 📝 Ensure `getOptions()` function exists for dynamic options
+
+### Modules to Remove (After Refactoring)
+
+1. **`gateway/modules/interfaces/interfaceDbAppAccess.py`** ❌ **REMOVE after Phase 5**
+ - ⚠️ **Convert all UAM logic to RBAC rules in `interfaceBootstrap.py`**
+ - Current UAM logic (`uam()`, `canModify()`) converted to AccessRule entries
+ - **Action**: Extract all permission logic from `uam()` and `canModify()` methods
+ - **Action**: Convert to RBAC rules in `interfaceBootstrap.createTableSpecificRules()`
+ - Remove after all interfaces migrated to RBAC and rules validated
+
+2. **`gateway/modules/interfaces/interfaceDbChatAccess.py`** ❌ **REMOVE after Phase 5**
+ - ⚠️ **Convert all UAM logic to RBAC rules in `interfaceBootstrap.py`**
+ - Similar to `interfaceDbAppAccess.py`
+ - Extract permission logic and convert to RBAC rules
+ - Remove after migration complete
+
+3. **`gateway/modules/interfaces/interfaceDbComponentAccess.py`** ❌ **REMOVE after Phase 5**
+ - ⚠️ **Convert all UAM logic to RBAC rules in `interfaceBootstrap.py`**
+ - Similar to `interfaceDbAppAccess.py`
+ - Extract permission logic and convert to RBAC rules
+ - Remove after migration complete
+
+**Migration Strategy for Access Modules**:
+1. **Phase 3**: Analyze all `interface*Access.py` modules
+2. **Phase 3**: Extract permission logic from `uam()` and `canModify()` methods
+3. **Phase 3**: Convert to RBAC rules in `interfaceBootstrap.createTableSpecificRules()`
+4. **Phase 5**: Replace all `_uam()` calls with RBAC filtering
+5. **Phase 5**: Remove `self.access` initialization from interfaces
+6. **Phase 9-10**: Delete `interface*Access.py` modules after validation
+
+**Note**: Keep these modules during migration for backward compatibility. Remove only after:
+- All UAM logic converted to RBAC rules in bootstrap
+- All interfaces use RBAC
+- All tests pass
+- Migration validation complete
+- No references to old UAM methods remain
+
+### Database Schema Changes
+
+1. **New Table**: `AccessRule`
+2. **Modified Table**: `User` (add `roleLabels` column)
+3. **New Indexes**: Performance optimization for RBAC queries
+
+---
+
+## Implementation Timeline
+
+### Week 1-2: Foundation
+- ✅ Create `datamodelRbac.py` with `AccessRule` model
+- ✅ Create `interfaceRbac.py` with core RBAC logic
+- ✅ Create `interfaceBootstrap.py` with centralized bootstrap logic
+- ✅ Extract bootstrap logic from `interfaceDbAppObjects.py` to `interfaceBootstrap.py`
+- ✅ Analyze `interface*Access.py` modules and extract UAM logic
+- ✅ Convert UAM logic to RBAC rules in `interfaceBootstrap.py`
+- ✅ Update `datamodelUam.py` with `roleLabels` field
+- ✅ Integrate `interfaceBootstrap.initBootstrap()` into `interfaceDbAppObjects.py`
+
+### Week 3-4: Database Integration
+- 📝 Extend database connector with RBAC support
+- 📝 Create migration script
+- 📝 Test database schema changes
+- 📝 Validate bootstrap initialization
+
+### Week 5-6: Interface Migration
+- 📝 Add RBAC CRUD methods to `interfaceDbAppObjects.py`
+- 📝 Update `interfaceDbChatObjects.py` to use RBAC
+- 📝 Update `interfaceDbComponentObjects.py` to use RBAC
+- 📝 Replace `_uam()` calls with RBAC filtering
+
+### Week 7-8: Testing & Optimization
+- 📝 Write unit tests
+- 📝 Write integration tests
+- 📝 Performance testing
+- 📝 Query optimization
+- 📝 Documentation updates
+
+### Week 9-10: Cleanup & Deprecation
+- 📝 Remove `interfaceDbAppAccess.py` (UAM logic converted to RBAC rules)
+- 📝 Remove `interfaceDbChatAccess.py` (UAM logic converted to RBAC rules)
+- 📝 Remove `interfaceDbComponentAccess.py` (UAM logic converted to RBAC rules)
+- 📝 Deprecate `UserPrivilege` enum in `datamodelUam.py` (keep for backward compatibility, mark as deprecated)
+- 📝 Final validation
+- 📝 Production deployment
+
+---
+
+## Risk Mitigation
+
+### Backward Compatibility
+- Keep `UserPrivilege` enum during migration
+- Maintain `_uam()` method alongside RBAC during transition
+- Gradual migration allows rollback if needed
+
+### Data Integrity
+- Migration script with validation
+- Backup before migration
+- Test migration on staging environment first
+
+### Performance
+- Index optimization for RBAC queries
+- Query performance testing before production
+- Monitor database load after deployment
+
+---
+
+## Success Criteria
+
+1. ✅ All users have `roleLabels` assigned
+2. ✅ All access rules created and validated
+3. ✅ RBAC filtering works for all data operations
+4. ✅ Performance meets or exceeds current UAM system
+5. ✅ All tests pass
+6. ✅ No deprecated UAM code remains
+7. ✅ Documentation updated
+
+---
+
+## Notes
+
+- Follow camelCase naming convention for all functions and variables
+- Internal functions use `_` prefix
+- Use Pydantic models for type safety
+- Maintain existing error handling patterns
+- Follow existing logging patterns
+
+## Important Clarifications
+
+### `datamodelUam.py` Status
+- ✅ **KEEP**: Core data models (`User`, `Mandate`, `UserConnection`) are still needed
+- ✅ **KEEP**: `AccessLevel` enum (used by RBAC)
+- ✅ **KEEP**: `UserPermissions` model (used by RBAC)
+- ⚠️ **DEPRECATE**: `UserPrivilege` enum (replaced by `roleLabels` with RBAC rules)
+- 📝 **ADD**: `roleLabels: List[str]` field to `User` model
+
+### `interface*Access.py` Modules Status
+- ❌ **REMOVE**: All `interface*Access.py` modules after migration
+- ⚠️ **CONVERT**: All UAM logic from these modules to RBAC rules in `interfaceBootstrap.py`
+- 📝 **ACTION**: Extract permission logic from `uam()` and `canModify()` methods
+- 📝 **ACTION**: Create corresponding `AccessRule` entries in bootstrap
+
+### Bootstrap Strategy
+- ⭐ **CENTRALIZE**: All bootstrap logic in `interfaceBootstrap.py`
+- 📝 **INCLUDE**: Mandate creation, user creation, RBAC rule initialization
+- 📝 **INCLUDE**: All bootstrap data (roles, user names, mandate profiles)
+- 📝 **INCLUDE**: RBAC rules converted from UAM logic