platform-core/modules/datamodels/datamodelFeatures.py
ValueOn AG bc7c6fe27c
Some checks failed
Deploy Plattform-Core (Int) / test (push) Failing after 13s
Deploy Plattform-Core (Int) / deploy (push) Has been skipped
elimination of technical issues (imports)
2026-06-06 00:32:45 +02:00

221 lines
9.8 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""Feature models: Feature definitions, instances, data sources, and shared feature types."""
import uuid
from typing import Optional, Dict, Any, List
from pydantic import BaseModel, Field
from modules.datamodels.datamodelBase import PowerOnModel
from modules.shared.i18nRegistry import i18nModel
from modules.datamodels.datamodelUtils import TextMultilingual
# ---------------------------------------------------------------------------
# Feature & FeatureInstance
# ---------------------------------------------------------------------------
@i18nModel("Feature")
class Feature(PowerOnModel):
"""Feature-Definition (global, z.B. 'trustee', 'commcoach'). Verfuegbare Funktionalitaeten der Plattform."""
code: str = Field(
description="Unique feature code (Primary Key), z.B. 'trustee', 'commcoach'",
json_schema_extra={"label": "Code", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True}
)
label: TextMultilingual = Field(
description="Feature label in multiple languages (I18n)",
json_schema_extra={"label": "Bezeichnung", "frontend_type": "multilingual", "frontend_readonly": False, "frontend_required": True}
)
icon: str = Field(
default="",
description="Icon identifier for the feature",
json_schema_extra={"label": "Symbol", "frontend_type": "text", "frontend_readonly": False, "frontend_required": False}
)
@i18nModel("Feature-Instanz")
class FeatureInstance(PowerOnModel):
"""Instanz eines Features in einem Mandanten. Ein Mandant kann mehrere Instanzen desselben Features haben."""
id: str = Field(
default_factory=lambda: str(uuid.uuid4()),
description="Unique ID of the feature instance",
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False}
)
featureCode: str = Field(
description="FK -> Feature.code",
json_schema_extra={
"label": "Feature",
"frontend_type": "select",
"frontend_readonly": True,
"frontend_required": True,
"fk_target": {"db": "poweron_app", "table": "Feature", "column": "code", "labelField": "code"},
},
)
mandateId: str = Field(
description="FK -> Mandate.id (CASCADE DELETE)",
json_schema_extra={
"label": "Mandant",
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": True,
"fk_target": {"db": "poweron_app", "table": "Mandate", "labelField": "label"},
},
)
label: str = Field(
default="",
description="Instance label, z.B. 'Buchhaltung 2025'",
json_schema_extra={"label": "Bezeichnung", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True}
)
enabled: bool = Field(
default=True,
description="Whether this feature instance is enabled",
json_schema_extra={"label": "Aktiviert", "frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False}
)
config: Optional[Dict[str, Any]] = Field(
default=None,
description="Instance-specific configuration (JSONB). Structure depends on featureCode.",
json_schema_extra={"label": "Konfiguration", "frontend_type": "json", "frontend_readonly": False, "frontend_required": False}
)
# ---------------------------------------------------------------------------
# FeatureDataSource
# ---------------------------------------------------------------------------
@i18nModel("Feature-Datenquelle")
class FeatureDataSource(PowerOnModel):
"""Feature-Instanz-Tabelle als Datenquelle im AI-Workspace."""
id: str = Field(
default_factory=lambda: str(uuid.uuid4()),
description="Primary key",
json_schema_extra={"label": "ID"},
)
featureInstanceId: str = Field(
description="FK to FeatureInstance",
json_schema_extra={"label": "Feature-Instanz", "fk_target": {"db": "poweron_app", "table": "FeatureInstance", "labelField": "label"}},
)
featureCode: str = Field(
description="Feature code (e.g. trustee, commcoach)",
json_schema_extra={"label": "Feature", "fk_target": {"db": "poweron_app", "table": "Feature", "column": "code", "labelField": "code"}},
)
tableName: str = Field(
description="Table name from DATA_OBJECTS meta (e.g. TrusteePosition)",
json_schema_extra={"label": "Tabelle"},
)
objectKey: str = Field(
description="RBAC object key (e.g. data.feature.trustee.TrusteePosition)",
json_schema_extra={"label": "Objekt-Schluessel"},
)
label: str = Field(
description="User-visible label",
json_schema_extra={"label": "Bezeichnung"},
)
mandateId: str = Field(
default="",
description="Mandate scope (set automatically from featureInstance.mandateId on create).",
json_schema_extra={"label": "Mandant", "fk_target": {"db": "poweron_app", "table": "Mandate", "labelField": "label"}},
)
neutralize: Optional[bool] = Field(
default=None,
description=(
"Three-state neutralization flag with cascade-inherit semantics. "
"None = inherit; True/False = explicit. Cascade-reset on parent toggle."
),
json_schema_extra={"label": "Neutralisieren", "frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False},
)
ragIndexEnabled: Optional[bool] = Field(
default=None,
description=(
"Three-state RAG-indexing flag with cascade-inherit semantics. "
"None = inherit; True/False = explicit. Cascade-reset on parent toggle."
),
json_schema_extra={"label": "RAG-Indexierung", "frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False},
)
neutralizeFields: Optional[List[str]] = Field(
default=None,
description="Column names whose values are replaced with placeholders before AI processing",
json_schema_extra={"label": "Zu neutralisierende Felder", "frontend_type": "multiselect", "frontend_readonly": False, "frontend_required": False},
)
recordFilter: Optional[Dict[str, str]] = Field(
default=None,
description="Record-level filter applied when querying this table, e.g. {'sessionId': 'abc-123'}",
json_schema_extra={"label": "Datensatzfilter"},
)
settings: Optional[Dict[str, Any]] = Field(
default=None,
description=(
"FeatureDataSource-scoped settings (JSON). Currently used keys: "
"ragLimits.{maxBytes,maxFileSize,maxItems,maxDepth}. "
"Mirror of DataSource.settings so the UDB settings modal can target both."
),
json_schema_extra={"label": "Einstellungen", "frontend_type": "json", "frontend_readonly": True, "frontend_required": False},
)
# ---------------------------------------------------------------------------
# DataNeutralizerAttributes
# ---------------------------------------------------------------------------
@i18nModel("Neutralisiertes Datenattribut")
class DataNeutralizerAttributes(PowerOnModel):
"""Zuordnung Originaltext zu Platzhalter fuer neutralisierte Daten."""
id: str = Field(
default_factory=lambda: str(uuid.uuid4()),
description="Unique ID of the attribute mapping (used as UID in neutralized files)",
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False},
)
mandateId: str = Field(
description="ID of the mandate this attribute belongs to",
json_schema_extra={
"label": "Mandanten-ID",
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": True,
"fk_target": {"db": "poweron_app", "table": "Mandate", "labelField": "label"},
},
)
featureInstanceId: str = Field(
description="ID of the feature instance this attribute belongs to",
json_schema_extra={
"label": "Feature-Instanz-ID",
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": True,
"fk_target": {"db": "poweron_app", "table": "FeatureInstance", "labelField": "label"},
},
)
userId: str = Field(
description="ID of the user who created this attribute",
json_schema_extra={
"label": "Benutzer-ID",
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": True,
"fk_target": {"db": "poweron_app", "table": "UserInDB", "labelField": "username"},
},
)
originalText: str = Field(
description="Original text that was neutralized",
json_schema_extra={"label": "Originaltext", "frontend_type": "text", "frontend_readonly": True, "frontend_required": True},
)
fileId: Optional[str] = Field(
default=None,
description="ID of the file this attribute belongs to",
json_schema_extra={
"label": "Datei-ID",
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": False,
"fk_target": {"db": "poweron_management", "table": "FileItem", "labelField": "fileName"},
},
)
patternType: str = Field(
description="Type of pattern that matched (email, phone, name, etc.)",
json_schema_extra={"label": "Mustertyp", "frontend_type": "text", "frontend_readonly": True, "frontend_required": True},
)
# ---------------------------------------------------------------------------
# AutoWorkflow — re-exported from canonical location (datamodelWorkflowAutomation)
# ---------------------------------------------------------------------------
from modules.datamodels.datamodelWorkflowAutomation import AutoWorkflow # noqa: F401