diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/AttributeValueCodec.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/AttributeValueCodec.cs
new file mode 100644
index 00000000..c4abd822
--- /dev/null
+++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/AttributeValueCodec.cs
@@ -0,0 +1,99 @@
+using System.Collections;
+using System.Globalization;
+using System.Text.Json;
+using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
+
+namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
+
+///
+/// Canonical, round-trippable codec for attribute values. Scalars encode to an
+/// invariant-culture string (identical to the historical representation); List
+/// attributes encode to a JSON array. Used wherever a value is stored or
+/// transmitted (DB Value column, site SQLite, gRPC wire).
+/// remains a separate, display-only (comma-joined) formatter.
+///
+public static class AttributeValueCodec
+{
+ private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = false };
+
+ /// Encodes a value to its canonical string form.
+ public static string? Encode(object? value)
+ {
+ switch (value)
+ {
+ case null: return null;
+ case string s: return s; // already canonical
+ case IFormattable f: return f.ToString(null, CultureInfo.InvariantCulture);
+ case IEnumerable e:
+ var items = e.Cast