diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
index af852475d2edcdc0fd639c88849b31893b82e2c4..2545bf92c22355eb5cf8f6531cce8ce60e268ee1 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
@@ -11,9 +11,9 @@ package de.justjanne.libquassel.protocol.api.client
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
-import de.justjanne.libquassel.protocol.api.dto.AliasManagerDto
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.AliasManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("AliasManager", side = ProtocolSide.CORE)
@@ -21,5 +21,5 @@ interface AliasManagerClientApi {
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 
-  suspend fun update(properties: AliasManagerDto) = update(properties.serialize())
+  suspend fun update(properties: AliasManagerDto) = update(properties.let(AliasManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
index 31458443c58579b7cac04ecc9c7d8e94918088fa..148e65bcf077a9eae5829b4c897970bda3fdefac 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
@@ -13,9 +13,11 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BacklogManagerDto
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("BacklogManager", side = ProtocolSide.CORE)
 interface BacklogManagerClientApi {
@@ -91,4 +93,9 @@ interface BacklogManagerClientApi {
     @RpcParam.Int flags: Int = -1,
     @RpcParam.QVariantList messages: QVariantList
   )
+
+  @RpcCall("update")
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: BacklogManagerDto) = update(properties.let(BacklogManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
index c4b103b01e9462285f5b02beb4bd6f2de6b652e7..dc2fa257b624f845c4342c5c3d7bc0cfa734d894 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BufferSyncerDto
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -45,4 +46,6 @@ interface BufferSyncerClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: BufferSyncerDto) = update(properties.let(BufferSyncerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
index 6868a03bd595275f9c94b19f98121610de4624ec..aeb5b644884f4cdd24fd057f4b8e211b5b4d2368 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
@@ -14,6 +14,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.api.ObjectName
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -21,47 +22,49 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferViewConfig", side = ProtocolSide.CORE)
 interface BufferViewConfigClientApi {
   @RpcCall("addBuffer")
-  suspend fun addBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun addBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("moveBuffer")
-  suspend fun moveBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun moveBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("removeBuffer")
-  suspend fun removeBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun removeBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("removeBufferPermanently")
-  suspend fun removeBufferPermanently(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun removeBufferPermanently(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("setBufferViewName")
-  suspend fun setBufferViewName(@RpcParam.QString value: String)
+  suspend fun setBufferViewName(objectName: ObjectName, @RpcParam.QString value: String)
 
   @RpcCall("setAddNewBuffersAutomatically")
-  suspend fun setAddNewBuffersAutomatically(@RpcParam.Bool value: Boolean)
+  suspend fun setAddNewBuffersAutomatically(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("setAllowedBufferTypes")
-  suspend fun setAllowedBufferTypes(@RpcParam.Int value: Int)
+  suspend fun setAllowedBufferTypes(objectName: ObjectName, @RpcParam.Int value: Int)
 
   @RpcCall("setDisableDecoration")
-  suspend fun setDisableDecoration(@RpcParam.Bool value: Boolean)
+  suspend fun setDisableDecoration(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("setHideInactiveBuffers")
-  suspend fun setHideInactiveBuffers(@RpcParam.Bool value: Boolean)
+  suspend fun setHideInactiveBuffers(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("setHideInactiveNetworks")
-  suspend fun setHideInactiveNetworks(@RpcParam.Bool value: Boolean)
+  suspend fun setHideInactiveNetworks(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("setMinimumActivity")
-  suspend fun setMinimumActivity(@RpcParam.Int value: Int)
+  suspend fun setMinimumActivity(objectName: ObjectName, @RpcParam.Int value: Int)
 
   @RpcCall("setNetworkId")
-  suspend fun setNetworkId(@RpcParam.UserType.NetworkId value: NetworkId)
+  suspend fun setNetworkId(objectName: ObjectName, @RpcParam.UserType.NetworkId value: NetworkId)
 
   @RpcCall("setShowSearch")
-  suspend fun setShowSearch(@RpcParam.Bool value: Boolean)
+  suspend fun setShowSearch(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("setSortAlphabetically")
-  suspend fun setSortAlphabetically(@RpcParam.Bool value: Boolean)
+  suspend fun setSortAlphabetically(objectName: ObjectName, @RpcParam.Bool value: Boolean)
 
   @RpcCall("update")
-  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun update(objectName: ObjectName, properties: BufferViewConfigDto) = update(objectName, properties.let(BufferViewConfigDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
index 4e4996163bb42aaf9bda7ff9cb4c84eadbbb1e73..c291fb5565c66642c7e7c63feadd377867f474df 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BufferViewManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("BufferViewManager", side = ProtocolSide.CORE)
@@ -25,4 +26,6 @@ interface BufferViewManagerClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: BufferViewManagerDto) = update(properties.let(BufferViewManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
index 483dc46f42417963bd934589179f33af8b2e49c3..d990bce5efb2a1181a6a58570a59754c11654b16 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
@@ -19,12 +19,14 @@ import java.nio.ByteBuffer
 
 @RpcApi("CertManager", side = ProtocolSide.CORE)
 interface CertManagerClientApi {
-      @RpcCall("setSslCert")
+  @RpcCall("setSslCert")
   suspend fun setSslCert(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
 
-      @RpcCall("setSslKey")
+  @RpcCall("setSslKey")
   suspend fun setSslKey(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
 
-      @RpcCall("update")
+  @RpcCall("update")
   suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun update(objectName: ObjectName, properties: CertManagerDto) = update(objectName, properties.let(CertManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
index bc11a73aa4ca38191d9bff35784b414aa7f6f3a8..da4421efb3de2291ded5dc095fc041e1f325e93a 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.CoreInfoDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("CoreInfo", side = ProtocolSide.CORE)
@@ -22,4 +23,6 @@ interface CoreInfoClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: CoreInfoDto) = update(properties.let(CoreInfoDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
index 6161e4a7acda073fba3599d9c7b1bf77931a830e..d872c2b70374d32d12317833fc20382891fe9d6b 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.HighlightRuleManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("HighlightRuleManager", side = ProtocolSide.CORE)
@@ -44,4 +45,6 @@ interface HighlightRuleManagerClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: HighlightRuleManagerDto) = update(properties.let(HighlightRuleManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
index 56de68320835cb82352db92667922df101f22f15..56b800c693226525417440cfd0758b7aab59d4f5 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
@@ -14,6 +14,7 @@ import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -98,4 +99,6 @@ interface IdentityClientApi {
 
   @RpcCall("update")
   suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(objectName: ObjectName, properties: IdentityDto) = update(objectName, properties.let(IdentityDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
index b4141640dbe98aaf5a5d77a5d13b0b722f570c3a..e98f14c72dc4024ff88722a5ef939c4202bc87d5 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.IgnoreListManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("IgnoreListManager", side = ProtocolSide.CORE)
@@ -36,4 +37,6 @@ interface IgnoreListManagerClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: IgnoreListManagerDto) = update(properties.let(IgnoreListManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
index 4b0c8d08b38cf13e3fa9d0fe166b979381928dcb..19b0243a2475b24dae386353f46f6ae305f16ff4 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
@@ -14,6 +14,7 @@ import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
+import de.justjanne.libquassel.protocol.dto.IrcChannelDto
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
@@ -61,4 +62,6 @@ interface IrcChannelClientApi  {
 
   @RpcCall("update")
   suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(objectName: ObjectName, properties: IrcChannelDto) = update(objectName, properties.let(IrcChannelDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
index ed9bedbddebf03fbda92fd245d5639ee09123271..04a71876e13e851586ab7ef85479f761f08d5098 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
@@ -13,9 +13,11 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.IrcListHelperDto
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("IrcListHelper", side = ProtocolSide.CORE)
 interface IrcListHelperClientApi  {
@@ -27,4 +29,9 @@ interface IrcListHelperClientApi  {
 
   @RpcCall("reportFinishedList")
   suspend fun reportFinishedList(@RpcParam.UserType.NetworkId netId: NetworkId)
+
+  @RpcCall("update")
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: IrcListHelperDto) = update(properties.let(IrcListHelperDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
index 3af403320059554b9e6f9814ce51933597e85989..ea363da36371684ec7650545df74872a87abd830 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
@@ -14,6 +14,7 @@ import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
+import de.justjanne.libquassel.protocol.dto.IrcUserDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import org.threeten.bp.temporal.Temporal
 
@@ -90,5 +91,6 @@ interface IrcUserClientApi {
 
   @RpcCall("update")
   suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
-}
 
+  suspend fun update(objectName: ObjectName, properties: IrcUserDto) = update(objectName, properties.let(IrcUserDto.Serializer::serialize))
+}
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
index 256dc966427ec192b5c3b42e42b4260c7b926483..dcc2644ccde2e7d965737174a6572f0521bcd0a7 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
@@ -171,4 +171,6 @@ interface NetworkClientApi {
 
   @RpcCall("update")
   suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun update(objectName: ObjectName, properties: NetworkDto) = update(objectName, properties.let(NetworkDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
index 979dc070415ec82446256d5edaa7252dfff3d20c..757737f4c192900dff4d98560ea8ca5e4d460a61 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
@@ -13,6 +13,7 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.NetworkConfigDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("NetworkConfig", side = ProtocolSide.CORE)
@@ -43,4 +44,6 @@ interface NetworkConfigClientApi {
 
   @RpcCall("update")
   suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun update(properties: NetworkConfigDto) = update(properties.let(NetworkConfigDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt
deleted file mode 100644
index 1bc2087326410a0e3f1ed9bb6480f51b4a90559e..0000000000000000000000000000000000000000
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2025 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.api.dto
-
-import de.justjanne.libquassel.protocol.models.QStringList
-import de.justjanne.libquassel.protocol.models.types.QtType
-import de.justjanne.libquassel.protocol.variant.QVariantMap
-import de.justjanne.libquassel.protocol.variant.into
-import de.justjanne.libquassel.protocol.variant.qVariant
-
-data class AliasManagerDto(
-  val aliases: AliasesDto
-) {
-  data class AliasesDto(
-    val names: List<String?>,
-    val expansions: List<String?>
-  ) {
-    fun serialize(): QVariantMap = mapOf(
-      "names" to qVariant(names, QtType.QStringList),
-      "expansions" to qVariant(expansions, QtType.QStringList)
-    )
-
-    companion object {
-      fun deserialize(data: QVariantMap) = AliasesDto(
-        names = data["names"].into<QStringList>().orEmpty(),
-        expansions = data["expansions"].into<QStringList>().orEmpty(),
-      )
-    }
-  }
-
-  fun serialize(): QVariantMap = mapOf(
-    "Aliases" to qVariant(aliases.serialize(), QtType.QVariantMap)
-  )
-
-  companion object {
-    fun deserialize(data: QVariantMap) = AliasManagerDto(
-      aliases = data["Aliases"].into<QVariantMap>().orEmpty().let(AliasesDto::deserialize)
-    )
-  }
-}
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/BufferSyncerDto.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/BufferSyncerDto.kt
deleted file mode 100644
index 2791ced5a8aa64c20590c9a56bbb42abff5ba82c..0000000000000000000000000000000000000000
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/BufferSyncerDto.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2025 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.api.dto
-
-import de.justjanne.libquassel.protocol.models.ids.BufferId
-import de.justjanne.libquassel.protocol.models.ids.MsgId
-import de.justjanne.libquassel.protocol.models.types.QtType
-import de.justjanne.libquassel.protocol.models.types.QuasselType
-import de.justjanne.libquassel.protocol.util.collections.pairs
-import de.justjanne.libquassel.protocol.variant.QVariantList
-import de.justjanne.libquassel.protocol.variant.QVariantMap
-import de.justjanne.libquassel.protocol.variant.QVariant_
-import de.justjanne.libquassel.protocol.variant.into
-import de.justjanne.libquassel.protocol.variant.qVariant
-
-private typealias BufferMap = Map<BufferId, QVariant_>
-
-private fun BufferMap.toVariantList(): QVariantList = entries.flatMap {
-  listOf(qVariant(it.key, QuasselType.BufferId), it.value)
-}
-
-private fun QVariantList.toBufferMap(): BufferMap = pairs { key, value ->
-  Pair(key.into<BufferId>() ?: return@pairs null, value)
-}.filterNotNull().toMap()
-
-data class BufferSyncerDto(
-  val activities: Map<BufferId, Int>,
-  val highlightCounts: Map<BufferId, Int>,
-  val lastSeenMsg: Map<BufferId, MsgId>,
-  val markerLines: Map<BufferId, MsgId>,
-) {
-
-  fun serialize(): QVariantMap = mapOf(
-    "Activities" to qVariant(
-      activities.flatMap {
-        listOf(
-          qVariant(it.key, QuasselType.BufferId),
-          qVariant(it.value, QtType.Int),
-        )
-      },
-      QtType.QVariantList
-    ),
-    "HighlightCounts" to qVariant(
-      highlightCounts.flatMap {
-        listOf(
-          qVariant(it.key, QuasselType.BufferId),
-          qVariant(it.value, QtType.Int),
-        )
-      },
-      QtType.QVariantList
-    ),
-    "LastSeenMsg" to qVariant(
-      lastSeenMsg.flatMap {
-        listOf(
-          qVariant(it.key, QuasselType.BufferId),
-          qVariant(it.value, QuasselType.MsgId),
-        )
-      },
-      QtType.QVariantList
-    ),
-    "MarkerLines" to qVariant(
-      markerLines.flatMap {
-        listOf(
-          qVariant(it.key, QuasselType.BufferId),
-          qVariant(it.value, QuasselType.MsgId),
-        )
-      },
-      QtType.QVariantList
-    ),
-  )
-
-  companion object {
-    fun deserialize(data: QVariantMap) = BufferSyncerDto(
-      activities = data["Activities"].into<QVariantList>().orEmpty().pairs { key, value ->
-        Pair(
-          key.into<BufferId>() ?: return@pairs null,
-          value.into<Int>() ?: return@pairs null
-        )
-      }.filterNotNull().toMap(),
-      highlightCounts = data["HighlightCounts"].into<QVariantList>().orEmpty().pairs { key, value ->
-        Pair(
-          key.into<BufferId>() ?: return@pairs null,
-          value.into<Int>() ?: return@pairs null
-        )
-      }.filterNotNull().toMap(),
-      lastSeenMsg = data["LastSeenMsg"].into<QVariantList>().orEmpty().pairs { key, value ->
-        Pair(
-          key.into<BufferId>() ?: return@pairs null,
-          value.into<MsgId>() ?: return@pairs null
-        )
-      }.filterNotNull().toMap(),
-      markerLines = data["MarkerLines"].into<QVariantList>().orEmpty().pairs { key, value ->
-        Pair(
-          key.into<BufferId>() ?: return@pairs null,
-          value.into<MsgId>() ?: return@pairs null
-        )
-      }.filterNotNull().toMap(),
-    )
-  }
-}
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
index 3682c13c6c9fa4c8975ce21e711a7451ea955b55..121fd61f24868a95dc91acfa6eaf993926ee8b52 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
@@ -11,9 +11,9 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
-import de.justjanne.libquassel.protocol.api.dto.AliasManagerDto
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.AliasManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("AliasManager", side = ProtocolSide.CLIENT)
@@ -25,9 +25,7 @@ interface AliasManagerServerApi {
   )
 
   @RpcCall("requestUpdate")
-  suspend fun requestUpdate(
-    @RpcParam.QVariantMap properties: QVariantMap
-  )
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
 
-  suspend fun requestUpdate(properties: AliasManagerDto) = requestUpdate(properties.serialize())
+  suspend fun requestUpdate(properties: AliasManagerDto) = requestUpdate(properties.let(AliasManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
index 786db4502dc53a4e6273965d62eb80ed3be27c9c..e0d7d7db7d1307f72262eebef10d67f7eb754201 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
@@ -11,10 +11,12 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BacklogManagerDto
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("BacklogManager", side = ProtocolSide.CLIENT)
 interface BacklogManagerServerApi {
@@ -113,4 +115,9 @@ interface BacklogManagerServerApi {
     @RpcParam.Int type: Int = -1,
     @RpcParam.Int flags: Int = -1
   )
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: BacklogManagerDto) = requestUpdate(properties.let(BacklogManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
index 785f142b680cdcc5d50e236e4acf143f4707c7ae..77fc79251420162faf67d3492b8090c4695ebb9b 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
@@ -11,8 +11,9 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BufferSyncerDto
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -54,4 +55,6 @@ interface BufferSyncerServerApi {
 
   @RpcCall("requestUpdate")
   suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: BufferSyncerDto) = requestUpdate(properties.let(BufferSyncerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
index b4e1805c9f5ead1c19c425ad3f85d149f9303278..c8e4ac30ca175931a31cb04680e28a17a03f37b5 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
@@ -11,8 +11,8 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -36,4 +36,6 @@ interface BufferViewConfigServerApi {
 
   @RpcCall("requestUpdate")
   suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun requestUpdate(objectName: ObjectName, properties: BufferViewConfigDto) = requestUpdate(objectName, properties.let(BufferViewConfigDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
index 6a2e77c132efbdbd51a1c2f96abb2282b7251451..5b0530efc92a8fd33e3f1d5851718bd757e21c28 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
@@ -11,8 +11,9 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.BufferViewManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
@@ -26,5 +27,10 @@ interface BufferViewManagerServerApi {
 
   @RpcCall("requestDeleteBufferView")
   suspend fun requestDeleteBufferView(@RpcParam.Int bufferViewConfigId: Int)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: BufferViewManagerDto) = requestUpdate(properties.let(BufferViewManagerDto.Serializer::serialize))
 }
 
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
index c8b86931875508d70857ec81bc1ae6eaf4000344..8ee8f65f0add10077f945767ec978d9ce36f4de9 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
@@ -11,8 +11,8 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
@@ -20,4 +20,6 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 interface CertManagerServerApi {
   @RpcCall("requestUpdate")
   suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun requestUpdate(objectName: ObjectName, properties: CertManagerDto) = requestUpdate(objectName, properties.let(CertManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
index 9751f27a344d67eda0482298f7cc3f5493e5340c..04739b32f41d3afd7b71b30086a0f387b18856a8 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
@@ -10,9 +10,11 @@
 package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
-import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcApi
+import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.HighlightRuleManagerDto
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("HighlightRuleManager", side = ProtocolSide.CLIENT)
 interface HighlightRuleManagerServerApi {
@@ -40,4 +42,9 @@ interface HighlightRuleManagerServerApi {
 
   @RpcCall("requestSetNicksCaseSensitive")
   suspend fun requestSetNicksCaseSensitive(@RpcParam.Bool nicksCaseSensitive: Boolean)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: HighlightRuleManagerDto) = requestUpdate(properties.let(HighlightRuleManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
index 05fe4baf77dbb0f787bef997f49652d76356380b..b32fdd1b590bb016f313b0a35de7ed6f23ad12ea 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
@@ -10,14 +10,17 @@
 package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
-import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcApi
+import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("Identity", side = ProtocolSide.CLIENT)
 interface IdentityServerApi {
   @RpcCall("requestUpdate")
   suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(objectName: ObjectName, properties: IdentityDto) = requestUpdate(objectName, properties.let(IdentityDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
index ed5716512f72902d2cd990c13edfc70b8781d908..0377a43e4f0c94e11bb166075f1d7bd79f57b675 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
@@ -13,6 +13,8 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.IgnoreListManagerDto
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("IgnoreListManager", side = ProtocolSide.CLIENT)
 interface IgnoreListManagerServerApi {
@@ -32,4 +34,9 @@ interface IgnoreListManagerServerApi {
 
   @RpcCall("requestToggleIgnoreRule")
   suspend fun requestToggleIgnoreRule(@RpcParam.QString ignoreRule: String?)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: IgnoreListManagerDto) = requestUpdate(properties.let(IgnoreListManagerDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
index 2e2eff212a676c47c2490a1a6e2550882b6d1abd..7f3242aad59bdb5bad30118ae9975f30c075552f 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
@@ -11,13 +11,20 @@ package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.IrcListHelperDto
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("IrcListHelper", side = ProtocolSide.CLIENT)
 interface IrcListHelperServerApi {
   @RpcCall("requestChannelList")
   suspend fun requestChannelList(@RpcParam.UserType.NetworkId netId: NetworkId, @RpcParam.QStringList channelFilters: QStringList)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: IrcListHelperDto) = requestUpdate(properties.let(IrcListHelperDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
index 7e8e6e43f032710ee771a082687fea01c3517c7f..e49431127645e4331fe43f9d8a679304e3109ea1 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
@@ -10,9 +10,11 @@
 package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
-import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcApi
+import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.NetworkConfigDto
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("NetworkConfig", side = ProtocolSide.CLIENT)
 interface NetworkConfigServerApi {
@@ -39,4 +41,9 @@ interface NetworkConfigServerApi {
 
   @RpcCall("requestSetStandardCtcp")
   suspend fun requestSetStandardCtcp(@RpcParam.Bool enabled: Boolean)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+
+  suspend fun requestUpdate(properties: NetworkConfigDto) = requestUpdate(properties.let(NetworkConfigDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
index 14b73286cbf98bf19301a745d438f1b5bd2c6383..452d24b081fb8764cf035446a8db10278b8d8750 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
@@ -10,11 +10,12 @@
 package de.justjanne.libquassel.protocol.api.server
 
 import de.justjanne.libquassel.annotations.ProtocolSide
-import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcApi
+import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.api.ObjectName
-import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
+import de.justjanne.libquassel.protocol.dto.NetworkInfoDto
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi("Network", side = ProtocolSide.CLIENT)
 interface NetworkServerApi {
@@ -26,4 +27,9 @@ interface NetworkServerApi {
 
   @RpcCall("requestSetNetworkInfo")
   suspend fun requestSetNetworkInfo(objectName: ObjectName, @RpcParam.UserType.NetworkInfo info: NetworkInfoDto)
+
+  @RpcCall("requestUpdate")
+  suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+
+  //suspend fun requestUpdate(properties: NetworkDto) = requestUpdate(properties.let(NetworkDto.Serializer::serialize))
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
index 5dfae0da550320e4f0c5e641c5692bc20a70c7c4..c852df870031410d9d6e1e190b585ed10d4a9a5e 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
@@ -13,11 +13,11 @@ import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
 import de.justjanne.libquassel.annotations.RpcCall
 import de.justjanne.libquassel.annotations.RpcParam
+import de.justjanne.libquassel.protocol.dto.IdentityDto
+import de.justjanne.libquassel.protocol.dto.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
-import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
 @RpcApi(side = ProtocolSide.CLIENT)
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
index 56e55a5114e75aa5892fae64a8ae4503b146a9a0..6d2dcd05f090d32a01aeca9aa0b4557fb96624b6 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
@@ -12,7 +12,7 @@ package de.justjanne.libquassel.backend
 import de.justjanne.libquassel.persistence.AliasEntity
 import de.justjanne.libquassel.persistence.AliasRepository
 import de.justjanne.libquassel.protocol.api.client.AliasManagerClientApi
-import de.justjanne.libquassel.protocol.api.dto.AliasManagerDto
+import de.justjanne.libquassel.protocol.dto.AliasManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
@@ -20,17 +20,10 @@ class AliasManagerPersister @Inject constructor(
   private val repository: AliasRepository,
 ) : AliasManagerClientApi {
   override suspend fun update(properties: QVariantMap) {
-    val data = AliasManagerDto.deserialize(properties)
-    val names = data.aliases.names.requireNoNulls()
-    val expansions = data.aliases.expansions.requireNoNulls()
-    require(names.size == expansions.size) {
-      "Sizes do not match: names=${names.size}, expansions=${expansions.size}"
-    }
-
-    val aliases = names.zip(expansions).mapIndexed { index, (name, expansion) ->
+    val data = AliasManagerDto.Serializer.deserialize(properties)
+    val aliases = data.aliases.mapIndexed { index, (name, expansion) ->
       AliasEntity(index, name, expansion)
     }
-
     repository.sync(aliases)
   }
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
index ce3001a058c6bef2f266d2395aea42bb4e229df6..7345cb9622abe59920d36ae45bcce064023b7356 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
@@ -16,6 +16,7 @@ import de.justjanne.libquassel.protocol.models.Message
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import javax.inject.Inject
 
@@ -29,4 +30,5 @@ class BacklogManagerPersister @Inject constructor(
   override suspend fun receiveBacklogForward(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
   override suspend fun receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList)  = Unit
   override suspend fun receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
+  override suspend fun update(properties: QVariantMap) = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
index 43bf4f468f652ca282e74150ca0b20d22676a143..c95ad80a07506cdd0bb6e4fc7a2ae300d4e7f0ad 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
@@ -11,7 +11,7 @@ package de.justjanne.libquassel.backend
 
 import de.justjanne.libquassel.persistence.BufferRepository
 import de.justjanne.libquassel.protocol.api.client.BufferSyncerClientApi
-import de.justjanne.libquassel.protocol.api.dto.BufferSyncerDto
+import de.justjanne.libquassel.protocol.dto.BufferSyncerDto
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -21,7 +21,7 @@ class BufferSyncerPersister @Inject constructor(
   private val repository: BufferRepository,
 ) : BufferSyncerClientApi {
   override suspend fun update(properties: QVariantMap) {
-    val data = BufferSyncerDto.deserialize(properties)
+    val data = BufferSyncerDto.Serializer.deserialize(properties)
     repository.syncActivites(data.activities)
     repository.syncHighlightCounts(data.highlightCounts)
     repository.syncLastSeenMsgs(data.lastSeenMsg)
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
index d237e96b25e5a9f6a5fa482822ef9e0ed6d96396..a60b2b0165b85f971eb17ac13be4344b04905643 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
@@ -9,6 +9,7 @@
 
 package de.justjanne.libquassel.backend
 
+import de.justjanne.libquassel.protocol.api.ObjectName
 import de.justjanne.libquassel.protocol.api.client.BufferViewConfigClientApi
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
@@ -16,19 +17,19 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class BufferViewConfigPersister @Inject constructor(): BufferViewConfigClientApi {
-  override suspend fun addBuffer(buffer: BufferId, pos: Int)  = Unit
-  override suspend fun moveBuffer(buffer: BufferId, pos: Int)  = Unit
-  override suspend fun removeBuffer(buffer: BufferId)  = Unit
-  override suspend fun removeBufferPermanently(buffer: BufferId)  = Unit
-  override suspend fun setBufferViewName(value: String)  = Unit
-  override suspend fun setAddNewBuffersAutomatically(value: Boolean)  = Unit
-  override suspend fun setAllowedBufferTypes(value: Int)  = Unit
-  override suspend fun setDisableDecoration(value: Boolean)  = Unit
-  override suspend fun setHideInactiveBuffers(value: Boolean)  = Unit
-  override suspend fun setHideInactiveNetworks(value: Boolean)  = Unit
-  override suspend fun setMinimumActivity(value: Int)  = Unit
-  override suspend fun setNetworkId(value: NetworkId)  = Unit
-  override suspend fun setShowSearch(value: Boolean)  = Unit
-  override suspend fun setSortAlphabetically(value: Boolean)  = Unit
-  override suspend fun update(properties: QVariantMap)  = Unit
+  override suspend fun addBuffer(objectName: ObjectName, buffer: BufferId, pos: Int)  = Unit
+  override suspend fun moveBuffer(objectName: ObjectName, buffer: BufferId, pos: Int)  = Unit
+  override suspend fun removeBuffer(objectName: ObjectName, buffer: BufferId)  = Unit
+  override suspend fun removeBufferPermanently(objectName: ObjectName, buffer: BufferId)  = Unit
+  override suspend fun setBufferViewName(objectName: ObjectName, value: String)  = Unit
+  override suspend fun setAddNewBuffersAutomatically(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun setAllowedBufferTypes(objectName: ObjectName, value: Int)  = Unit
+  override suspend fun setDisableDecoration(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun setHideInactiveBuffers(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun setHideInactiveNetworks(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun setMinimumActivity(objectName: ObjectName, value: Int)  = Unit
+  override suspend fun setNetworkId(objectName: ObjectName, value: NetworkId)  = Unit
+  override suspend fun setShowSearch(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun setSortAlphabetically(objectName: ObjectName, value: Boolean)  = Unit
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
index 0484ff3f456c4fef661f210dd8ee60c10fb4bc69..5428185d09ce51ebe5a3a64fb4bf89a45c2f28ea 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
@@ -13,10 +13,12 @@ import de.justjanne.libquassel.protocol.api.client.IrcListHelperClientApi
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class IrcListHelperPersister @Inject constructor(): IrcListHelperClientApi {
   override suspend fun receiveChannelList(netId: NetworkId, channelFilters: QStringList, channels: QVariantList)  = Unit 
   override suspend fun reportError(error: String?)  = Unit 
   override suspend fun reportFinishedList(netId: NetworkId)  = Unit
+  override suspend fun update(properties: QVariantMap) = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt
index c470ea87cbe7eaeeb687ea1ff1f2a74c5833ac09..09fe4ffe9a702e4ddcb6ea31fc84732fee188d55 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt
@@ -36,8 +36,20 @@ class ClientSessionHandler(
 
     val initRequests = listOf(
       Pair("AliasManager", ""),
-      Pair("BufferSyncer", "")
+      Pair("BufferSyncer", ""),
+      Pair("BufferViewManager", ""),
+      Pair("CoreInfo", ""),
+      Pair("IgnoreListManager", ""),
+      Pair("HighlightRuleManager", ""),
+      Pair("IrcListHelper", ""),
+      Pair("NetworkConfig", "GlobalNetworkConfig"),
+      Pair("BacklogManager", ""),
     )
+      /*
+      .plus(handshake.sessionInit.networkIds.map { Pair("Network", "${it.id}") })
+      .plus(handshake.sessionInit.identities.map { Pair("Identity", "${it.identityId.id}") })
+      .plus(handshake.sessionInit.identities.map { Pair("CertManager", "${it.identityId.id}") })
+       */
 
     bufferRepository.sync(handshake.sessionInit.bufferInfos)
 
@@ -47,8 +59,10 @@ class ClientSessionHandler(
     }
 
     while (true) {
+      println("Reading:")
       val message = connection.read { SignalProxyMessageSerializer.deserialize(it, handshake.clientInitAck.featureSet) }
       println("Receive: $message")
+      println("Waiting: ${toInit.value}")
       when (message) {
         is SignalProxyMessage.HeartBeat -> connection.send(SignalProxyMessage.HeartBeatReply(message.timestamp))
         is SignalProxyMessage.HeartBeatReply -> Unit
@@ -60,6 +74,7 @@ class ClientSessionHandler(
         is SignalProxyMessage.Rpc -> rpc.invoke(message.slotName, message.params)
         is SignalProxyMessage.Sync -> sync.invoke(message.className, ObjectName(message.objectName), message.slotName, message.params)
       }
+      println("Finished")
     }
   }
 }
diff --git a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
index bacd285d3ae9d0d21e93341b269112ba8c329e46..f8650bb512d99947fc25c62d67c9bff07c086e97 100644
--- a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
+++ b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
@@ -82,7 +82,6 @@ import de.justjanne.libquassel.protocol.connection.ProtocolVersion
 import de.justjanne.libquassel.protocol.exceptions.RpcInvocationFailedException
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.CoroutineChannel
-import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.models.SignalProxyMessage
 import de.justjanne.libquassel.protocol.models.ids.BufferId
@@ -94,7 +93,6 @@ import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.qVariant
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.collectLatest
@@ -103,9 +101,7 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withTimeout
 import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
 import java.net.InetSocketAddress
-import java.nio.channels.ClosedByInterruptException
 import javax.inject.Inject
 import javax.inject.Singleton
 import kotlin.test.assertFails
@@ -137,6 +133,19 @@ class ProxyImpl @Inject constructor(
   }
 }
 
+@Singleton
+class OfflineProxyImpl @Inject constructor() : Proxy {
+  override suspend fun sync(className: String, objectName: ObjectName, function: String, params: QVariantList) {
+    val message = SignalProxyMessage.Sync(className, objectName.objectName, function, params)
+    println("Send: $message")
+  }
+
+  override suspend fun rpc(function: String, params: QVariantList) {
+    val message = SignalProxyMessage.Rpc(function, params)
+    println("Send: $message")
+  }
+}
+
 @Module
 interface ClientModule {
   @Binds fun bindAliasManagerPersister(impl: AliasManagerPersister): AliasManagerClientApi
@@ -155,9 +164,18 @@ interface ClientModule {
   @Binds fun bindNetworkConfigPersister(impl: NetworkConfigPersister): NetworkConfigClientApi
   @Binds fun bindNetworkPersister(impl: NetworkPersister): NetworkClientApi
   @Binds fun bindRpcPersister(impl: RpcPersister): RpcClientApi
+}
+
+@Module
+interface OnlineClientModule {
   @Binds fun bindProxy(impl: ProxyImpl): Proxy
 }
 
+@Module
+interface OfflineClientModule {
+  @Binds fun bindProxy(impl: OfflineProxyImpl): Proxy
+}
+
 @Module
 class DatabaseModule {
   @Singleton
@@ -194,7 +212,7 @@ class QuasselApiClient @Inject constructor(
 )
 
 @Singleton
-@Component(modules = [ClientModule::class, DatabaseModule::class, ClientDispatcherModule::class, ClientProxyModule::class])
+@Component(modules = [ClientModule::class, OnlineClientModule::class, DatabaseModule::class, ClientDispatcherModule::class, ClientProxyModule::class])
 interface ClientComponent {
   fun db(): AppDatabase
   fun sync(): SyncHandler
@@ -209,10 +227,19 @@ interface ClientComponent {
   }
 }
 
+@Singleton
+@Component(modules = [ClientModule::class, OfflineClientModule::class, DatabaseModule::class, ClientDispatcherModule::class, ClientProxyModule::class])
+interface OfflineClientComponent {
+  fun db(): AppDatabase
+  fun sync(): SyncHandler
+  fun rpc(): RpcDispatcher
+  fun api(): QuasselApiClient
+}
+
 class QuasselApiTest {
   @Test
   fun test() = runBlocking {
-    val client = DaggerClientComponent.builder().build()
+    val client = DaggerOfflineClientComponent.builder().build()
     client.sync().invoke(
       "AliasManager",
       ObjectName(""),
@@ -300,15 +327,16 @@ class QuasselApiTest {
     launch {
       sessionHandler.handle(connection)
     }
-    withTimeout(2.seconds) {
+    withTimeout(20.seconds) {
       sessionHandler.toInit.first { it != null && it.isEmpty() }
     }
     val bufferInfo = handshake.sessionInit.bufferInfos.first { it.bufferName == "#quassel-test" }
-    di.api().rpc.sendInput(bufferInfo, "/SAY Test from libquassel?")
-    delay(15.seconds)
+    di.api().rpc.sendInput(bufferInfo, "/PRINT Test from libquassel?")
+    delay(1.seconds)
     channel.close()
     println(di.db().alias().getAll())
     println(di.db().buffer().getAll())
+    println(di.db().message().getAll())
     Unit
   }
 }
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageRepository.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageRepository.kt
index 7cb353a61ade13c6f317924c5bd0a38520dc36a9..31878144b9d667457600f25d03c4f3ed396c4006 100644
--- a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageRepository.kt
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageRepository.kt
@@ -19,6 +19,12 @@ import kotlinx.coroutines.flow.Flow
 
 @Dao
 interface MessageRepository {
+  @Query("SELECT * FROM MessageEntity ORDER BY messageId ASC")
+  suspend fun getAll(): List<MessageEntity>
+
+  @Query("SELECT * FROM MessageEntity ORDER BY messageId ASC")
+  fun collectAll(): Flow<List<MessageEntity>>
+
   @Query("SELECT * FROM MessageEntity WHERE buffer = :buffer ORDER BY messageId ASC")
   suspend fun getAll(buffer: BufferId): List<MessageEntity>
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/AliasManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/AliasManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..de3036be99f0d1c9f4f2bccc469a6c69c4ac1282
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/AliasManagerDto.kt
@@ -0,0 +1,66 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class AliasManagerDto(
+  val aliases: List<AliasDto>
+) {
+  data class AliasDto(
+    val name: String,
+    val expansion: String,
+  )
+
+  object Serializer : SyncableSerializer<AliasManagerDto> {
+    override fun serialize(data: AliasManagerDto): QVariantMap = mapOf(
+      "Aliases" to qVariant(mapOf(
+        "names" to qVariant(data.aliases.map { it.name }, QtType.QStringList),
+        "expansions" to qVariant(data.aliases.map { it.expansion }, QtType.QStringList),
+      ), QtType.QVariantMap),
+    )
+
+    override fun deserialize(data: QVariantMap): AliasManagerDto = AliasManagerDto(
+      aliases = data["Aliases"].into<QVariantMap>()?.let { aliases ->
+        val names = aliases["names"].into<QStringList>().orEmpty().map { it ?: "" }
+        val expansions = aliases["expansions"].into<QStringList>().orEmpty().map { it ?: "" }
+        if (names.size != expansions.size) return@let null
+        names.indices.map { index ->
+          AliasDto(
+            name = names[index],
+            expansion = expansions[index],
+          )
+        }
+        names.zip(expansions, ::AliasDto)
+      }.orEmpty()
+    )
+  }
+
+  companion object {
+    val Defaults = AliasManagerDto(
+      aliases = listOf(
+        AliasDto("j", "/join $0"),
+        AliasDto("ns", "/quote nickserv $0"),
+        AliasDto("nickserv", "/quote nickserv $0"),
+        AliasDto("cs", "/quote chanserv $0"),
+        AliasDto("chanserv", "/quote chanserv $0"),
+        AliasDto("hs", "/quote hostserv $0"),
+        AliasDto("hostserv", "/quote hostserv $0"),
+        AliasDto("wii", "/whois $0 $0"),
+        AliasDto("back", "/quote away"),
+        AliasDto("raw", "/quote $0"),
+      )
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BacklogManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BacklogManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bc134fff6a6c8264296664727ebda6b110ca2518
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BacklogManagerDto.kt
@@ -0,0 +1,19 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data object BacklogManagerDto {
+  object Serializer : SyncableSerializer<BacklogManagerDto> {
+    override fun serialize(data: BacklogManagerDto): QVariantMap = emptyMap()
+    override fun deserialize(data: QVariantMap) = BacklogManagerDto
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferSyncerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferSyncerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d8321d30a769d0cc4fcb7928faa9b10e60f572d4
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferSyncerDto.kt
@@ -0,0 +1,85 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.ids.BufferId
+import de.justjanne.libquassel.protocol.models.ids.MsgId
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.models.types.QuasselType
+import de.justjanne.libquassel.protocol.util.collections.pairs
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class BufferSyncerDto(
+  val activities: Map<BufferId, Int>,
+  val highlightCounts: Map<BufferId, Int>,
+  val lastSeenMsg: Map<BufferId, MsgId>,
+  val markerLines: Map<BufferId, MsgId>,
+) {
+  object Serializer : SyncableSerializer<BufferSyncerDto> {
+    private inline fun <reified T> QVariantList.deserialize(): Map<BufferId, T> = pairs { key, value ->
+      Pair(
+        key.into<BufferId>() ?: return@pairs null,
+        value.into<T>() ?: return@pairs null
+      )
+    }.filterNotNull().toMap()
+
+    private inline fun <reified T> Map<BufferId, T>.serialize(type: QuasselType): QVariantList = flatMap {
+      listOf(
+        qVariant(it.key, QuasselType.BufferId),
+        qVariant(it.value, type),
+      )
+    }
+
+    private inline fun <reified T> Map<BufferId, T>.serialize(type: QtType): QVariantList = flatMap {
+      listOf(
+        qVariant(it.key, QuasselType.BufferId),
+        qVariant(it.value, type),
+      )
+    }
+
+    override fun serialize(data: BufferSyncerDto): QVariantMap = mapOf(
+      "Activities" to qVariant(
+        data.activities.serialize(QtType.Int),
+        QtType.QVariantList
+      ),
+      "HighlightCounts" to qVariant(
+        data.highlightCounts.serialize(QtType.Int),
+        QtType.QVariantList
+      ),
+      "LastSeenMsg" to qVariant(
+        data.lastSeenMsg.serialize(QuasselType.MsgId),
+        QtType.QVariantList
+      ),
+      "MarkerLines" to qVariant(
+        data.markerLines.serialize(QuasselType.MsgId),
+        QtType.QVariantList
+      ),
+    )
+
+    override fun deserialize(data: QVariantMap) = BufferSyncerDto(
+      activities = data["Activities"].into<QVariantList>()?.deserialize() ?: Defaults.activities,
+      highlightCounts = data["HighlightCounts"].into<QVariantList>()?.deserialize() ?: Defaults.highlightCounts,
+      lastSeenMsg = data["LastSeenMsg"].into<QVariantList>()?.deserialize() ?: Defaults.lastSeenMsg,
+      markerLines = data["MarkerLines"].into<QVariantList>()?.deserialize() ?: Defaults.markerLines,
+    )
+  }
+
+  companion object {
+    val Defaults = BufferSyncerDto(
+      activities = emptyMap(),
+      highlightCounts = emptyMap(),
+      lastSeenMsg = emptyMap(),
+      markerLines = emptyMap(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewConfigDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewConfigDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f50815810a5ddd5004bfec65c19d862ef06a7446
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewConfigDto.kt
@@ -0,0 +1,33 @@
+
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class BufferViewConfigDto(
+  val `null`: Nothing,
+) {
+  object Serializer : SyncableSerializer<BufferViewConfigDto> {
+    override fun serialize(data: BufferViewConfigDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = BufferViewConfigDto(
+      TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = BufferViewConfigDto(
+      TODO()
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f43afda124c32c2d5daf4451788979ebc67b54b7
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/BufferViewManagerDto.kt
@@ -0,0 +1,39 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class BufferViewManagerDto(
+  val ids: List<Int> ,
+) {
+  object Serializer : SyncableSerializer<BufferViewManagerDto> {
+    override fun serialize(data: BufferViewManagerDto): QVariantMap = mapOf(
+      "BufferViewIds" to qVariant(
+        data.ids.map { qVariant(it, QtType.Int) },
+        QtType.QVariantList,
+      )
+    )
+
+    override fun deserialize(data: QVariantMap) = BufferViewManagerDto(
+      data["BufferViewIds"].into<QVariantList>()?.mapNotNull { it.into<Int>() } ?: Defaults.ids
+    )
+  }
+
+  companion object {
+    val Defaults = BufferViewManagerDto(
+      ids = emptyList(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CertManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CertManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..29edd07e3f462e5cf46d6fa9e01f70835f3aa4ec
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CertManagerDto.kt
@@ -0,0 +1,32 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class CertManagerDto(
+  val `null`: Nothing,
+) {
+  object Serializer : SyncableSerializer<CertManagerDto> {
+    override fun serialize(data: CertManagerDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = CertManagerDto(
+      TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = CertManagerDto(
+      TODO()
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CoreInfoDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CoreInfoDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d5a7fa72713a74f7b8c7513f5f0669d1968427c8
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/CoreInfoDto.kt
@@ -0,0 +1,87 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.threeten.bp.Instant
+
+data class CoreInfoDto(
+  val quasselVersion: String?,
+  val quasselBuildDate: String?,
+  val startTime: Instant?,
+  val sessionConnectedClients: Int?,
+  val sessionConnectedClientData: List<ClientDto>,
+) {
+  data class ClientDto(
+    val secure: Boolean?,
+    val remoteAddress: String?,
+    val id: Int?,
+    val features: UInt?,
+    val featureList: List<String>,
+    val connectedSince: Instant?,
+    val clientVersionDate: String?,
+    val clientVersion: String?,
+  ) {
+    object Serializer : SyncableSerializer<ClientDto> {
+      override fun serialize(data: ClientDto): QVariantMap = mapOf(
+        "secure" to qVariant(data.secure, QtType.Bool),
+        "remoteAddress" to qVariant(data.remoteAddress, QtType.QString),
+        "id" to qVariant(data.id, QtType.Int),
+        "features" to qVariant(data.features, QtType.UInt),
+        "featureList" to qVariant(data.featureList, QtType.QStringList),
+        "connectedSince" to qVariant(data.connectedSince, QtType.QDateTime),
+        "clientVersionDate" to qVariant(data.clientVersionDate, QtType.QString),
+        "clientVersion" to qVariant(data.clientVersion, QtType.QString),
+      )
+
+      override fun deserialize(data: QVariantMap) = ClientDto(
+        secure = data["secure"].into<Boolean>(),
+        remoteAddress = data["remoteAddress"].into<String>(),
+        id = data["id"].into<Int>(),
+        features = data["features"].into<UInt>(),
+        featureList = data["featureList"].into<QStringList>().orEmpty().filterNotNull(),
+        connectedSince = data["connectedSince"].into<Instant>(),
+        clientVersionDate = data["clientVersionDate"].into<String>(),
+        clientVersion = data["clientVersion"].into<String>(),
+      )
+    }
+  }
+
+  object Serializer : SyncableSerializer<CoreInfoDto> {
+    override fun serialize(data: CoreInfoDto): QVariantMap = mapOf(
+      "coreData" to qVariant(
+        mapOf(
+          "quasselVersion" to qVariant(data.quasselVersion, QtType.QString),
+          "quasselBuildDate" to qVariant(data.quasselBuildDate, QtType.QString),
+          "startTime" to qVariant(data.startTime, QtType.QDateTime),
+          "sessionConnectedClients" to qVariant(data.sessionConnectedClients, QtType.Int),
+          "sessionConnectedClientData" to qVariant(data.sessionConnectedClientData, QtType.QVariantList),
+        ),
+        QtType.QVariantMap,
+      )
+    )
+
+    override fun deserialize(data: QVariantMap) = data["coreData"].into<QVariantMap>().orEmpty().let { properties ->
+      CoreInfoDto(
+        quasselVersion = properties["quasselVersion"].into<String>(),
+        quasselBuildDate = properties["quasselBuildDate"].into<String>(),
+        startTime = properties["startTime"].into<Instant>(),
+        sessionConnectedClients = properties["sessionConnectedClients"].into<Int>(),
+        sessionConnectedClientData = properties["sessionConnectedClientData"].into<QVariantList>()
+          ?.mapNotNull { it.into<QVariantMap>()?.let(ClientDto.Serializer::deserialize) }.orEmpty(),
+      )
+    }
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/HighlightRuleManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/HighlightRuleManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ad030c1bee290af81dca38585226fe6e5ac68644
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/HighlightRuleManagerDto.kt
@@ -0,0 +1,94 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.rules.HighlightNickType
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class HighlightRuleManagerDto(
+  val rules: List<HighlightRuleDto>,
+  val highlightNick: HighlightNickType,
+  val nicksCaseSensitive: Boolean,
+) {
+  data class HighlightRuleDto(
+    val id: Int,
+    val name: String,
+    val isRegEx: Boolean,
+    val isCaseSensitive: Boolean,
+    val isEnabled: Boolean,
+    val isInverse: Boolean,
+    val sender: String,
+    val channel: String,
+  )
+
+  object Serializer : SyncableSerializer<HighlightRuleManagerDto> {
+    override fun serialize(data: HighlightRuleManagerDto): QVariantMap = mapOf(
+      "highlightNick" to qVariant(data.highlightNick.value, QtType.Int),
+      "nicksCaseSensitive" to qVariant(data.nicksCaseSensitive, QtType.Bool),
+      "HighlightRuleList" to qVariant(mapOf(
+        "id" to qVariant(data.rules.map { qVariant(it.id, QtType.Int) }, QtType.QVariantList),
+        "name" to qVariant(data.rules.map { it.name }, QtType.QStringList),
+        "isRegEx" to qVariant(data.rules.map { qVariant(it.isRegEx, QtType.Bool) }, QtType.QVariantList),
+        "isCaseSensitive" to qVariant(data.rules.map { qVariant(it.isCaseSensitive, QtType.Bool) }, QtType.QVariantList),
+        "isEnabled" to qVariant(data.rules.map { qVariant(it.isEnabled, QtType.Bool) }, QtType.QVariantList),
+        "isInverse" to qVariant(data.rules.map { qVariant(it.isInverse, QtType.Bool) }, QtType.QVariantList),
+        "sender" to qVariant(data.rules.map { it.sender }, QtType.QStringList),
+        "channel" to qVariant(data.rules.map { it.channel }, QtType.QStringList),
+      ), QtType.QVariantMap),
+    )
+
+    override fun deserialize(data: QVariantMap) = HighlightRuleManagerDto(
+      highlightNick = data["highlightNick"].into<Int>()?.let(HighlightNickType::of) ?: Defaults.highlightNick,
+      nicksCaseSensitive = data["nicksCaseSensitive"].into<Boolean>(Defaults.nicksCaseSensitive),
+      rules = data["HighlightRuleList"].into<QVariantMap>()?.let { rules ->
+        val id = rules["id"].into<QVariantList>().orEmpty().map { it.into<Int>(0) }
+        val name = rules["name"].into<QStringList>().orEmpty().map { it ?: "" }
+        val isRegEx = rules["isRegEx"].into<QVariantList>().orEmpty().map { it.into<Boolean>(false) }
+        val isCaseSensitive = rules["isCaseSensitive"].into<QVariantList>().orEmpty().map { it.into<Boolean>(false) }
+        val isEnabled = rules["isEnabled"].into<QVariantList>().orEmpty().map { it.into<Boolean>(false) }
+        val isInverse = rules["isInverse"].into<QVariantList>().orEmpty().map { it.into<Boolean>(false) }
+        val sender = rules["sender"].into<QStringList>().orEmpty().map { it ?: "" }
+        val channel = rules["channel"].into<QStringList>().orEmpty().map { it ?: "" }
+        if (id.size != name.size) return@let null
+        if (id.size != isRegEx.size) return@let null
+        if (id.size != isCaseSensitive.size) return@let null
+        if (id.size != isEnabled.size) return@let null
+        if (id.size != isInverse.size) return@let null
+        if (id.size != sender.size) return@let null
+        if (id.size != channel.size) return@let null
+        id.indices.map { index ->
+          HighlightRuleDto(
+            id = id[index],
+            name = name[index],
+            isRegEx = isRegEx[index],
+            isCaseSensitive = isCaseSensitive[index],
+            isEnabled = isEnabled[index],
+            isInverse = isInverse[index],
+            sender = sender[index],
+            channel = channel[index],
+          )
+        }
+      }.orEmpty()
+    )
+  }
+
+  companion object {
+    val Defaults = HighlightRuleManagerDto(
+      highlightNick = HighlightNickType.CurrentNick,
+      nicksCaseSensitive = false,
+      rules = emptyList(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IdentityDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IdentityDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bf950d61432b22c53d573537f0ab7dbbabec9c8b
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IdentityDto.kt
@@ -0,0 +1,87 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class IdentityDto(
+  val identityId: IdentityId,
+  val identityName: String,
+  val realName: String,
+  val nicks: List<String>,
+  val awayNick: String,
+  val awayNickEnabled: Boolean,
+  val awayReason: String,
+  val awayReasonEnabled: Boolean,
+  val autoAwayEnabled: Boolean,
+  val autoAwayTime: Int,
+  val autoAwayReason: String,
+  val autoAwayReasonEnabled: Boolean,
+  val detachAwayEnabled: Boolean,
+  val detachAwayReason: String,
+  val detachAwayReasonEnabled: Boolean,
+  val ident: String,
+  val kickReason: String,
+  val partReason: String,
+  val quitReason: String,
+) {
+  object Serializer : SyncableSerializer<IdentityDto> {
+    override fun serialize(data: IdentityDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = IdentityDto(
+      identityId = TODO(),
+      identityName = TODO(),
+      realName = TODO(),
+      nicks = TODO(),
+      awayNick = TODO(),
+      awayNickEnabled = TODO(),
+      awayReason = TODO(),
+      awayReasonEnabled = TODO(),
+      autoAwayEnabled = TODO(),
+      autoAwayTime = TODO(),
+      autoAwayReason = TODO(),
+      autoAwayReasonEnabled = TODO(),
+      detachAwayEnabled = TODO(),
+      detachAwayReason = TODO(),
+      detachAwayReasonEnabled = TODO(),
+      ident = TODO(),
+      kickReason = TODO(),
+      partReason = TODO(),
+      quitReason = TODO(),
+    )
+  }
+
+  companion object {
+    val Defaults = IdentityDto(
+      identityId = IdentityId(-1),
+      identityName = "<empty>",
+      realName = "",
+      nicks = listOf("quassel"),
+      awayNick = "",
+      awayNickEnabled = false,
+      awayReason = "Gone fishing.",
+      awayReasonEnabled = true,
+      autoAwayEnabled = false,
+      autoAwayTime = 10,
+      autoAwayReason = "Not here. No really. not here!",
+      autoAwayReasonEnabled = false,
+      detachAwayEnabled = false,
+      detachAwayReason = "All Quassel clients vanished from the face of the earth...",
+      detachAwayReasonEnabled = false,
+      ident = "quassel",
+      kickReason = "Kindergarten is elsewhere!",
+      partReason = "http://quassel-irc.org - Chat comfortably. Anywhere.",
+      quitReason = "http://quassel-irc.org - Chat comfortably. Anywhere.",
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IgnoreListManagerDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IgnoreListManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..52d7262b03a6be836f30f99f8150a68e8d24a94e
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IgnoreListManagerDto.kt
@@ -0,0 +1,95 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.rules.IgnoreType
+import de.justjanne.libquassel.protocol.models.rules.ScopeType
+import de.justjanne.libquassel.protocol.models.rules.StrictnessType
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class IgnoreListManagerDto(
+  val rules: List<IgnoreRuleDto>,
+) {
+  data class IgnoreRuleDto(
+    val ignoreType: IgnoreType,
+    val ignoreRule: String,
+    val isRegEx: Boolean,
+    val strictness: StrictnessType,
+    val scope: ScopeType,
+    val scopeRule: String,
+    val isActive: Boolean,
+  ) {
+    companion object {
+      val Defaults = IgnoreRuleDto(
+        ignoreType = IgnoreType.SenderIgnore,
+        ignoreRule = "",
+        isRegEx = false,
+        strictness = StrictnessType.UnmatchedStrictness,
+        scope = ScopeType.GlobalScope,
+        scopeRule = "",
+        isActive = false,
+      )
+    }
+  }
+
+  object Serializer : SyncableSerializer<IgnoreListManagerDto> {
+    override fun serialize(data: IgnoreListManagerDto): QVariantMap = mapOf(
+      "IgnoreList" to qVariant(mapOf(
+        "ignoreType" to qVariant(data.rules.map { qVariant(it.ignoreType.value, QtType.Int) }, QtType.QVariantList),
+        "ignoreRule" to qVariant(data.rules.map { it.ignoreRule }, QtType.QStringList),
+        "isRegEx" to qVariant(data.rules.map { qVariant(it.isRegEx, QtType.Bool) }, QtType.QVariantList),
+        "strictness" to qVariant(data.rules.map { qVariant(it.strictness.value, QtType.Int) }, QtType.QVariantList),
+        "scope" to qVariant(data.rules.map { qVariant(it.scope.value, QtType.Int) }, QtType.QVariantList),
+        "scopeRule" to qVariant(data.rules.map { it.scopeRule }, QtType.QStringList),
+        "isActive" to qVariant(data.rules.map { qVariant(it.isActive, QtType.Bool) }, QtType.QVariantList),
+      ), QtType.QVariantMap),
+    )
+
+    override fun deserialize(data: QVariantMap) = IgnoreListManagerDto(
+      rules = data["IgnoreList"].into<QVariantMap>()?.let { rules ->
+        val ignoreType = rules["ignoreType"].into<QVariantList>().orEmpty().map { it.into<Int>() }
+        val ignoreRule = rules["ignoreRule"].into<QStringList>().orEmpty().map { it ?: "" }
+        val isRegEx = rules["isRegEx"].into<QVariantList>().orEmpty().map { it.into<Boolean>(IgnoreRuleDto.Defaults.isRegEx) }
+        val strictness = rules["strictness"].into<QVariantList>().orEmpty().map { it.into<Int>() }
+        val scope = rules["scope"].into<QVariantList>().orEmpty().map { it.into<Int>() }
+        val scopeRule = rules["scopeRule"].into<QStringList>().orEmpty().map { it ?: "" }
+        val isActive = rules["isActive"].into<QVariantList>().orEmpty().map { it.into<Boolean>(IgnoreRuleDto.Defaults.isActive) }
+        if (ignoreRule.size != ignoreType.size) return@let null
+        if (ignoreRule.size != isRegEx.size) return@let null
+        if (ignoreRule.size != strictness.size) return@let null
+        if (ignoreRule.size != scope.size) return@let null
+        if (ignoreRule.size != scopeRule.size) return@let null
+        if (ignoreRule.size != isActive.size) return@let null
+        ignoreRule.indices.map { index ->
+          IgnoreRuleDto(
+            ignoreType = ignoreType[index]?.let(IgnoreType::of) ?: IgnoreRuleDto.Defaults.ignoreType,
+            ignoreRule = ignoreRule[index],
+            isRegEx = isRegEx[index],
+            strictness = strictness[index]?.let(StrictnessType::of) ?: IgnoreRuleDto.Defaults.strictness,
+            scope = scope[index]?.let(ScopeType::of) ?: IgnoreRuleDto.Defaults.scope,
+            scopeRule = scopeRule[index],
+            isActive = isActive[index],
+          )
+        }
+      }.orEmpty()
+    )
+  }
+
+  companion object {
+    val Defaults = IgnoreListManagerDto(
+      rules = emptyList(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcChannelDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcChannelDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5bc18f904af96eb8c80ea9b2b3619839ad0d7e04
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcChannelDto.kt
@@ -0,0 +1,48 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.network.ChannelModes
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class IrcChannelDto(
+  val name: String,
+  val topic: String,
+  val password: String,
+  val encrypted: Boolean,
+  val channelModes: ChannelModes,
+  val userModes: Map<String, Set<Char>>,
+) {
+  object Serializer : SyncableSerializer<IrcChannelDto> {
+    override fun serialize(data: IrcChannelDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = IrcChannelDto(
+      name = TODO(),
+      topic = TODO(),
+      password = TODO(),
+      encrypted = TODO(),
+      channelModes = TODO(),
+      userModes = TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = IrcChannelDto(
+      name = "",
+      topic = "",
+      password = "",
+      encrypted = false,
+      channelModes = ChannelModes(),
+      userModes = emptyMap(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcListHelperDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcListHelperDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bcf0a1e5b78a40863646cb9785e5ed77e3df3945
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcListHelperDto.kt
@@ -0,0 +1,20 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data object IrcListHelperDto {
+  object Serializer : SyncableSerializer<IrcListHelperDto> {
+    override fun serialize(data: IrcListHelperDto): QVariantMap = emptyMap()
+    override fun deserialize(data: QVariantMap) = IrcListHelperDto
+  }
+}
+
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcUserDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcUserDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6aaf8ad4246a26370290893a1865ba5b15e562ee
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/IrcUserDto.kt
@@ -0,0 +1,81 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import org.threeten.bp.Instant
+
+data class IrcUserDto(
+  val nick: String,
+  val user: String,
+  val host: String,
+  val realName: String,
+  val account: String,
+  val away: Boolean,
+  val awayMessage: String,
+  val idleTime: Instant,
+  val loginTime: Instant,
+  val server: String,
+  val ircOperator: String,
+  val lastAwayMessageTime: Instant,
+  val whoisServiceReply: String,
+  val suserHost: String,
+  val encrypted: Boolean,
+  val channels: Set<String>,
+  val userModes: Set<Char>,
+) {
+  object Serializer : SyncableSerializer<IrcUserDto> {
+    override fun serialize(data: IrcUserDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = IrcUserDto(
+      nick = TODO(),
+      user = TODO(),
+      host = TODO(),
+      realName = TODO(),
+      account = TODO(),
+      away = TODO(),
+      awayMessage = TODO(),
+      idleTime = TODO(),
+      loginTime = TODO(),
+      server = TODO(),
+      ircOperator = TODO(),
+      lastAwayMessageTime = TODO(),
+      whoisServiceReply = TODO(),
+      suserHost = TODO(),
+      encrypted = TODO(),
+      channels = TODO(),
+      userModes = TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = IrcUserDto(
+      nick = "",
+      user = "",
+      host = "",
+      realName = "",
+      account = "",
+      away = false,
+      awayMessage = "",
+      idleTime = Instant.EPOCH,
+      loginTime = Instant.EPOCH,
+      server = "",
+      ircOperator = "",
+      lastAwayMessageTime = Instant.EPOCH,
+      whoisServiceReply = "",
+      suserHost = "",
+      encrypted = false,
+      channels = emptySet(),
+      userModes = emptySet(),
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkConfigDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkConfigDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..461484c9b0903f5359e42bd05c08e07b78127f10
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkConfigDto.kt
@@ -0,0 +1,63 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class NetworkConfigDto(
+  val pingTimeoutEnabled: Boolean,
+  val pingInterval: Int,
+  val maxPingCount: Int,
+  val autoWhoEnabled: Boolean,
+  val autoWhoInterval: Int,
+  val autoWhoNickLimit: Int,
+  val autoWhoDelay: Int,
+  val standardCtcp: Boolean,
+) {
+  object Serializer : SyncableSerializer<NetworkConfigDto> {
+    override fun serialize(data: NetworkConfigDto): QVariantMap = mapOf(
+      "pingTimeoutEnabled" to qVariant(data.pingTimeoutEnabled, QtType.Bool),
+      "pingInterval" to qVariant(data.pingInterval, QtType.Int),
+      "maxPingCount" to qVariant(data.maxPingCount, QtType.Int),
+      "autoWhoEnabled" to qVariant(data.autoWhoEnabled, QtType.Bool),
+      "autoWhoInterval" to qVariant(data.autoWhoInterval, QtType.Int),
+      "autoWhoNickLimit" to qVariant(data.autoWhoNickLimit, QtType.Int),
+      "autoWhoDelay" to qVariant(data.autoWhoDelay, QtType.Int),
+      "standardCtcp" to qVariant(data.standardCtcp, QtType.Bool),
+    )
+
+    override fun deserialize(data: QVariantMap) = NetworkConfigDto(
+      pingTimeoutEnabled = data["pingTimeoutEnabled"].into<Boolean>(Defaults.pingTimeoutEnabled),
+      pingInterval = data["pingInterval"].into<Int>(Defaults.pingInterval),
+      maxPingCount = data["maxPingCount"].into<Int>(Defaults.maxPingCount),
+      autoWhoEnabled = data["autoWhoEnabled"].into<Boolean>(Defaults.autoWhoEnabled),
+      autoWhoInterval = data["autoWhoInterval"].into<Int>(Defaults.autoWhoInterval),
+      autoWhoNickLimit = data["autoWhoNickLimit"].into<Int>(Defaults.autoWhoNickLimit),
+      autoWhoDelay = data["autoWhoDelay"].into<Int>(Defaults.autoWhoDelay),
+      standardCtcp = data["standardCtcp"].into<Boolean>(Defaults.standardCtcp),
+    )
+  }
+
+  companion object {
+    val Defaults = NetworkConfigDto(
+      pingTimeoutEnabled = true,
+      pingInterval = 30,
+      maxPingCount = 6,
+      autoWhoEnabled = true,
+      autoWhoInterval = 90,
+      autoWhoNickLimit = 200,
+      autoWhoDelay = 5,
+      standardCtcp = false
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d78cafa4839f702a917413c5f2b3fb9499177b03
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkDto.kt
@@ -0,0 +1,32 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class NetworkDto(
+  val `null`: Nothing,
+) {
+  object Serializer : SyncableSerializer<NetworkDto> {
+    override fun serialize(data: NetworkDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = NetworkDto(
+      TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = NetworkDto(
+      TODO()
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkInfoDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkInfoDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..11c4376306408122263689e3b18449818cb581c5
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/NetworkInfoDto.kt
@@ -0,0 +1,107 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.network.NetworkServer
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+data class NetworkInfoDto(
+  val networkId: NetworkId,
+  val networkName: String,
+  val identity: IdentityId,
+  val useCustomEncodings: Boolean,
+  val codecForServer: String,
+  val codecForEncoding: String,
+  val codecForDecoding: String,
+  val serverList: List<NetworkServer>,
+  val useRandomServer: Boolean,
+  val perform: List<String>,
+  val useAutoIdentify: Boolean,
+  val autoIdentifyService: String,
+  val autoIdentifyPassword: String,
+  val useSasl: Boolean,
+  val saslAccount: String,
+  val saslPassword: String,
+  val useAutoReconnect: Boolean,
+  val autoReconnectInterval: UInt,
+  val autoReconnectRetries: UShort,
+  val unlimitedReconnectRetries: Boolean,
+  val rejoinChannels: Boolean,
+  val useCustomMessageRate: Boolean,
+  val messageRateBurstSize: UInt,
+  val messageRateDelay: UInt,
+  val unlimitedMessageRate: Boolean,
+) {
+  object Serializer : SyncableSerializer<NetworkInfoDto> {
+    override fun serialize(data: NetworkInfoDto): QVariantMap = mapOf(
+      TODO()
+    )
+
+    override fun deserialize(data: QVariantMap) = NetworkInfoDto(
+      networkId = TODO(),
+      networkName = TODO(),
+      identity = TODO(),
+      useCustomEncodings = TODO(),
+      codecForServer = TODO(),
+      codecForEncoding = TODO(),
+      codecForDecoding = TODO(),
+      serverList = TODO(),
+      useRandomServer = TODO(),
+      perform = TODO(),
+      useAutoIdentify = TODO(),
+      autoIdentifyService = TODO(),
+      autoIdentifyPassword = TODO(),
+      useSasl = TODO(),
+      saslAccount = TODO(),
+      saslPassword = TODO(),
+      useAutoReconnect = TODO(),
+      autoReconnectInterval = TODO(),
+      autoReconnectRetries = TODO(),
+      unlimitedReconnectRetries = TODO(),
+      rejoinChannels = TODO(),
+      useCustomMessageRate = TODO(),
+      messageRateBurstSize = TODO(),
+      messageRateDelay = TODO(),
+      unlimitedMessageRate = TODO()
+    )
+  }
+
+  companion object {
+    val Defaults = NetworkInfoDto(
+      networkId = NetworkId(-1),
+      networkName = "",
+      identity = IdentityId(-1),
+      useCustomEncodings = false,
+      codecForServer = "UTF_8",
+      codecForEncoding = "UTF_8",
+      codecForDecoding = "UTF_8",
+      serverList = emptyList(),
+      useRandomServer = false,
+      perform = emptyList(),
+      useAutoIdentify = false,
+      autoIdentifyService = "",
+      autoIdentifyPassword = "",
+      useSasl = false,
+      saslAccount = "",
+      saslPassword = "",
+      useAutoReconnect = true,
+      autoReconnectInterval = 0u,
+      autoReconnectRetries = 0u,
+      unlimitedReconnectRetries = true,
+      rejoinChannels = true,
+      useCustomMessageRate = false,
+      messageRateBurstSize = 0u,
+      messageRateDelay = 0u,
+      unlimitedMessageRate = false,
+    )
+  }
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/SyncableSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/SyncableSerializer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..201fcd67dede53a0db3dd51350257124e66140ab
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/dto/SyncableSerializer.kt
@@ -0,0 +1,17 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.dto
+
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+interface SyncableSerializer<T> {
+  fun serialize(data: T): QVariantMap
+  fun deserialize(data: QVariantMap): T
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
index 1a5db8bfe814bcd4b2a42d9d36fbc39a3f3f7114..16f93d12ed9ac0a3b9dff89732e5012da1071499 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
@@ -9,9 +9,9 @@
 
 package de.justjanne.libquassel.protocol.models
 
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
 import de.justjanne.libquassel.protocol.models.setup.BackendInfo
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt
index 6280cb14c8bf2a700983ba91b23546292badb1a7..97bc598e81cd7a1a358528571f66b109a79a23e9 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt
@@ -99,7 +99,7 @@ sealed class SignalProxyMessage {
     val initData: QVariantMap,
   ) : SignalProxyMessage() {
     override fun toString(): String {
-      return "InitData::$className($objectName)"
+      return "InitData::$className/$objectName(${initData.toString()})"
     }
   }
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcChannelDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcChannelDto.kt
deleted file mode 100644
index c344858fc7d347c18377e042aadec2e72e95aacb..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcChannelDto.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2024 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.models.network
-
-import de.justjanne.libquassel.protocol.models.ids.IdentityId
-
-data class IrcChannelDto(
-  val name: String,
-  val topic: String = "",
-  val password: String = "",
-  val encrypted: Boolean = false,
-  val channelModes: ChannelModes = ChannelModes(),
-  val userModes: Map<String, Set<Char>> = emptyMap(),
-)
-
-data class IdentityDto(
-  val identityId: IdentityId = IdentityId(-1),
-  val identityName: String = "<empty>",
-  val realName: String = "",
-  val nicks: List<String> = listOf("quassel"),
-  val awayNick: String = "",
-  val awayNickEnabled: Boolean = false,
-  val awayReason: String = "Gone fishing.",
-  val awayReasonEnabled: Boolean = true,
-  val autoAwayEnabled: Boolean = false,
-  val autoAwayTime: Int = 10,
-  val autoAwayReason: String = "Not here. No really. not here!",
-  val autoAwayReasonEnabled: Boolean = false,
-  val detachAwayEnabled: Boolean = false,
-  val detachAwayReason: String = "All Quassel clients vanished from the face of the earth...",
-  val detachAwayReasonEnabled: Boolean = false,
-  val ident: String = "quassel",
-  val kickReason: String = "Kindergarten is elsewhere!",
-  val partReason: String = "http://quassel-irc.org - Chat comfortably. Anywhere.",
-  val quitReason: String = "http://quassel-irc.org - Chat comfortably. Anywhere.",
-)
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcUserDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcUserDto.kt
deleted file mode 100644
index fdf1641279b2a836e2ffa0fab97e3e644ab0ddc0..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/IrcUserDto.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2024 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.models.network
-
-import org.threeten.bp.Instant
-
-data class IrcUserDto(
-  val nick: String,
-  val user: String,
-  val host: String,
-  val realName: String = "",
-  val account: String = "",
-  val away: Boolean = false,
-  val awayMessage: String = "",
-  val idleTime: Instant = Instant.EPOCH,
-  val loginTime: Instant = Instant.EPOCH,
-  val server: String = "",
-  val ircOperator: String = "",
-  val lastAwayMessageTime: Instant = Instant.EPOCH,
-  val whoisServiceReply: String = "",
-  val suserHost: String = "",
-  val encrypted: Boolean = false,
-  val channels: Set<String> = emptySet(),
-  val userModes: Set<Char> = emptySet(),
-)
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/NetworkInfoDto.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/NetworkInfoDto.kt
deleted file mode 100644
index a649435f1a0e5d02c24d2c89813497edabf54a7c..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/network/NetworkInfoDto.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2024 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.models.network
-
-import de.justjanne.libquassel.protocol.models.ids.IdentityId
-import de.justjanne.libquassel.protocol.models.ids.NetworkId
-
-data class NetworkInfoDto(
-  val networkId: NetworkId = NetworkId(-1),
-  val networkName: String = "",
-  val identity: IdentityId = IdentityId(-1),
-  val useCustomEncodings: Boolean = false,
-  val codecForServer: String = "UTF_8",
-  val codecForEncoding: String = "UTF_8",
-  val codecForDecoding: String = "UTF_8",
-  val serverList: List<NetworkServer> = emptyList(),
-  val useRandomServer: Boolean = false,
-  val perform: List<String> = emptyList(),
-  val useAutoIdentify: Boolean = false,
-  val autoIdentifyService: String = "",
-  val autoIdentifyPassword: String = "",
-  val useSasl: Boolean = false,
-  val saslAccount: String = "",
-  val saslPassword: String = "",
-  val useAutoReconnect: Boolean = true,
-  val autoReconnectInterval: UInt = 0u,
-  val autoReconnectRetries: UShort = 0u,
-  val unlimitedReconnectRetries: Boolean = true,
-  val rejoinChannels: Boolean = true,
-  val useCustomMessageRate: Boolean = false,
-  val messageRateBurstSize: UInt = 0u,
-  val messageRateDelay: UInt = 0u,
-  val unlimitedMessageRate: Boolean = false,
-)
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightNickType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightNickType.kt
index 883d078e1e6afb2624b68b76fca2f342b27f7f71..256b8a0a266e5414224585eef417f8206cd750f0 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightNickType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightNickType.kt
@@ -14,8 +14,7 @@ enum class HighlightNickType(
 ) {
   NoNick(0),
   CurrentNick(1),
-  AllNicks(2),
-  ;
+  AllNicks(2);
 
   companion object {
     private val values =
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/IgnoreType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/IgnoreType.kt
index e786518faff0df8938c6e76073c5eba161f16c36..549d64657545a1b1623ea47e4f0acb8bb8d10bd1 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/IgnoreType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/IgnoreType.kt
@@ -14,8 +14,7 @@ enum class IgnoreType(
 ) {
   SenderIgnore(0),
   MessageIgnore(1),
-  CtcpIgnore(2),
-  ;
+  CtcpIgnore(2);
 
   companion object {
     private val values =
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/ScopeType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/ScopeType.kt
index 87ddcbdc2257c6fdb317edf6c1f6ebe66d364b5d..c08d8e2890b6a9f7d86e3c5649e97bbde007c61f 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/ScopeType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/ScopeType.kt
@@ -14,8 +14,7 @@ enum class ScopeType(
 ) {
   GlobalScope(0),
   NetworkScope(1),
-  ChannelScope(2),
-  ;
+  ChannelScope(2);
 
   companion object {
     private val values =
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/StrictnessType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/StrictnessType.kt
index 7bc8f004e43427bf677e5bb97613278ea261331d..00b33bbf840bd700a16ff191b74fe53685a2ae28 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/StrictnessType.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/StrictnessType.kt
@@ -14,8 +14,7 @@ enum class StrictnessType(
 ) {
   UnmatchedStrictness(0),
   SoftStrictness(1),
-  HardStrictness(2),
-  ;
+  HardStrictness(2);
 
   companion object {
     private val values =
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
index ea8c624297e517e112b7ca18ff70477b79f25044..d088b46e15707fac19654feef1c0b3bc97e6a096 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
@@ -9,10 +9,10 @@
 
 package de.justjanne.libquassel.protocol.serializers.handshake
 
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
index 53e44b574e92431d4ced7d2a9c4f8ebb9b95abc2..a1539d4e32f9416dfbfeb8e930a3d75731ad48ec 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
@@ -9,10 +9,10 @@
 
 package de.justjanne.libquassel.protocol.serializers.quassel
 
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
index 0e474f69ca9f79183cb8ac49e9464021e4db612f..d98d941d17b959f2da6de4a6a99641bd1b97040a 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
@@ -9,10 +9,10 @@
 
 package de.justjanne.libquassel.protocol.serializers.quassel
 
+import de.justjanne.libquassel.protocol.dto.IrcChannelDto
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
 import de.justjanne.libquassel.protocol.models.network.ChannelModes
-import de.justjanne.libquassel.protocol.models.network.IrcChannelDto
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
 import de.justjanne.libquassel.protocol.serializers.qt.QVariantMapSerializer
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
index e4fea903893a4144efdd94776ffe68bb8cd7cd5d..e5b1a6980e0fd0d741d513d87d65d1bf91e23554 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
@@ -9,9 +9,9 @@
 
 package de.justjanne.libquassel.protocol.serializers.quassel
 
+import de.justjanne.libquassel.protocol.dto.IrcUserDto
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
-import de.justjanne.libquassel.protocol.models.network.IrcUserDto
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
 import de.justjanne.libquassel.protocol.serializers.qt.QVariantMapSerializer
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializer.kt
index 441043cc7091da8569c295470abc0fa27a783bbf..7f23115704cb5aa525f3e9eb504c810944be0ec8 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializer.kt
@@ -9,12 +9,12 @@
 
 package de.justjanne.libquassel.protocol.serializers.quassel
 
+import de.justjanne.libquassel.protocol.dto.NetworkInfoDto
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.network.NetworkServer
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
index 185724dc6c56c2b459dcb6d98493cbf2998174da..86405202844073515562679c3b15f15f6770a73a 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
@@ -9,13 +9,13 @@
 package de.justjanne.libquassel.protocol.serializers.handshake
 
 import de.justjanne.bitflags.of
+import de.justjanne.libquassel.protocol.dto.IdentityDto
 import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.models.flags.BufferType
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
 import org.junit.jupiter.api.Tag
@@ -83,7 +83,7 @@ class SessionInitSerializerTest {
       HandshakeMessage.SessionInit(
         identities =
           listOf(
-            IdentityDto(
+            IdentityDto.Defaults.copy(
                 identityId = IdentityId(1),
             ),
           ),
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
index c857f283b4b4ec95bcc66a3374645387be70184c..91a04180bc116c397faa4597073858763e84a7a7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
@@ -8,7 +8,7 @@
  */
 package de.justjanne.libquassel.protocol.serializers.quassel
 
-import de.justjanne.libquassel.protocol.models.network.IrcChannelDto
+import de.justjanne.libquassel.protocol.dto.IrcChannelDto
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
@@ -30,7 +30,7 @@ class IrcChannelSerializerTest {
   @Test
   fun testNormal() = primitiveSerializerTest(
       IrcChannelSerializer as PrimitiveSerializer<IrcChannelDto>,
-      IrcChannelDto(
+      IrcChannelDto.Defaults.copy(
             name = "#quassel",
       ),
       encoded = byteBufferOf(
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt
index 9d198f020f4dfde0a17a66dbc29d4d0020091f94..7726d9b59b8f3b7b81db8ad25e1ae16a3171f6b7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt
@@ -8,11 +8,10 @@
  */
 package de.justjanne.libquassel.protocol.serializers.quassel
 
-import de.justjanne.libquassel.protocol.models.network.IrcUserDto
+import de.justjanne.libquassel.protocol.dto.IrcUserDto
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
-import de.justjanne.libquassel.protocol.variant.QVariantMap
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
@@ -31,7 +30,7 @@ class IrcUserSerializerTest {
   fun testNormal() =
     primitiveSerializerTest(
       IrcUserSerializer,
-      IrcUserDto(
+      IrcUserDto.Defaults.copy(
         nick = "AzureDiamond",
         user = "~azure",
         host = "127.0.0.1",
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
index 78d3fcc3fdf5f567cbc6f0edf3f1e722499280f0..5c6caec6c66b5d11f0ce14347a412c6562f8e476 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
@@ -8,8 +8,8 @@
  */
 package de.justjanne.libquassel.protocol.serializers.quassel
 
+import de.justjanne.libquassel.protocol.dto.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
@@ -31,7 +31,7 @@ class NetworkInfoSerializerTest {
   fun testEmptyMap() =
     primitiveSerializerTest(
       NetworkInfoSerializer,
-      NetworkInfoDto(),
+      NetworkInfoDto.Defaults,
       byteBufferOf(
         // no elements
         0x00u,
@@ -47,7 +47,7 @@ class NetworkInfoSerializerTest {
   fun testNormal() =
     primitiveSerializerTest(
       NetworkInfoSerializer,
-      NetworkInfoDto(
+      NetworkInfoDto.Defaults.copy(
         networkId = NetworkId(4),
       ),
       byteBufferOf(
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
index 82ddb60a5475321b8e83b6780d74893889734ad1..54c55da26d752c75216eadbeef6aad3241570c3d 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
@@ -9,13 +9,8 @@
 package de.justjanne.libquassel.protocol.serializers.signalproxy
 
 import de.justjanne.libquassel.protocol.models.SignalProxyMessage
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
-import de.justjanne.libquassel.protocol.models.types.QtType
-import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
-import de.justjanne.libquassel.protocol.variant.QVariant_
-import de.justjanne.libquassel.protocol.variant.qVariant
 import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
index 6705c44778743d92ef23c102a2cf29fb7919ecd8..3f587cdc2c1f6e6f3dddec4eb180ef7a4b5185f3 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
@@ -9,16 +9,15 @@
 
 package de.justjanne.libquassel.protocol.testutil
 
+import de.justjanne.libquassel.protocol.dto.IdentityDto
+import de.justjanne.libquassel.protocol.dto.IrcChannelDto
+import de.justjanne.libquassel.protocol.dto.IrcUserDto
+import de.justjanne.libquassel.protocol.dto.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
-import de.justjanne.libquassel.protocol.models.network.IdentityDto
-import de.justjanne.libquassel.protocol.models.network.IrcChannelDto
-import de.justjanne.libquassel.protocol.models.network.IrcUserDto
-import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
 import de.justjanne.libquassel.protocol.models.network.NetworkServer
 import org.threeten.bp.Instant
-import java.util.UUID
-import java.util.EnumSet
+import java.util.*
 import kotlin.random.Random
 import kotlin.random.nextUInt
 
@@ -42,7 +41,7 @@ inline fun <reified T : Enum<T>> Random.nextEnum(): T {
 fun Random.nextInstant(): Instant = Instant.ofEpochMilli(nextLong())
 
 fun Random.nextNetworkInfo(networkId: NetworkId = NetworkId(nextInt())) =
-  NetworkInfoDto(
+  NetworkInfoDto.Defaults.copy(
     networkId = networkId,
     identity = IdentityId(nextInt()),
     networkName = nextString(),
@@ -91,7 +90,7 @@ fun Random.nextNetworkServer() =
   )
 
 fun Random.nextIrcUser() =
-  IrcUserDto(
+  IrcUserDto.Defaults.copy(
     nick = nextString(),
     user = nextString(),
     host = nextString(),
@@ -110,7 +109,7 @@ fun Random.nextIrcUser() =
   )
 
 fun Random.nextIrcChannel() =
-  IrcChannelDto(
+  IrcChannelDto.Defaults.copy(
     name = nextString(),
     topic = nextString(),
     password = nextString(),
@@ -118,7 +117,7 @@ fun Random.nextIrcChannel() =
   )
 
 fun Random.nextIdentity(identityId: IdentityId = IdentityId(nextInt())) =
-  IdentityDto(
+  IdentityDto.Defaults.copy(
     identityId = identityId,
     identityName = nextString(),
     realName = nextString(),