API and persisted records use PowerOnModel system fields: - sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy Removed legacy JSON/DB field names: - _createdAt, _createdBy, _modifiedAt, _modifiedBy Frontend (frontend_nyla) and gateway call sites were updated accordingly. Database: - Bootstrap runs idempotent backfill (_migrateSystemFieldColumns) from old underscore columns and selected business duplicates into sys* where sys* IS NULL. - Re-run app bootstrap against each PostgreSQL database after deploy. - Optional: DROP INDEX IF EXISTS "idx_invitation_createdby" if an old index remains; new index: idx_invitation_syscreatedby on Invitation(sysCreatedBy). Tests: - RBAC integration tests aligned with current GROUP mandate filter and UserMandate-based UserConnection GROUP clause; buildRbacWhereClause(..., mandateId=...) must be passed explicitly (same as production request context).
23 KiB
Plan: System-Felder Architektur (inkl. Review-Findings)
Entscheidung: Echte Pydantic-Felder (KEIN extra='allow')
Pydantic v2 erlaubt keine _-prefixed Felder als regulaere model_fields.
Deshalb: Felder OHNE Underscore-Prefix in einer Base-Class, DB-Spalten werden umbenannt.
Feldnamen: sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy
Vorteile gegenueber extra='allow':
- Felder sind in model_fields (type-safe, sichtbar fuer getModelAttributeDefinitions)
- model_dump() inkludiert sie natuerlich
- Kein extra='allow' noetig - wird global entfernt
- Kein Spezial-Code in attributeUtils noetig
Deploy-Reihenfolge (Boot-Sequenz)
- Deploy neuer Code
- Boot:
_ensureTableExistsfuegt neuesysCreatedAtetc. Spalten automatisch hinzu (da jetzt in model_fields) - Boot: Bootstrap
_migrateSystemFieldColumnskopiert Daten von alten Spalten in neue - Applikation laeuft — referenziert nur noch
sysCreatedAtetc.
Alte _createdAt-Spalten bleiben in DB bestehen (kein DROP COLUMN), werden aber ignoriert.
Ziel-Architektur (Datenfluss)
PostgreSQL (sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy)
|
connectorDbPostgre.py (_saveRecord setzt die 4 Felder automatisch)
|
PowerOnModel (echte Felder: sysCreatedAt etc., readonly, visible=false)
|
Alle persistenten Models erben von PowerOnModel
|
interfaceDbApp.py (KEIN _-Filter mehr, Konstruktor akzeptiert alle Felder)
|
Route Endpoints (model_dump() inkludiert system fields)
|
Frontend (API liefert sysCreatedAt etc., FormGenerator zeigt sie nur wenn visible=true)
Schritt 1: PowerOnModel Basisklasse erstellen
Neue Datei: gateway/modules/datamodels/datamodelBase.py
from typing import Optional
from pydantic import BaseModel, Field
from modules.shared.attributeUtils import registerModelLabels
class PowerOnModel(BaseModel):
sysCreatedAt: Optional[float] = Field(
default=None,
description="Record creation timestamp (UTC, set by system)",
json_schema_extra={
"frontend_type": "timestamp",
"frontend_readonly": True,
"frontend_required": False,
"frontend_visible": False,
"system": True,
}
)
sysCreatedBy: Optional[str] = Field(
default=None,
description="User ID who created this record (set by system)",
json_schema_extra={
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": False,
"frontend_visible": False,
"system": True,
}
)
sysModifiedAt: Optional[float] = Field(
default=None,
description="Record last modification timestamp (UTC, set by system)",
json_schema_extra={
"frontend_type": "timestamp",
"frontend_readonly": True,
"frontend_required": False,
"frontend_visible": False,
"system": True,
}
)
sysModifiedBy: Optional[str] = Field(
default=None,
description="User ID who last modified this record (set by system)",
json_schema_extra={
"frontend_type": "text",
"frontend_readonly": True,
"frontend_required": False,
"frontend_visible": False,
"system": True,
}
)
registerModelLabels(
"PowerOnModel",
{"en": "Base Record", "de": "Basisdatensatz"},
{
"sysCreatedAt": {"en": "Created At", "de": "Erstellt am", "fr": "Cree le"},
"sysCreatedBy": {"en": "Created By", "de": "Erstellt von", "fr": "Cree par"},
"sysModifiedAt": {"en": "Modified At", "de": "Geaendert am", "fr": "Modifie le"},
"sysModifiedBy": {"en": "Modified By", "de": "Geaendert von", "fr": "Modifie par"},
},
)
Label-Vererbung in attributeUtils.py (Review #6)
getModelAttributeDefinitions liest Labels anhand des Model-Namens (z.B. "Prompt").
Die Labels der Basis-Klasse "PowerOnModel" werden NICHT automatisch vererbt.
Fix: getModelAttributeDefinitions anpassen: wenn ein Label fuer ein Feld
nicht im aktuellen Model gefunden wird, in der MRO (Method Resolution Order)
der Elternklassen suchen. Pseudocode:
labels = getModelLabels(model_name, userLanguage)
if not labels.get(fieldName):
for parent in modelClass.__mro__:
parentLabels = getModelLabels(parent.__name__, userLanguage)
if parentLabels.get(fieldName):
labels[fieldName] = parentLabels[fieldName]
break
Schritt 2: connectorDbPostgre.py anpassen
DB-Spaltennamen von _createdAt auf sysCreatedAt etc. aendern:
2a: _create_table_from_model (Zeile ~598)
Vorher: "_createdAt" DOUBLE PRECISION etc. hardcoded append
Nachher: ENTFERNEN — Spalten kommen jetzt automatisch aus model_fields via _get_model_fields()
2b: _save_record columns-Liste (Zeile ~629)
Vorher: columns = [...] + ["_createdAt", "_createdBy", "_modifiedAt", "_modifiedBy"]
Nachher: columns = ["id"] + [field for field in fields.keys() if field != "id"]
(system fields sind jetzt in model_fields, kein Append noetig)
2c: KRITISCH — _save_record ON CONFLICT Klausel (Zeile ~689-694) (Review #2)
Vorher:
updates = ", ".join(
[f'"{col}" = EXCLUDED."{col}"'
for col in columns[1:]
if col not in ["_createdAt", "_createdBy"]]
)
Nachher:
updates = ", ".join(
[f'"{col}" = EXCLUDED."{col}"'
for col in columns[1:]
if col not in ["sysCreatedAt", "sysCreatedBy"]]
)
Zweck: bei UPSERT werden sysCreatedAt/sysCreatedBy NICHT ueberschrieben.
2d: _save_record Timestamp-String-Parsing (Zeile ~651) (Review #3)
Vorher: if col in ["_createdAt", "_modifiedAt"] and value is not None:
Nachher: if col in ["sysCreatedAt", "sysModifiedAt"] and value is not None:
2e: KRITISCH — _saveRecord Metadata-Logik (Zeile ~746) (Review #11)
Vorher:
if "_createdAt" not in record:
record["_createdAt"] = currentTime
Problem: da sysCreatedAt ein model_field mit default=None ist, ist es
bei model_dump() IMMER im Dict (als None). "sysCreatedAt" not in record
waere deshalb NIE True.
Nachher:
if not record.get("sysCreatedAt"):
record["sysCreatedAt"] = currentTime
if effective_user_id:
record["sysCreatedBy"] = effective_user_id
elif not record.get("sysCreatedBy"):
if effective_user_id:
record["sysCreatedBy"] = effective_user_id
record["sysModifiedAt"] = currentTime
if effective_user_id:
record["sysModifiedBy"] = effective_user_id
2f: _ensureTableExists (Zeile ~521)
Vorher: desired_columns |= {"_createdAt", "_modifiedAt", "_createdBy", "_modifiedBy"}
Nachher: ENTFERNEN (kommen aus model_fields)
2g: _buildPaginationClauses (Zeile ~995)
Vorher: fields["_createdAt"] = "DOUBLE PRECISION" etc.
Nachher: ENTFERNEN (kommen aus model_fields)
2h: getDistinctColumnValues (Zeile ~1193)
Vorher: fields["_createdAt"] = "DOUBLE PRECISION" etc.
Nachher: ENTFERNEN (kommen aus model_fields)
2i: _system Tabelle (Review #7)
Die interne _system-Tabelle hat hardcoded _createdAt/_modifiedAt in
CREATE TABLE (Zeile ~326-333, ~447-454). SystemTable erbt von BaseModel.
Empfehlung: SystemTable auf PowerOnModel umstellen, hardcoded
_createdAt/_modifiedAt auf sysCreatedAt/sysModifiedAt aendern.
Bootstrap-Migration muss auch _system beruecksichtigen.
Schritt 3: Alle persistenten Models auf PowerOnModel umstellen
Kern-Datamodels (gateway/modules/datamodels/):
- datamodelUam.py: User, Mandate, UserConnection, UserVoicePreferences, UserInDB
- datamodelRbac.py: Role, AccessRule
- datamodelMembership.py: UserMandate, FeatureAccess, UserMandateRole, FeatureAccessRole
- datamodelFeatures.py: Feature, FeatureInstance
- datamodelUtils.py: Prompt (ENTFERNE extra='allow')
- datamodelFiles.py: FileItem (ENTFERNE extra='allow'), FileData
- datamodelFileFolder.py: FileFolder
- datamodelInvitation.py: Invitation
- datamodelFeatureDataSource.py: FeatureDataSource
- datamodelDataSource.py: DataSource
- datamodelMessaging.py: MessagingSubscription
- datamodelBilling.py: BillingAccount, BillingTransaction
- datamodelSubscription.py: MandateSubscription
- datamodelNotification.py: UserNotification
- datamodelSecurity.py: Token, AuthEvent
- datamodelKnowledge.py: persistente Knowledge-Models
- datamodelChat.py: persistente Chat-Models
Feature-Datamodels (gateway/modules/features/):
- commcoach/datamodelCommcoach.py: CoachingContext, CoachingSession, CoachingMessage, CoachingTask, CoachingScore, CoachingUserProfile, CoachingPersona, CoachingBadge
- workspace/datamodelFeatureWorkspace.py: WorkspaceUserSettings
- neutralization/datamodelFeatureNeutralizer.py: DataNeutraliserConfig
- automation2/datamodelFeatureAutomation2.py: Automation2Workflow, Automation2WorkflowRun, Automation2HumanTask
- trustee/datamodelFeatureTrustee.py: TrusteeOrganisation, TrusteeRole, TrusteeAccess, TrusteeContract, TrusteeDocument, TrusteePosition (ENTFERNE extra='allow'), TrusteeDataAccount, TrusteeDataJournalEntry, TrusteeDataJournalLine, TrusteeDataContact, TrusteeDataAccountBalance, TrusteeAccountingConfig, TrusteeAccountingSync
- teamsbot/datamodelTeamsbot.py: TeamsbotSession, TeamsbotTranscript, TeamsbotBotResponse, TeamsbotSystemBot, TeamsbotUserAccount, TeamsbotUserSettings, TeamsbotConfig
- automation/datamodelFeatureAutomation.py: AutomationDefinition, AutomationTemplate
- realEstate/datamodelFeatureRealEstate.py: Land, Kanton, Gemeinde, Parzelle, Projekt, Dokument, Kontext
Connector-intern:
- connectorDbPostgre.py: SystemTable (Review #7)
NICHT umstellen (reine DTOs):
- PaginationParams, PaginatedResponse, AttributeDefinition, FilePreview, TextMultilingual
- CreateContextRequest, UpdateContextRequest, etc. (Request/Response DTOs)
- DataNeutralizerAttributes (DTO)
- GeoPunkt, GeoPolylinie (embedded value objects)
- Enums
Schritt 4: Business-Feld-Duplikate entfernen
Felder die durch die neuen System-Felder ersetzt werden:
datamodelFileFolder.py:
- ENTFERNE:
createdAt: float-> ersetzt durch sysCreatedAt
datamodelFiles.py:
- ENTFERNE:
creationDate: float-> ersetzt durch sysCreatedAt
datamodelInvitation.py:
- ENTFERNE:
createdAt: float-> ersetzt durch sysCreatedAt - ENTFERNE:
createdBy: str-> ersetzt durch sysCreatedBy
datamodelFeatureDataSource.py:
- ENTFERNE:
createdAt: float-> ersetzt durch sysCreatedAt
datamodelDataSource.py (Review #5):
- ENTFERNE:
createdAt: float-> ersetzt durch sysCreatedAt
datamodelNotification.py (Review #5):
- ENTFERNE:
createdAt: floatauf UserNotification -> ersetzt durch sysCreatedAt
datamodelSecurity.py (Review #5):
- ENTFERNE:
createdAt: Optional[float]auf Token -> ersetzt durch sysCreatedAt
datamodelMessaging.py:
- ENTFERNE:
createdBy: str-> ersetzt durch sysCreatedBy - ENTFERNE:
modifiedBy: str-> ersetzt durch sysModifiedBy
commcoach/datamodelCommcoach.py:
- ENTFERNE:
createdAtauf 8 Models -> ersetzt durch sysCreatedAt - ENTFERNE:
updatedAtauf mehreren Models -> ersetzt durch sysModifiedAt
teamsbot/datamodelTeamsbot.py:
- ENTFERNE:
creationDateauf 6 Models -> ersetzt durch sysCreatedAt - ENTFERNE:
lastModifiedauf 4 Models -> ersetzt durch sysModifiedAt
Schritt 5: _-Filter und Passthrough-Logik bereinigen
5a: 44x _-Filter in interfaceDbApp.py entfernen
Vorher (44 Stellen):
cleanedRecord = {k: v for k, v in record.items() if not k.startswith("_")}
return UserMandate(**cleanedRecord)
Nachher:
return UserMandate(**record)
Da alle Models jetzt von PowerOnModel erben und die system fields als echte model_fields haben, akzeptiert der Konstruktor sie direkt.
5b: Muster B — User.model_validate statt Denylist (Review #1)
Die 2 Stellen mit Zusatzausschluss hashedPassword/resetToken/resetTokenExpires
(Zeile ~652 und ~2560-2567) ersetzen durch:
user = User.model_validate(userRecord)
if not hasattr(user, 'roleLabels') or user.roleLabels is None:
# roleLabels Defaulting wie bisher
pass
Pydantic v2 extra='ignore' verwirft unbekannte Keys automatisch.
Die Sicherheit steckt im Schema von User (Allowlist), nicht in
einer parallelen Ausschlussliste (Denylist).
5c: startswith("_") Passthrough entfernen (Review #4)
In interfaceDbApp.py Zeile ~192 und interfaceDbManagement.py Zeile ~180:
if fieldName.startswith("_"):
simpleFields[fieldName] = value
Diese Sonderbehandlung wird OBSOLET: sysCreatedAt ist ein regulaeres
model_field und landet automatisch in simpleFields. Die startswith("_")-
Branch kann ENTFERNT werden.
5d: Gleiche Bereinigung in:
- gateway/modules/interfaces/interfaceFeatures.py (9 Stellen, nur Muster A)
- gateway/modules/interfaces/interfaceDbManagement.py
Inventar Muster A (Ziel-Model pro Block, interfaceDbApp.py):
| Ziel-Model | Typische Funktionen / Bereich | Zeilen (ca.) |
|---|---|---|
User |
getUsers, Listen, einzelner User | ~531, ~563, ~589, ~880, ~920, ~981, ~1044 |
Mandate |
Mandanten-Filter fuer API | ~1332, ~1381 |
UserMandate |
Membership | ~1797, ~1820, ~1872, ~2002, ~2596 |
UserMandateRole |
Junction | ~2026, ~2123, ~2131, ~2617 |
FeatureAccess |
Feature-Zugriff | ~2196, ~2219, ~2243, ~2292 |
Invitation |
Einladungen | ~2430, ~2450, ~2471, ~2492, ~2513, ~2534 |
FeatureInstance |
Instanz laden / nach Mandant | ~2637, ~2682 |
Feature |
getFeatureByCode | ~2657 |
UserNotification |
Benachrichtigungen | ~2706, ~2737 |
AccessRule |
Regeln laden | ~2765, ~2786, ~3366 |
Role |
Rollen nach Instanz/Code/Mandant/alle | ~2807, ~2832, ~3550, ~3571 |
Token |
Tokens nach Connection/User | ~3031, ~3052 |
Sonderfall Token:
Zeile ~3006: Token(**tokens[0]) ohne vorherigen _-Filter — nach
Umbenennung konsistent, aber an andere Token-Pfade angleichen.
Sonderfall Invitation + recordFilter:
getInvitationsByCreator nutzt recordFilter={"createdBy": creatorId} (~2489).
Nach Entfernung des Business-Felds auf recordFilter={"sysCreatedBy": creatorId} umstellen.
Sonderfall UserNotification + Sortierung:
getNotificationsByUser sortiert mit x.createdAt (~2740).
Nach Entfernung auf x.sysCreatedAt aendern.
Schritt 6: extra='allow' global entfernen
Entfernen aus:
- datamodelUtils.py: Prompt (
ConfigDict(extra='allow')) - datamodelFiles.py: FileItem (
ConfigDict(extra='allow')) - features/trustee/datamodelFeatureTrustee.py: TrusteePosition (
model_config={"extra":"allow"})
Keine model_config mit extra='allow' mehr in der gesamten Applikation.
Schritt 7: Bootstrap-Migration (interfaceBootstrap.py)
Neue Funktion _migrateSystemFieldColumns(db) in interfaceBootstrap.py,
aufgerufen frueh in initBootstrap() (NACH initRootMandate, VOR allem anderen):
def _migrateSystemFieldColumns(db: DatabaseConnector) -> None:
"""Migrate old _createdAt/_createdBy/_modifiedAt/_modifiedBy columns
to new sysCreatedAt/sysCreatedBy/sysModifiedAt/sysModifiedBy columns.
Also migrates business field duplicates (createdAt, creationDate, etc.)
Idempotent: safe to run on every boot."""
COLUMN_RENAMES = {
"_createdAt": "sysCreatedAt",
"_createdBy": "sysCreatedBy",
"_modifiedAt": "sysModifiedAt",
"_modifiedBy": "sysModifiedBy",
}
BUSINESS_FIELD_MIGRATIONS = {
"FileFolder": {"createdAt": "sysCreatedAt"},
"FileItem": {"creationDate": "sysCreatedAt"},
"Invitation": {"createdAt": "sysCreatedAt", "createdBy": "sysCreatedBy"},
"FeatureDataSource": {"createdAt": "sysCreatedAt"},
"DataSource": {"createdAt": "sysCreatedAt"},
"UserNotification": {"createdAt": "sysCreatedAt"},
"Token": {"createdAt": "sysCreatedAt"},
"MessagingSubscription": {"createdBy": "sysCreatedBy", "modifiedBy": "sysModifiedBy"},
"CoachingContext": {"createdAt": "sysCreatedAt"},
"CoachingSession": {"createdAt": "sysCreatedAt", "updatedAt": "sysModifiedAt"},
"CoachingMessage": {"createdAt": "sysCreatedAt"},
"CoachingTask": {"createdAt": "sysCreatedAt", "updatedAt": "sysModifiedAt"},
"CoachingScore": {"createdAt": "sysCreatedAt"},
"CoachingUserProfile": {"createdAt": "sysCreatedAt", "updatedAt": "sysModifiedAt"},
"CoachingPersona": {"createdAt": "sysCreatedAt", "updatedAt": "sysModifiedAt"},
"CoachingBadge": {"createdAt": "sysCreatedAt"},
"TeamsbotSession": {"creationDate": "sysCreatedAt", "lastModified": "sysModifiedAt"},
"TeamsbotTranscript": {"creationDate": "sysCreatedAt"},
"TeamsbotBotResponse": {"creationDate": "sysCreatedAt"},
"TeamsbotSystemBot": {"creationDate": "sysCreatedAt", "lastModified": "sysModifiedAt"},
"TeamsbotUserAccount": {"creationDate": "sysCreatedAt", "lastModified": "sysModifiedAt"},
"TeamsbotUserSettings": {"creationDate": "sysCreatedAt", "lastModified": "sysModifiedAt"},
"_system": {"_createdAt": "sysCreatedAt", "_modifiedAt": "sysModifiedAt"},
}
# Fuer jede Tabelle in der DB:
# 1. Alte _-Spalten -> neue sys-Spalten kopieren (COLUMN_RENAMES)
# 2. Business-Felder -> sys-Felder kopieren (BUSINESS_FIELD_MIGRATIONS)
# 3. Nur wo sysX IS NULL (idempotent)
# 4. Neue Spalten werden automatisch von _ensureTableExists erstellt
Schritt 8: Gateway Calling References anpassen
Alle Dateien, die _createdAt/_createdBy/_modifiedAt/_modifiedBy referenzieren:
Interfaces:
- gateway/modules/interfaces/interfaceDbApp.py (44x _-Filter + direkte Referenzen)
- gateway/modules/interfaces/interfaceDbManagement.py
- gateway/modules/interfaces/interfaceBootstrap.py
- gateway/modules/interfaces/interfaceRbac.py
- gateway/modules/interfaces/interfaceDbChat.py
- gateway/modules/interfaces/interfaceDbBilling.py
Routes:
- gateway/modules/routes/routeDataFiles.py
- gateway/modules/routes/routeBilling.py
- gateway/modules/routes/routeAdminAutomationLogs.py
- gateway/modules/routes/routeAdminRbacRules.py
- gateway/modules/routes/routeAdminAutomationEvents.py
- gateway/modules/routes/routeSecurityLocal.py
- gateway/modules/routes/routeSecurityGoogle.py
Features:
- gateway/modules/features/trustee/interfaceFeatureTrustee.py
- gateway/modules/features/chatbot/interfaceFeatureChatbot.py
- gateway/modules/features/automation2/routeFeatureAutomation2.py
- gateway/modules/features/automation/routeFeatureAutomation.py
- gateway/modules/features/automation/interfaceFeatureAutomation.py
- gateway/modules/features/workspace/mainWorkspace.py
- gateway/modules/features/teamsbot/routeFeatureTeamsbot.py
- gateway/modules/features/teamsbot/interfaceFeatureTeamsbot.py
Sonstige Gateway:
- gateway/modules/connectors/connectorDbPostgre.py
- gateway/modules/auth/tokenManager.py
- gateway/modules/serviceCenter/services/serviceChat/mainServiceChat.py
- gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py
- gateway/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py
- gateway/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py
- gateway/modules/workflows/automation/mainWorkflow.py
- gateway/modules/security/rbac.py
- gateway/modules/shared/gdprDeletion.py
- gateway/modules/migration/migrateRootUsers.py
- gateway/scripts/script_db_export_migration.py
- gateway/tests/integration/rbac/test_rbac_database.py
Business-Feld Referenzen (creationDate, .createdAt, .createdBy, etc.):
- gateway/modules/features/teamsbot/datamodelTeamsbot.py
- gateway/modules/features/teamsbot/interfaceFeatureTeamsbot.py
- gateway/modules/features/teamsbot/routeFeatureTeamsbot.py
- gateway/modules/features/commcoach/datamodelCommcoach.py
- gateway/modules/datamodels/datamodelFiles.py
- gateway/modules/datamodels/datamodelMessaging.py
- gateway/modules/datamodels/datamodelDataSource.py
- gateway/modules/datamodels/datamodelNotification.py
- gateway/modules/datamodels/datamodelSecurity.py
- gateway/modules/interfaces/interfaceDbManagement.py
- gateway/modules/routes/routeSecurityLocal.py
- gateway/modules/routes/routeSecurityGoogle.py
- gateway/modules/serviceCenter/services/serviceChat/mainServiceChat.py
- gateway/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py
- gateway/modules/auth/tokenManager.py
Schritt 9: Frontend Calling References anpassen
Alle Dateien die _createdAt/_createdBy/_modifiedAt/_modifiedBy oder
Business-Duplikate referenzieren:
API Types:
- frontend_nyla/src/api/automationApi.ts
_createdAt,_createdBy,_createdByUserName->sysCreatedAt,sysCreatedBy - frontend_nyla/src/api/automation2Api.ts
createdAtKommentar ->sysCreatedAt
Type Definitions:
- frontend_nyla/src/types/mandate.ts
record._createdBy->record.sysCreatedBy(RBAC owner check)
Hooks:
- frontend_nyla/src/hooks/useAutomations.ts
Omit<..., '_createdAt' | '_createdBy'>->Omit<..., 'sysCreatedAt' | 'sysCreatedBy'>
Pages (excludedFields/hiddenColumns Listen):
- frontend_nyla/src/pages/basedata/PromptsPage.tsx
- frontend_nyla/src/pages/basedata/FilesPage.tsx
- frontend_nyla/src/pages/basedata/ConnectionsPage.tsx
- frontend_nyla/src/pages/views/trustee/TrusteePositionsView.tsx
- frontend_nyla/src/pages/views/trustee/TrusteePositionDocumentsView.tsx
- frontend_nyla/src/pages/views/trustee/TrusteeDocumentsView.tsx
- frontend_nyla/src/pages/views/realestate/RealEstateProjectsView.tsx
- frontend_nyla/src/pages/views/realestate/RealEstateParcelsView.tsx
- frontend_nyla/src/pages/views/automation/AutomationDefinitionsView.tsx
- frontend_nyla/src/pages/views/automation/AutomationTemplatesView.tsx
- frontend_nyla/src/pages/views/workspace/NeutralizationPanel.tsx
m.createdAt || m._createdAt->m.sysCreatedAt
Hinweis zu den excludedFields-Listen:
Da die System-Felder jetzt mit visible=false in den Attributen kommen,
werden viele dieser manuellen Ausschluss-Listen OBSOLET. Der FormGenerator
filtert sie automatisch raus. Die Listen koennen vereinfacht werden.
Zusammenfassung
| Bereich | Dateien | Aenderungsart |
|---|---|---|
| Neue Datei | datamodelBase.py | 1 neue Datei (PowerOnModel + Labels) |
| Connector | connectorDbPostgre.py | ~15 Stellen: Spaltennamen + Logik-Fix |
| attributeUtils | attributeUtils.py | Label-Vererbung via MRO |
| Kern-Datamodels | ~17 Dateien | BaseModel -> PowerOnModel |
| Feature-Datamodels | 8 Dateien | BaseModel -> PowerOnModel |
| Business-Felder | ~13 Models | Felder entfernen |
| extra='allow' | 3 Models | ConfigDict entfernen |
| _-Filter | interfaceDbApp.py + 2 weitere | ~50 Stellen vereinfachen |
| Muster B | interfaceDbApp.py (2 Stellen) | Denylist -> User.model_validate |
| Passthrough | interfaceDbApp.py + interfaceDbManagement.py | startswith("_") entfernen |
| Gateway Referenzen | ~30 Dateien | _createdAt -> sysCreatedAt |
| Frontend Referenzen | ~13 Dateien | _createdAt -> sysCreatedAt |
| Bootstrap | interfaceBootstrap.py | Migration-Funktion |
| registerModelLabels | ~10 Dateien | Labels fuer entfernte Felder bereinigen |
| _system Tabelle | connectorDbPostgre.py | Hardcoded Spalten umbenennen |