diff --git a/public/assets/styles/main.css b/public/assets/styles/main.css
new file mode 100644
index 0000000..a08cff0
--- /dev/null
+++ b/public/assets/styles/main.css
@@ -0,0 +1,29 @@
+body {
+    background: #1f1f1f;
+    color: #cdcdcd;
+}
+
+/* unvisited link */
+a:link {
+    color: #ff8844;
+    text-decoration: none;
+}
+
+/* visited link */
+a:visited {
+    color: #ff8844;
+    text-decoration: none;
+}
+
+/* mouse over link */
+a:hover {
+    color: #ff8844;
+    text-decoration: none;
+}
+
+/* selected link */
+a:active {
+    color: #ff8844;
+    text-decoration: none;
+    font-weight: bold;
+}
\ No newline at end of file
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 0000000..f697e3a
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,13 @@
+<?php
+ini_set(option: 'display_errors', value: 1);
+ini_set(option: 'display_startup_errors', value: 1);
+error_reporting(error_level: E_ALL);
+
+require dirname(path: __DIR__) . '/src/bootstrap.php';
+
+use App\Controller\AddressBook;
+
+$container = new \App\Service\Container();
+
+$addressBook = $container->get(AddressBook::class);
+//$addressBook = new AddressBook();
diff --git a/src/Controller/AddressBook.php b/src/Controller/AddressBook.php
new file mode 100644
index 0000000..2a2e0ba
--- /dev/null
+++ b/src/Controller/AddressBook.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Controller;
+
+use App\Service\Template;
+use stdClass;
+
+class AddressBook extends stdClass
+{
+    public function __construct(Template $template)
+    {
+        $template->render(templateName: 'index.tpl');
+    }
+}
\ No newline at end of file
diff --git a/src/Entity/AddressBookEntry.php b/src/Entity/AddressBookEntry.php
new file mode 100644
index 0000000..f944311
--- /dev/null
+++ b/src/Entity/AddressBookEntry.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Entity;
+
+class AddressBookEntry
+{
+    public function __construct(
+        private int $userid,
+        private string $first,
+        private string $last,
+        private string $nick,
+    )
+    {
+        // empty body
+    }
+}
\ No newline at end of file
diff --git a/src/Entity/User.php b/src/Entity/User.php
new file mode 100644
index 0000000..29dfd52
--- /dev/null
+++ b/src/Entity/User.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Entity;
+
+class User
+{
+    public function __construct(
+        private string $nick,
+        private string $password,
+        private string $first = '',
+        private string $last = '',
+        private int $id = 0
+    )
+        {
+            // empty body
+        }
+}
\ No newline at end of file
diff --git a/src/Service/Container.php b/src/Service/Container.php
new file mode 100644
index 0000000..440bb0b
--- /dev/null
+++ b/src/Service/Container.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Service;
+
+use App\Controller\AddressBook;
+use Exception;
+use stdClass;
+
+class Container
+{
+    // no autowiring yet, maybe later, but it might fit for a demo
+
+    private Template $template;
+    private AddressBook $addressBook;
+
+    public function __construct()
+    {
+        $this->template = new Template(templateDir: dirname(path: __DIR__, levels: 2) . '/templates/');
+        $this->addressBook = new AddressBook(template: $this->template);
+    }
+
+
+    /**
+     * @throws Exception
+     */
+    public function get(string $class): stdClass
+    {
+        return match($class) {
+            'App\Controller\AddressBook' => $this->addressBook,
+            default => throw new Exception(message: "Missing class definition: $class")
+        };
+    }
+}
\ No newline at end of file
diff --git a/src/Service/Template.php b/src/Service/Template.php
new file mode 100644
index 0000000..a844515
--- /dev/null
+++ b/src/Service/Template.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Service;
+
+use Exception;
+
+class Template
+{
+    public function __construct(private readonly string $templateDir)
+    {
+        // empty body
+    }
+
+    /**
+     * @throws Exception
+     */
+    public function render(string $templateName): void
+    {
+        $template = file_get_contents(filename: $this->templateDir . $templateName);
+
+        // search for includes
+        preg_match_all(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', subject: $template, matches: $matches, flags: PREG_SET_ORDER);
+
+        foreach ($matches as $value) {
+            $token = $value[0];
+            $include = $this->templateDir . $value[1];
+            if (file_exists(filename: $include)) {
+                $replacement = file_get_contents(filename: $include);
+            } else {
+                throw new Exception(message: "Missing included file: $include");
+            }
+            $template = str_replace(search: $token, replace: $replacement, subject: $template);
+        }
+
+        // remove the original template code
+        $template = preg_replace(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', replacement: '', subject: $template);
+
+        echo $template;
+    }
+}
\ No newline at end of file
diff --git a/src/bootstrap.php b/src/bootstrap.php
new file mode 100644
index 0000000..5646681
--- /dev/null
+++ b/src/bootstrap.php
@@ -0,0 +1,18 @@
+<?php
+
+spl_autoload_register(callback: function($className) {
+    $prefix = 'App';
+    $baseDir = __DIR__;
+
+    $len = strlen(string: $prefix);
+    if (strncmp(string1: $prefix, string2: $className, length: $len) !== 0) {
+        return;
+    }
+    $realClassName = substr(string: $className, offset: $len);
+    $classLocation = $baseDir . str_replace(search: '\\', replace: '/', subject: $realClassName) . '.php';
+    if (file_exists(filename: $classLocation)) {
+        require $classLocation;
+    } else {
+        die("Invalid class: $className");
+    }
+});
diff --git a/templates/_footer.tpl b/templates/_footer.tpl
new file mode 100644
index 0000000..8f950a9
--- /dev/null
+++ b/templates/_footer.tpl
@@ -0,0 +1,3 @@
+    <!-- mind the javascript -->
+    </body>
+</html>
\ No newline at end of file
diff --git a/templates/_header.tpl b/templates/_header.tpl
new file mode 100644
index 0000000..c1c74b8
--- /dev/null
+++ b/templates/_header.tpl
@@ -0,0 +1,5 @@
+<html>
+    <head>
+        <title>Address Book</title>
+        <link rel="stylesheet" href="/assets/styles/main.css">
+    </head>
\ No newline at end of file
diff --git a/templates/index.tpl b/templates/index.tpl
new file mode 100644
index 0000000..ce1d3a4
--- /dev/null
+++ b/templates/index.tpl
@@ -0,0 +1,8 @@
+{% include '_header.tpl' %}
+
+<h1>Address Book</h1>
+<a href="/">🏠 Home</a>
+<a href="/">⚙ Admin</a>
+<a href="/">🚪 Login</a>
+
+{% include '_footer.tpl' %}