diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IRawTreeService.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IRawTreeService.cs
new file mode 100644
index 00000000..bc0050c8
--- /dev/null
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IRawTreeService.cs
@@ -0,0 +1,44 @@
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
+
+///
+/// Loads and mutates the v3 Raw project tree (/raw) — the cluster-rooted
+/// Enterprise → Cluster → Folder → Driver → Device → TagGroup → Tag hierarchy — from the config
+/// database. The peer of for the Raw subtree.
+///
+/// Contract split (Batch 2 Wave A): this file's committed surface is the read contract
+/// the RawTree component consumes — (eager Enterprise→Cluster roots)
+/// and (one lazy level per expand). B2-WP1 (RawTreeService)
+/// extends this interface with the mutation surface — create/rename/delete per node type,
+/// move-into-folder, and the per-node edit projections — enforcing the integrity rules with
+/// user-readable errors (a delete blocked by a UnsTagReference names the referencing equipment).
+/// Rename methods return so the UI can show non-blocking warnings.
+/// Mutations reuse . WP2 must not add to this interface.
+///
+///
+public interface IRawTreeService
+{
+ ///
+ /// Loads the eager top of the Raw tree: Enterprise → Cluster roots, each cluster marked
+ /// so its folders + drivers load on first expand. Empty
+ /// clusters are retained so they stay visible and authorable. The returned nodes are detached
+ /// view-models, safe to hold and mutate UI state on after the underlying context is disposed.
+ ///
+ /// A token to cancel the load.
+ /// The enterprise roots, populated down to (but not through) their clusters.
+ Task> LoadRootsAsync(CancellationToken ct = default);
+
+ ///
+ /// Loads the direct children of one container node — the next level down, keyed off
+ /// 's and :
+ /// a Cluster yields its root Folders + Drivers; a Folder yields sub-Folders + Drivers; a Driver
+ /// yields its Devices; a Device yields its root TagGroups + Tags; a TagGroup yields sub-TagGroups
+ /// + Tags. Tags are leaves and yield nothing. Ordering is deterministic and ordinal. Reads
+ /// untracked; returns detached nodes. Per-device tag counts can be large — the implementation may
+ /// page, but the committed shape returns the level's nodes (paging knobs, if any, are WP1's to add
+ /// on the concrete type without changing this signature's meaning for the tree).
+ ///
+ /// The container node whose direct children to load.
+ /// A token to cancel the load.
+ /// The parent's direct child nodes; empty for a leaf or an empty container.
+ Task> LoadChildrenAsync(RawNode parent, CancellationToken ct = default);
+}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawNode.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawNode.cs
new file mode 100644
index 00000000..973a989c
--- /dev/null
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawNode.cs
@@ -0,0 +1,101 @@
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
+
+///
+/// The kind of node within the v3 Raw project tree (/raw). Determines how the
+/// renderer styles the row, which context-menu it shows, and which entity (if any) it
+/// links to. The Raw tree is cluster-rooted and mirrors the RawPath hierarchy:
+/// Enterprise → Cluster → Folder(s) → Driver → Device → TagGroup(s) → Tag.
+///
+public enum RawNodeKind
+{
+ /// Top-level grouping label (a string on cluster rows, not a DB entity).
+ Enterprise,
+
+ /// A server cluster — the root of a Raw project tree.
+ Cluster,
+
+ /// A driver-organizing RawFolder (nestable under a cluster or another folder).
+ Folder,
+
+ /// A DriverInstance.
+ Driver,
+
+ /// A Device under a driver (universal in v3 — every driver has ≥1).
+ Device,
+
+ /// A tag-organizing TagGroup (nestable under a device or another group).
+ TagGroup,
+
+ /// A raw Tag (signal) — a leaf.
+ Tag,
+}
+
+///
+/// View-model for a single node in the Raw project tree. Carries the stable identity,
+/// display text, per-kind ids, and lazy-load metadata the renderer needs, plus transient UI
+/// state (expansion/loading) that is never persisted. Detached from EF — safe to hold and
+/// mutate UI state on after the loading context is disposed. This is the shared contract
+/// between (which produces nodes) and the RawTree
+/// component (which renders + lazily expands them).
+///
+public sealed class RawNode
+{
+ /// The kind of node — drives styling, context-menu, and entity linking.
+ public required RawNodeKind Kind { get; init; }
+
+ /// Stable per-node key, unique within the tree (e.g. drv:{driverInstanceId}).
+ public required string Key { get; init; }
+
+ /// Human-readable label shown in the tree (the node's Name, or Enterprise/Cluster label).
+ public required string DisplayName { get; init; }
+
+ /// Owning cluster id for every node under a cluster (and the cluster itself); null for Enterprise.
+ public string? ClusterId { get; init; }
+
+ ///
+ /// This node's own logical entity id (RawFolderId/DriverInstanceId/DeviceId/
+ /// TagGroupId/TagId, or the ClusterId for a cluster); null for Enterprise. The
+ /// child loader keys off + this id to fetch the next level.
+ ///
+ public string? EntityId { get; init; }
+
+ ///
+ /// The bound DriverType for (and propagated to Device/TagGroup/Tag
+ /// nodes beneath it, so tag editors and the browse-enable gate can dispatch without another query);
+ /// null for folders/clusters/enterprise. Use the DriverTypeNames constants when matching.
+ ///
+ public string? DriverType { get; init; }
+
+ /// Whether a Driver/Device node is enabled (drives the enable/disable menu label + styling); true otherwise.
+ public bool Enabled { get; init; } = true;
+
+ /// Direct child count (for the badge). For a device this is its tag-group + tag count.
+ public int ChildCount { get; set; }
+
+ ///
+ /// Whether this node's children load lazily on expand. True for every container kind in the Raw tree
+ /// (Cluster/Folder/Driver/Device/TagGroup) — unlike the UNS tree, /raw actually exercises the
+ /// lazy plumbing (per-device tag counts can be large). Tags are leaves (false).
+ ///
+ public bool HasLazyChildren { get; init; }
+
+ /// Lazily-materialised children — empty until flips on expand.
+ public List Children { get; } = new();
+
+ /// Optimistic-concurrency token for this node's backing row (empty for Enterprise); echoed on mutations.
+ public byte[] RowVersion { get; init; } = Array.Empty();
+
+ // --- Runtime UI state (not persisted) ---
+
+ /// Whether the node is currently expanded in the UI.
+ public bool Expanded { get; set; }
+
+ /// Whether the node's lazy children have been loaded.
+ public bool Loaded { get; set; }
+
+ /// Whether a lazy-load is currently in flight for this node.
+ public bool Loading { get; set; }
+
+ /// Last load error message, if any.
+ public string? Error { get; set; }
+}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawRenameResult.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawRenameResult.cs
new file mode 100644
index 00000000..6db0eea3
--- /dev/null
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/RawRenameResult.cs
@@ -0,0 +1,24 @@
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
+
+///
+/// Outcome of a Raw-tree rename. Like it reports success/failure,
+/// but a rename additionally surfaces : non-blocking advisories the UI shows
+/// after the rename succeeds (a RawPath segment changed, so downstream references may need attention).
+/// In this batch the warnings answerable from the schema are wired — a renamed node with historized
+/// tags beneath it, or raw tags referenced by an equipment (UnsTagReference). Batch 3 adds the
+/// script-substring scan to the same list. On failure is false,
+/// carries the operator-facing message, and is empty.
+///
+/// Whether the rename was applied.
+/// The operator-facing failure message, or null on success.
+/// Non-blocking advisories to show after a successful rename; empty when there are none.
+public readonly record struct RawRenameResult(bool Ok, string? Error, IReadOnlyList Warnings)
+{
+ /// A successful rename carrying zero or more advisory warnings.
+ public static RawRenameResult Success(IReadOnlyList? warnings = null) =>
+ new(true, null, warnings ?? Array.Empty());
+
+ /// A failed rename carrying the operator-facing message.
+ public static RawRenameResult Failure(string error) =>
+ new(false, error, Array.Empty());
+}