# LIAM NTFS / DFS Pfadklassifikation - Zielkonzept ## Ziel Dieses Dokument beschreibt ein belastbares Zielkonzept fuer die Klassifikation von UNC-Pfaden im LIAM-NTFS-Provider. Der aktuelle Code behandelt die Unterscheidung zwischen Share und Folder im Wesentlichen ueber die Pfadtiefe. Das ist fuer einfache klassische UNC-Freigaben teilweise ausreichend, aber fachlich nicht robust genug. Insbesondere folgende Faelle sollen perspektivisch sauber unterstuetzt werden: - `\\server` - `\\server\share` - `\\server\share\folder` - `\\server\namespace` - `\\server\namespace\link` - `\\server\namespace\link\folder` Das Konzept ist bewusst noch keine Implementierung. Es beschreibt, welche semantischen Informationen benoetigt werden und wie die Entscheidung logisch aufgebaut sein sollte. ## Problem des aktuellen Ansatzes Der bestehende NTFS-Provider leitet den Objekttyp im Kern aus der Anzahl der UNC-Segmente ab. Beispiel: - `\\server\share` -> wird als Share behandelt - `\\server\share\folder` -> wird als Folder behandelt Das hat mehrere fachliche Schwaechen: - Ein DFS-Link wie `\\server\namespace\link` ist semantisch oft ein Share-aehnlicher Einstiegspunkt, hat aber drei Segmente. - Ein Root wie `\\server` ist mit der bisherigen Logik ueberhaupt nicht sinnvoll modellierbar. - `LoadDataArea()` und `getDataAreasAsync()` arbeiten nicht zwingend mit derselben Semantik. - Die Klassifikation basiert auf Syntax statt auf den tatsaechlichen Freigabe- und Namespace-Metadaten. Die Folge ist, dass bei DFS und bei kuenftigem Server-Root-Support keine verlaessliche Typbestimmung moeglich ist. ## Grundprinzip der richtigen Loesung Die Klassifikation darf nicht von der Pfadtiefe abhaengen, sondern muss aus der tatsaechlichen Bedeutung des Pfads ermittelt werden. Das bedeutet: - Ein klassischer Windows-Share wird ueber Share-Metadaten erkannt. - Ein DFS-Namespace oder DFS-Link wird ueber DFS-Metadaten erkannt. - Ein Folder ist ein Pfad, der unterhalb eines Share- oder Link-Grenzpunkts liegt. Die zentrale Regel lautet daher: Nicht fragen "Wie tief liegt der Pfad?", sondern "Welches Namensobjekt repraesentiert dieser Pfad fachlich?". ## Fachliche Objektarten Fuer eine robuste interne Modellierung sollten mehr Typen unterschieden werden als nur `Share` und `Folder`. Empfohlenes internes Zielmodell: - `ServerRoot` - `ClassicShare` - `DfsNamespaceRoot` - `DfsLink` - `Folder` - `Unknown` Nach aussen kann das bei Bedarf weiter auf bestehende LIAM-Typen gemappt werden: - `ClassicShare` -> `NtfsShare` - `DfsNamespaceRoot` -> je nach fachlicher Entscheidung `NtfsShare` oder Container-Typ - `DfsLink` -> `NtfsShare` - `Folder` -> `NtfsFolder` Der entscheidende Punkt ist, dass intern sauber unterschieden wird, auch wenn die externe API zunaechst kompatibel bleiben soll. ## Semantische Datenquellen ### 1. Klassische Windows-Freigaben Fuer klassische Shares ist die sichere Quelle die Share-Konfiguration des Zielservers. Fachlich wird geprueft: - Welche Shares existieren auf dem Server? - Welcher UNC-Pfad repraesentiert exakt einen Share? - Auf welchen lokalen Zielpfad zeigt der Share? Aus dieser Sicht gilt: - `\\server\share` ist ein Share, wenn auf dem Server genau dieser Share publiziert ist. - Jeder Pfad unterhalb davon ist ein Folder. ### 2. DFS Fuer DFS reicht die Share-Liste nicht aus. Hier muss zusaetzlich geprueft werden: - Ist `\\server\namespace` ein DFS-Namespace-Root? - Ist `\\server\namespace\link` ein DFS-Link? - Welche Link-Ziele sind hinterlegt? Aus dieser Sicht gilt: - `\\server\namespace` ist ein Namespace-Objekt, nicht einfach nur ein Folder. - `\\server\namespace\link` ist fachlich ein Share-aehnlicher Einstiegspunkt. - Jeder Pfad unterhalb eines DFS-Links ist ein Folder. ## Zielbild fuer Roots ### Fall 1: Root ist `\\server` Wenn `\\server` als Root erlaubt sein soll, muss die erste Ebene alle publizierten Einstiegspunkte des Servers liefern. Das bedeutet: - klassische Shares des Servers - DFS-Namespaces, die ueber diesen Server angesprochen werden koennen - administrative Shares wie `C$`, `ADMIN$`, `IPC$` sollten in der Regel herausgefiltert werden Unter `\\server` duerfen also nicht einfach Dateisystemordner enumeriert werden. Stattdessen werden Namensobjekte auf Server-Ebene enumeriert. Beispiele: - `\\server\shareA` -> `ClassicShare` - `\\server\dfs` -> `DfsNamespaceRoot` - `\\server\shareA\team1` -> `Folder` - `\\server\dfs\link1` -> `DfsLink` ### Fall 2: Root ist `\\server\share` Bei einem klassischen Share als Root ist die Bedeutung eindeutig: - Root selbst ist `ClassicShare` - alle darunter liegenden Eintraege sind `Folder` Hier ist die fachliche Share-Grenze der Root-Pfad selbst. ### Fall 3: Root ist `\\server\namespace` Bei einem DFS-Namespace als Root muss die erste Ebene nicht als Folderliste, sondern als Namespace-Inhaltsliste verstanden werden. Typischerweise bedeutet das: - Root selbst ist `DfsNamespaceRoot` - direkte Kinder koennen `DfsLink`-Objekte sein - alles unterhalb eines `DfsLink` ist `Folder` Ob der Namespace-Root selbst nach aussen als `NtfsShare` oder als eigener Container-Typ behandelt wird, ist eine fachliche API-Entscheidung. ### Fall 4: Root ist `\\server\namespace\link` Wenn der Root-Pfad bereits ein DFS-Link ist, dann gilt: - Root selbst ist `DfsLink` - alles darunter ist `Folder` Fuer die bestehende LIAM-Semantik waere das nach aussen typischerweise ein `NtfsShare`. ## Empfohlene zentrale Klassifikationslogik Die Klassifikation sollte in einer einzigen zentralen Komponente gebuendelt werden. Wichtig ist: - `getDataAreasAsync()` muss dieselbe Logik verwenden wie `LoadDataArea()` - die UI, Workflow-Aktivitaeten und Web-API duerfen nicht jeweils eigene Heuristiken haben Empfohlenes konzeptionelles Interface: ```text ClassifyPath(path) -> PathClassification EnumerateChildren(path) -> List ``` Eine `PathClassification` sollte mindestens enthalten: - `NormalizedPath` - `Kind` - `DisplayName` - `BoundaryPath` - `ParentBoundaryPath` - `BackingType` wie `SMB` oder `DFS` - optionale Diagnoseinformationen zur Herleitung ## Empfohlene Entscheidungsreihenfolge Die Aufloesung eines Pfads sollte in einer festen Reihenfolge passieren. ### Schritt 1: Pfad normalisieren Vor jeder Klassifikation: - UNC-Pfad vereinheitlichen - doppelte Separatoren bereinigen - optional Gross-/Kleinschreibung fuer Vergleiche normalisieren - Trailing Backslash konsistent behandeln Beispiele: - `\\server\share\` - `\\SERVER\share` - `\\server\\share` sollten intern auf einen stabilen Vergleichswert normalisiert werden. ### Schritt 2: Root-Typ erkennen Zuerst wird geprueft, ob der Pfad einer dieser Grundtypen ist: - Server-Root - klassischer Share - DFS-Namespace-Root - DFS-Link - Folder unterhalb eines bekannten Grenzpunkts ### Schritt 3: DFS zuerst pruefen Fuer UNC-Pfade mit mehreren Segmenten sollte zuerst geprueft werden, ob ein Pfad oder ein Pfadpraefix ein DFS-Namespace oder DFS-Link ist. Der Grund: - DFS kann Pfade erzeugen, die syntaktisch wie normale Ordner wirken - semantisch sind sie aber eigenstaendige Einstiegspunkte Wenn ein Praefix als DFS-Link identifiziert wird, ist dieses Praefix die fachliche Share-Grenze. Beispiel: - Pfad: `\\server\namespace\link\teamA\finance` - erkannter DFS-Link: `\\server\namespace\link` - Klassifikation des Gesamtpfads: `Folder` - fachlicher Parent-Share: `\\server\namespace\link` ### Schritt 4: Klassische Shares pruefen Wenn kein DFS-Fall vorliegt, wird geprueft, ob der Pfad oder ein Praefix einem klassischen Share entspricht. Beispiel: - Pfad: `\\server\share\dept\project` - erkannter Share: `\\server\share` - Klassifikation des Gesamtpfads: `Folder` - fachlicher Parent-Share: `\\server\share` ### Schritt 5: Fallback nur kontrolliert verwenden Wenn weder DFS noch klassischer Share sicher ermittelt werden kann: - nicht blind ueber Segmentzahl entscheiden - stattdessen `Unknown` liefern oder einen explizit konfigurierten Fallback nutzen Das ist wichtig, damit Unsicherheit nicht als scheinbar sichere Fachlogik maskiert wird. ## Share-Grenze als zentrales Konzept Ein hilfreiches Kernmodell ist die sogenannte Share-Grenze. Die Share-Grenze ist der fachliche Einstiegspunkt, unterhalb dessen normale Folder-Hierarchie beginnt. Beispiele: - `\\server\share` -> Share-Grenze bei klassischem SMB-Share - `\\server\namespace\link` -> Share-Grenze bei DFS-Link Ein Pfad wird damit nicht nur als `Share` oder `Folder` klassifiziert, sondern auch relativ zu seiner Share-Grenze verstanden. Das ist fuer mehrere Dinge wichtig: - korrektes Setzen von `ParentUID` - konsistente Anzeige des Root-Objekts - korrektes Nachladen von Kindern - spaetere Berechtigungs- oder Traverselogik ## Zielverhalten fuer typische Beispiele ### Beispiel A: Klassische Freigabe - `\\filesrv\finance` -> `ClassicShare` - `\\filesrv\finance\2026` -> `Folder` - `\\filesrv\finance\2026\plan.xlsx` -> fuer LIAM ggf. ausserhalb des Scope, falls nur Ordner modelliert werden ### Beispiel B: DFS-Namespace - `\\dfs01\file_shares` -> `DfsNamespaceRoot` - `\\dfs01\file_shares\shareA` -> `DfsLink` - `\\dfs01\file_shares\shareA\team1` -> `Folder` ### Beispiel C: Server-Root - `\\dfs01` -> `ServerRoot` - Kind `\\dfs01\file_shares` -> `DfsNamespaceRoot` - Kind `\\dfs01\public` -> `ClassicShare` ### Beispiel D: Gemischte Landschaft Ein Server kann gleichzeitig hosten: - klassische Shares - DFS-Namespaces - administrative Shares Die Enumeration unter `\\server` muss daher bewusst entscheiden, welche publizierten Namensobjekte sichtbar gemacht werden und welche nicht. ## Konsequenzen fuer die LIAM-Architektur ### 1. Eine gemeinsame Path-Classification-Schicht Die Logik darf nicht in mehreren Stellen verteilt bleiben. Stattdessen sollte es eine zentrale Schicht geben, die: - Pfade klassifiziert - Kindobjekte enumeriert - die Share-Grenze mitliefert - Diagnoseinformationen fuer Logging bereitstellt ### 2. `LoadDataArea()` und `getDataAreasAsync()` muessen dieselbe Semantik teilen Beide Methoden muessen dieselbe Klassifikation verwenden. Sonst entsteht wieder ein Fehlerbild wie heute: - Listenansicht liefert einen Typ - Einzelaufladung liefert einen anderen Typ Das ist fachlich unzulaessig. ### 3. Die Konstruktion von LIAM-Datenobjekten muss auf Klassifikation folgen Nicht: - Pfadtiefe bestimmen - direkt `cLiamNtfsShare` oder `cLiamNtfsFolder` erzeugen Sondern: 1. Pfad klassifizieren 2. daraus internes `Kind` bestimmen 3. danach passendes LIAM-Objekt erzeugen ### 4. Nach aussen kann die API zunaechst kompatibel bleiben Wenn eine API-Aenderung vermieden werden soll, koennen intern mehrere Arten von Share-artigen Objekten existieren, die nach aussen zunaechst auf `NtfsShare` gemappt werden. Beispiel: - `ClassicShare` -> `NtfsShare` - `DfsLink` -> `NtfsShare` - `DfsNamespaceRoot` -> je nach Entscheidung ebenfalls `NtfsShare` oder eigener Typ spaeter So laesst sich die Semantik verbessern, ohne sofort alle Konsumenten anpassen zu muessen. ## Technische Grenzen und Realitaet Die sichere Ermittlung ist programmatisch grundsaetzlich moeglich, aber an Infrastrukturbedingungen gebunden. Moegliche Einschraenkungen: - fehlende Rechte fuer Share- oder DFS-Abfragen - Firewall- oder RPC-Beschraenkungen - temporaer nicht verfuegbare Server - unterschiedliche Betriebsweisen in der Kundenumgebung Deshalb ist ein kontrollierter Unsicherheitszustand wichtig. Empfohlene Regel: - wenn die Semantik sicher ermittelt werden kann, klaren Typ liefern - wenn die Semantik nicht sicher ermittelt werden kann, `Unknown` oder einen expliziten diagnostischen Fehler liefern - nicht stillschweigend auf reine Pfadtiefe zurueckfallen, wenn dadurch fachlich falsche Typen entstehen ## Empfohlene Implementierungsstrategie in Etappen ### Etappe 1: Fachmodell einziehen Intern neue Klassifikationsarten definieren: - `ServerRoot` - `ClassicShare` - `DfsNamespaceRoot` - `DfsLink` - `Folder` - `Unknown` ### Etappe 2: Zentrale Klassifikationskomponente bauen Eine zentrale Komponente einfuehren, die: - Pfade normalisiert - Typen klassifiziert - Share-Grenzen bestimmt - Kinder kontextabhaengig enumeriert ### Etappe 3: `LoadDataArea()` umstellen `LoadDataArea()` sollte zuerst die neue Klassifikation verwenden, weil dort der heutige Fehlpfad am deutlichsten sichtbar ist. ### Etappe 4: `getDataAreasAsync()` umstellen Danach den Listenpfad auf dieselbe Klassifikation bringen. ### Etappe 5: API-Mapping pruefen Danach bewerten: - reicht extern weiter `NtfsShare` / `NtfsFolder` - oder wird spaeter ein eigener Typ fuer Namespace-Container benoetigt ## Entscheidungspunkte, die fachlich geklaert werden muessen Vor einer spaeteren Implementierung sollten einige Punkte explizit entschieden werden: - Soll `\\server` als sichtbares DataArea-Objekt existieren oder nur als Enumerationsroot? - Soll ein DFS-Namespace-Root nach aussen als `NtfsShare` gelten oder als eigener Container? - Sollen nur DFS-Links als Share-aehnliche Objekte gelten? - Sollen administrative Shares immer ausgeblendet werden? - Wie soll sich das System bei fehlenden Rechten fuer DFS-/Share-Abfragen verhalten? Ohne diese Entscheidungen wird die technische Umsetzung sonst schnell inkonsistent. ## Fazit Die bisherige Heuristik "Pfadtiefe bestimmt Share oder Folder" ist fuer eine Umgebung mit klassischen Shares, DFS und kuenftigem `\\server`-Root nicht ausreichend. Das richtige Zielbild ist: - zentrale semantische Pfadklassifikation - Unterscheidung von Server, klassischem Share, DFS-Namespace, DFS-Link und Folder - gemeinsame Logik fuer Listen- und Einzel-Ladepfad - externe Rueckgabe weiterhin kompatibel, intern aber fachlich korrekt modelliert Nur mit diesem Ansatz koennen spaeter sowohl klassische Freigaben als auch DFS-Strukturen sauber und nachvollziehbar behandelt werden.