Phase 1C: Frontend unified contact UI

This commit is contained in:
Agent Zero
2026-07-23 17:17:32 +02:00
parent a8331fbc2b
commit 879106c4eb
62 changed files with 552 additions and 1276 deletions
+6 -18
View File
@@ -13,9 +13,6 @@ logger = logging.getLogger(__name__)
# ── Core system permissions ──
CORE_PERMISSIONS: list[dict[str, str]] = [
{"key": "companies:read", "label": "Companies: Read", "category": "core", "module": "companies"},
{"key": "companies:write", "label": "Companies: Write", "category": "core", "module": "companies"},
{"key": "companies:delete", "label": "Companies: Delete", "category": "core", "module": "companies"},
{"key": "contacts:read", "label": "Contacts: Read", "category": "core", "module": "contacts"},
{"key": "contacts:write", "label": "Contacts: Write", "category": "core", "module": "contacts"},
{"key": "contacts:delete", "label": "Contacts: Delete", "category": "core", "module": "contacts"},
@@ -61,21 +58,12 @@ CORE_PERMISSIONS: list[dict[str, str]] = [
# ── Core field definitions for field-level permissions ──
CORE_FIELD_DEFINITIONS: list[dict[str, str]] = [
{"module": "companies", "field": "name", "label": "Name", "sensitivity": "normal"},
{"module": "companies", "field": "account_number", "label": "Account Number", "sensitivity": "normal"},
{"module": "companies", "field": "industry", "label": "Industry", "sensitivity": "normal"},
{"module": "companies", "field": "phone", "label": "Phone", "sensitivity": "normal"},
{"module": "companies", "field": "email", "label": "Email", "sensitivity": "normal"},
{"module": "companies", "field": "website", "label": "Website", "sensitivity": "normal"},
{"module": "companies", "field": "description", "label": "Description", "sensitivity": "normal"},
{"module": "contacts", "field": "first_name", "label": "First Name", "sensitivity": "normal"},
{"module": "contacts", "field": "last_name", "label": "Last Name", "sensitivity": "normal"},
{"module": "contacts", "field": "email", "label": "Email", "sensitivity": "normal"},
{"module": "contacts", "field": "phone", "label": "Phone", "sensitivity": "normal"},
{"module": "contacts", "field": "mobile", "label": "Mobile", "sensitivity": "sensitive"},
{"module": "contacts", "field": "position", "label": "Position", "sensitivity": "normal"},
{"module": "contacts", "field": "department", "label": "Department", "sensitivity": "normal"},
{"module": "contacts", "field": "linkedin_url", "label": "LinkedIn URL", "sensitivity": "sensitive"},
{"module": "contacts", "field": "firstname", "label": "First Name", "sensitivity": "normal"},
{"module": "contacts", "field": "surname", "label": "Last Name", "sensitivity": "normal"},
{"module": "contacts", "field": "email_1", "label": "Email", "sensitivity": "normal"},
{"module": "contacts", "field": "phone_1", "label": "Phone", "sensitivity": "normal"},
{"module": "contacts", "field": "mobilephone", "label": "Mobile", "sensitivity": "sensitive"},
{"module": "contacts", "field": "function", "label": "Position", "sensitivity": "normal"},
{"module": "contacts", "field": "notes", "label": "Notes", "sensitivity": "sensitive"},
{"module": "users", "field": "email", "label": "Email", "sensitivity": "normal"},
{"module": "users", "field": "name", "label": "Name", "sensitivity": "normal"},
+9 -9
View File
@@ -5,7 +5,7 @@ Architecture:
- Redis cache: resolved:{user_id}:{tenant_id} with 5-min TTL.
- Permission-version stamping for immediate invalidation.
- Resolution: allowed = (role groups), denied = (role.denied groups.denied), resolved = allowed denied.
- Wildcards: companies:*, *:read, *:* (bare * is forbidden).
- Wildcards: contacts:*, *:read, *:* (bare * is forbidden).
"""
from __future__ import annotations
@@ -35,8 +35,8 @@ def _matches_permission(granted: str, required: str) -> bool:
"""Check if a granted permission matches the required permission.
Supports wildcards:
- companies:read → exact match
- companies:* → all actions for companies
- contacts:read → exact match
- contacts:* → all actions for contacts
- *:read → all modules, read action
- *:* → everything (superadmin)
"""
@@ -67,9 +67,9 @@ def _normalize_permissions(permissions: Any) -> set[str]:
"""Normalize permissions from JSONB to a set of strings.
Supports formats:
- list[str]: ["companies:read", "contacts:write"]
- dict[str, bool]: {"companies:read": true, "contacts:write": false}
- dict[str, dict]: {"companies": {"read": true, "write": false}}
- list[str]: ["contacts:read", "contacts:write"]
- dict[str, bool]: {"contacts:read": true, "contacts:write": false}
- dict[str, dict]: {"contacts": {"read": true, "write": false}}
"""
result: set[str] = set()
if isinstance(permissions, list):
@@ -156,7 +156,7 @@ async def resolve_permissions(
if legacy_role == "admin":
allowed.add("*:*")
elif legacy_role == "editor":
allowed |= {"companies:read", "companies:write", "contacts:read", "contacts:write",
allowed |= {"contacts:read", "contacts:write", "contacts:read", "contacts:write",
"users:read", "roles:read", "audit:read", "attachments:read",
"attachments:write", "workflows:read", "workflows:write",
"sequences:read", "sequences:write", "addresses:read", "addresses:write",
@@ -164,7 +164,7 @@ async def resolve_permissions(
"notifications:read", "notifications:write", "import_export:read",
"import_export:write"}
elif legacy_role == "viewer":
allowed |= {"companies:read", "contacts:read", "users:read", "roles:read",
allowed |= {"contacts:read", "contacts:read", "users:read", "roles:read",
"audit:read", "attachments:read", "workflows:read", "sequences:read",
"addresses:read", "taxes:read", "currencies:read",
"notifications:read", "import_export:read"}
@@ -265,7 +265,7 @@ def check_permission(resolved: dict[str, Any], required: str) -> bool:
Args:
resolved: result from get_cached_permissions or resolve_permissions
required: permission string like "companies:read"
required: permission string like "contacts:read"
"""
if resolved.get("is_system_admin"):
return True
-2
View File
@@ -43,7 +43,6 @@ from app.plugins.builtins.unified_search.jobs import (
index_mails,
index_file,
index_contact,
index_company,
index_event,
reindex,
embedding_batch,
@@ -57,7 +56,6 @@ class WorkerSettings:
index_mails,
index_file,
index_contact,
index_company,
index_event,
reindex,
embedding_batch,