diff --git a/moder/.gitignore b/moder/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f3d7823329ee16ace6941e0987f02cc4f9900026
--- /dev/null
+++ b/moder/.gitignore
@@ -0,0 +1,4 @@
+.*
+!.git*
+build/
+gradle/
diff --git a/moder/build.gradle.kts b/moder/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..c7144ef48e13de16c3b04ec9540a84ec769a4df8
--- /dev/null
+++ b/moder/build.gradle.kts
@@ -0,0 +1,29 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+    kotlin("jvm") version "1.4.10"
+    application
+}
+
+group = "hu.bme.i9rv7w"
+version = "1.0-SNAPSHOT"
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testImplementation(kotlin("test-junit"))
+}
+
+tasks.test {
+    useJUnit()
+}
+
+tasks.withType<KotlinCompile>() {
+    kotlinOptions.jvmTarget = "1.8"
+}
+
+application {
+    mainClassName = "MainKt"
+}
\ No newline at end of file
diff --git a/moder/gradle.properties b/moder/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..7fc6f1ff272ee12d8be9694acdaa36b4284eefdb
--- /dev/null
+++ b/moder/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official
diff --git a/moder/gradlew b/moder/gradlew
new file mode 100755
index 0000000000000000000000000000000000000000..4f906e0c811fc9e230eb44819f509cd0627f2600
--- /dev/null
+++ b/moder/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/moder/gradlew.bat b/moder/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..107acd32c4e687021ef32db511e8a206129b88ec
--- /dev/null
+++ b/moder/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/moder/settings.gradle.kts b/moder/settings.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..aaf6edf4e3bcc69ddd2f1e361f2c899edbff7f6d
--- /dev/null
+++ b/moder/settings.gradle.kts
@@ -0,0 +1,3 @@
+
+rootProject.name = "moder"
+
diff --git a/moder/src/main/kotlin/core/relation/SameAs.kt b/moder/src/main/kotlin/core/relation/SameAs.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cb9dd48d5127084883d8b38fc7b482ac406e6498
--- /dev/null
+++ b/moder/src/main/kotlin/core/relation/SameAs.kt
@@ -0,0 +1,6 @@
+package core.relation
+
+import core.schema.Entity
+import core.schema.Relation
+
+class SameAs(from: Entity, to: Entity) : Relation(from, to)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/relation/physical/Connects.kt b/moder/src/main/kotlin/core/relation/physical/Connects.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5f3acd8bf25d70fd7c8ed23b7a1908b3d0d706e5
--- /dev/null
+++ b/moder/src/main/kotlin/core/relation/physical/Connects.kt
@@ -0,0 +1,6 @@
+package core.relation.physical
+
+import core.schema.Entity
+import core.schema.Relation
+
+class Connects(a: Entity, b: Entity) : Relation(a, b)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/relation/physical/Consists.kt b/moder/src/main/kotlin/core/relation/physical/Consists.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ef44e5103013a5c282af14e604e56fecec6ecc94
--- /dev/null
+++ b/moder/src/main/kotlin/core/relation/physical/Consists.kt
@@ -0,0 +1,6 @@
+package core.relation.physical
+
+import core.schema.Entity
+import core.schema.Relation
+
+class Consists(container: Entity, containee: Entity) : Relation(container, containee)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/relation/physical/connectionTypes.kt b/moder/src/main/kotlin/core/relation/physical/connectionTypes.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e24cfd67e74a0c0bd4c3fca20fd7a1682cbbf0de
--- /dev/null
+++ b/moder/src/main/kotlin/core/relation/physical/connectionTypes.kt
@@ -0,0 +1,6 @@
+package core.relation.physical
+
+val physicalRelations = setOf(
+    Connects::class,
+    Consists::class
+)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/schema/ComposableEntity.kt b/moder/src/main/kotlin/core/schema/ComposableEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ee32e4fcb8c7f698bcae058246ca9bd0d85d386d
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/ComposableEntity.kt
@@ -0,0 +1,18 @@
+package core.schema
+
+import core.relation.physical.Consists
+
+abstract class ComposableEntity<T : Entity> : Entity {
+    constructor() : super()
+    constructor(consists: List<T>) : super() {
+        madeUp(consists)
+    }
+
+    fun madeUp(consists: List<T>): ComposableEntity<T> {
+        val container = this
+        consists.forEach { containee ->
+            Consists(container, containee)
+        }
+        return this
+    }
+}
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/schema/Entity.kt b/moder/src/main/kotlin/core/schema/Entity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1ed270cb2ee4f44679079f14cf21469ac81dd6a1
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/Entity.kt
@@ -0,0 +1,35 @@
+package core.schema
+
+import core.util.Serial
+import java.util.*
+
+open class Entity {
+    val uuid: UUID = UUID.randomUUID()
+    val labels = mutableSetOf<Label>()
+
+    // related entities
+    val relatives = mutableMapOf<Relation, Entity>()
+
+    val type: String = entityType(this.javaClass)
+
+    init {
+        Graph.addEntity(this) // sorry, it's by design
+        val serial = Serial.generateSerialFor(this).toString()
+        labels.add(Label("serial", serial))
+    }
+
+    fun relate(relation: Relation, entity: Entity) {
+        relatives[relation] = entity
+    }
+
+    override fun toString(): String {
+        return "{$type}@{$uuid}"
+    }
+
+    inline fun <reified T : Entity> cast(): T? {
+        val target: String = entityType(T::class.java)
+        if (target != type) return null
+        return this as T
+    }
+
+}
diff --git a/moder/src/main/kotlin/core/schema/Graph.kt b/moder/src/main/kotlin/core/schema/Graph.kt
new file mode 100644
index 0000000000000000000000000000000000000000..63d350e00d579dc1f91286312da949ee98de1f0a
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/Graph.kt
@@ -0,0 +1,44 @@
+package core.schema
+
+import kotlin.reflect.KClass
+
+/**
+ * Behaves as an Entity store
+ */
+object Graph {
+    val entities = mutableSetOf<Entity>()
+
+    fun addEntity(entity: Entity) = entities.add(entity)
+}
+
+fun Entity.traverse(
+    allowedPath: Set<KClass<out Relation>>,
+    terminals: Set<KClass<out Entity>>
+): Set<Entity> {
+    val visited = mutableSetOf<Entity>()  // to prevent loop
+    val affected = mutableSetOf<Entity>() // output
+    val queue = mutableListOf(this)       // to visit still
+    while (queue.isNotEmpty()) {
+        val entityIter = queue.removeLast()
+        visited.add(entityIter)
+        affected.add(entityIter)
+        if (terminals.terminatesIn(entityIter))
+            continue
+
+        // get neighbours on allowed relations
+        val relatives = entityIter.allowedRelatives(allowedPath).values
+
+        queue.addAll(
+            relatives.filter { !visited.contains(it) }
+        )
+    }
+    return affected
+}
+
+private fun Entity.allowedRelatives(allowedPath: Set<KClass<out Relation>>): Map<Relation, Entity> =
+    relatives.filterKeys { relation ->
+        allowedPath.contains(relation::class)
+    }
+
+private fun Set<KClass<out Entity>>.terminatesIn(entity: Entity): Boolean =
+    contains(entity::class)
diff --git a/moder/src/main/kotlin/core/schema/Label.kt b/moder/src/main/kotlin/core/schema/Label.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3101c1e1046b4b6ed165cf79f146eb726f87757c
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/Label.kt
@@ -0,0 +1,3 @@
+package core.schema
+
+data class Label(val name: String, val value: String)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/schema/Relation.kt b/moder/src/main/kotlin/core/schema/Relation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fa48b7b13999771728a32855f907749564d28911
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/Relation.kt
@@ -0,0 +1,12 @@
+package core.schema
+
+import java.util.*
+
+open class Relation(val from: Entity, val to: Entity) {
+    val uuid: UUID = UUID.randomUUID()
+
+    init {
+        from.relate(this, to)
+        to.relate(this, from)
+    }
+}
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/schema/typesStrings.kt b/moder/src/main/kotlin/core/schema/typesStrings.kt
new file mode 100644
index 0000000000000000000000000000000000000000..51acf0414c28fb9a8bcc344f1ced7ff180972d0f
--- /dev/null
+++ b/moder/src/main/kotlin/core/schema/typesStrings.kt
@@ -0,0 +1,12 @@
+package core.schema
+
+import kotlin.reflect.KClass
+
+fun <T> typeFromClass(type: Class<T>): String {
+    return type.simpleName.toLowerCase()
+}
+
+fun <T> entityType(type: Class<T>) = typeFromClass(type)
+fun entityType(type: KClass<out Entity>) = typeFromClass(type.java)
+
+fun relationType(type: KClass<out Relation>) = typeFromClass(type.java)
\ No newline at end of file
diff --git a/moder/src/main/kotlin/core/util/Serial.kt b/moder/src/main/kotlin/core/util/Serial.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c65c66cdde14f44e796ccf0cd233cecbaf56f74d
--- /dev/null
+++ b/moder/src/main/kotlin/core/util/Serial.kt
@@ -0,0 +1,17 @@
+package core.util
+
+import core.schema.Entity
+
+object Serial {
+    var serials = mutableMapOf<String, Int>()
+
+    fun generateSerialFor(entity: Entity): Int {
+        val type: String = entity.type
+        var counter = 1
+        if (serials.containsKey(type))
+            counter += serials[type]!!
+        serials[type] = counter
+
+        return counter
+    }
+}
diff --git a/moder/src/main/kotlin/main.kt b/moder/src/main/kotlin/main.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3fd0c2f57c5049c7562cebdfeb4783135735f4f7
--- /dev/null
+++ b/moder/src/main/kotlin/main.kt
@@ -0,0 +1,22 @@
+import core.relation.physical.physicalRelations
+import core.schema.Entity
+import core.schema.traverse
+import model.entity.electrical.InputSource
+import model.entity.electrical.Supply
+import model.network.loadTestElectricalNetwork
+
+fun main() {
+    val strip1 = loadTestElectricalNetwork()
+    strip1.traverse(
+        allowedPath = physicalRelations,
+        terminals = setOf(InputSource::class)
+    ).let { affected ->
+        val devices = affected.mapNotNull { it.cast<Supply>() }
+        // TODO mark affected supplies
+        // TODO get unreachable nodes
+        devices.forEach { println(it.serial) }
+    }
+}
+
+private val Entity.serial
+    get() = labels.first().value
\ No newline at end of file
diff --git a/moder/src/main/kotlin/model/entity/electrical/ElectricalStuff.kt b/moder/src/main/kotlin/model/entity/electrical/ElectricalStuff.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1021bdc2fe6dd2bead82ebff4ccd681b3926d9ca
--- /dev/null
+++ b/moder/src/main/kotlin/model/entity/electrical/ElectricalStuff.kt
@@ -0,0 +1,18 @@
+package model.entity.electrical
+
+import core.schema.ComposableEntity
+import core.schema.Entity
+
+class InputSource : Entity()
+class SocketStrip(
+    socketNum: Int = 6,
+    val sockets: List<Socket> = List(socketNum) { Socket() }
+) : ComposableEntity<Socket>(sockets)
+
+class Socket : Entity()
+class PowerCord : Entity()
+class Supply : Entity()
+class Device(
+    supplyNum: Int = 1,
+    val supplies: List<Supply> = List(supplyNum) { Supply() }
+) : ComposableEntity<Supply>(supplies)
diff --git a/moder/src/main/kotlin/model/entity/network/NetzwerkStuff.kt b/moder/src/main/kotlin/model/entity/network/NetzwerkStuff.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4c3b3342acfedc95ef0646b4c8ca4fc83c2979a5
--- /dev/null
+++ b/moder/src/main/kotlin/model/entity/network/NetzwerkStuff.kt
@@ -0,0 +1,9 @@
+package model.entity.network
+
+import core.schema.ComposableEntity
+import core.schema.Entity
+
+class Node : ComposableEntity<Port>()
+class Port : Entity()
+class Cable : Entity()
+class Service : Entity()
diff --git a/moder/src/main/kotlin/model/network/ElectricalNetwork.kt b/moder/src/main/kotlin/model/network/ElectricalNetwork.kt
new file mode 100644
index 0000000000000000000000000000000000000000..24e691ac6984e87457b35ef578e20484f7b604ef
--- /dev/null
+++ b/moder/src/main/kotlin/model/network/ElectricalNetwork.kt
@@ -0,0 +1,31 @@
+package model.network
+
+import model.entity.electrical.*
+import core.relation.physical.Connects as PhysicalConnection
+
+fun loadTestElectricalNetwork(): SocketStrip {
+    val strip1 = SocketStrip()
+    val strip2 = SocketStrip(socketNum = 3)
+
+    val server1 = Device(supplyNum = 2)
+    val server2 = Device(supplyNum = 2)
+
+    server1.supplies[0].wiredTo(strip1.sockets[1])
+    server1.supplies[1].wiredTo(strip1.sockets[4])
+
+    server2.supplies[0].wiredTo(strip1.sockets[5])
+    server2.supplies[1].wiredTo(strip2.sockets[2])
+
+    val input = InputSource()
+    PhysicalConnection(input, strip1)
+    PhysicalConnection(input, strip2)
+
+    return strip1
+}
+
+fun Supply.wiredTo(socket: Socket) {
+    val supply = this
+    val cord = PowerCord()
+    PhysicalConnection(supply, cord)
+    PhysicalConnection(cord, socket)
+}