diff --git a/src/snek/docs/__pycache__/app.cpython-312.pyc b/src/snek/docs/__pycache__/app.cpython-312.pyc
new file mode 100644
index 0000000..6f355a6
Binary files /dev/null and b/src/snek/docs/__pycache__/app.cpython-312.pyc differ
diff --git a/src/snek/docs/app.py b/src/snek/docs/app.py
new file mode 100644
index 0000000..50a4245
--- /dev/null
+++ b/src/snek/docs/app.py
@@ -0,0 +1,43 @@
+import pathlib
+
+from aiohttp import web
+from app.app import Application as BaseApplication
+
+from snek.system.markdown import MarkdownExtension
+
+
+class Application(BaseApplication):
+
+    def __init__(self, path=None, *args, **kwargs):
+        self.path = pathlib.Path(path)
+        template_path = self.path
+
+        super().__init__(template_path=template_path, *args, **kwargs)
+        self.jinja2_env.add_extension(MarkdownExtension)
+
+        self.router.add_get("/{tail:.*}", self.handle_document)
+
+    async def handle_document(self, request):
+        relative_path = request.match_info["tail"].strip("/")
+        if relative_path == "":
+            relative_path = "index.html"
+        document_path = self.path.joinpath(relative_path)
+        if not document_path.exists():
+            return web.Response(
+                status=404,
+                body=b"Resource is not found on this server.",
+                content_type="text/plain",
+            )
+        if document_path.is_dir():
+            document_path = document_path.joinpath("index.html")
+        if not document_path.exists():
+            return web.Response(
+                status=404,
+                body=b"Resource is not found on this server.",
+                content_type="text/plain",
+            )
+
+        response = await self.render_template(
+            str(document_path.relative_to(self.path)), request
+        )
+        return response
diff --git a/src/snek/docs/docs/api.html b/src/snek/docs/docs/api.html
new file mode 100644
index 0000000..e30a99d
--- /dev/null
+++ b/src/snek/docs/docs/api.html
@@ -0,0 +1,61 @@
+{% extends "docs/base.html" %}
+
+{% block main %}
+{% markdown %}
+
+# API Documentation
+
+Currently only some details about the internal API are available.
+
+## How to create a user
+```python
+# Save user to the table named 'user'
+# Password gets sha256 encrypted with default a salt string
+# of the snek.system.security module.
+
+new_user_object = await app.service.user.register(
+    username="retoor", 
+    password="retoorded"
+)
+```
+
+## Encrypt string
+```python
+from snek.system import security
+
+# Support for both utf and bytes.
+var1 = security.encrypt("data")
+var2 = security.encrypt(b"data")
+
+# Is correct:
+assert(var1 == var2)
+```
+
+## How to create a basic HTML / Markdown view
+```python
+from snek.system.view import BaseView 
+
+class IndexView(BaseView):
+    
+    async def get(self):
+        # The render function supports markdown.
+        # It will render with syntax highlighting.
+        # Just use the .md file extension in the file name.
+        return await self.render("index.html")
+```
+## How to create a FormView
+```python
+from snek.system.view import BaseFormView
+from snek.form.register import RegisterForm
+
+class RegisterFormView(BaseFormView):
+    
+    form = RegisterForm
+```
+## How to register a class view
+```python
+app.routes.add_view("/your-page.html", YourViewClass)
+```
+
+{% endmarkdown %}
+{% endblock %}
\ No newline at end of file
diff --git a/src/snek/docs/docs/base.html b/src/snek/docs/docs/base.html
new file mode 100644
index 0000000..7c53bec
--- /dev/null
+++ b/src/snek/docs/docs/base.html
@@ -0,0 +1,116 @@
+<html>
+
+<head>
+    <style>{{ highlight_styles }}</style>
+    <style>
+        
+        * {
+
+            box-sizing: border-box;
+        }
+
+        .dialog {
+
+            background-color: #0f0f0f;
+            border-radius: 10px;
+            padding: 30px;
+            width: 800px;
+            margin: 30px;
+            box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
+        }
+
+        @media screen and (max-width: 500px) {
+            .center {
+                width: 100%;
+                left: 0px;
+            }
+
+            .dialog {
+                width: 100%;
+                left: 0px;
+            }
+
+        }
+
+        h1 {
+            font-size: 2em;
+            color: #f05a28;
+            margin-bottom: 20px;
+        }
+
+        h2 {
+            font-size: 1.4em;
+            color: #f05a28;
+            margin-bottom: 20px;
+        }
+
+        html,body,main {
+            font-family: Arial, sans-serif;
+            background-color: #1a1a1a;
+            color: #e6e6e6;
+            line-height: 1.5;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            min-height: 100vh;
+            width: 100%;
+        }
+        article {
+            max-width: 100%;
+            width: 60%;
+            background-color: #0f0f0f;
+            padding: 30px;
+            min-height: 100vh;
+            word-break: break-all;
+        }
+        footer {
+            position: fixed;
+            width: 60%;
+            text-align: center; 
+            bottom: 0;
+            left: 20%;
+            background-color: #000;
+        }
+        a {
+    color: #f05a28;
+    display: block;
+    margin-top: 15px;
+    font-size: 0.9em;
+    transition: color 0.3s;
+  }
+  header {
+
+    text-align: left;
+    width: 60%;
+    padding: 30px;
+  }
+  header a {
+    display: inline;
+
+  }
+        div {
+            text-align: left;
+
+        }
+    </style>
+</head>
+
+<body>
+    <main>
+        <header>
+            <a href="/">Snek</a>
+            <a href="/docs/docs">Docs</a>
+        </header>
+      <article>
+            {% block main %}
+            {% endblock %}
+        </article>
+    </main>
+    <footer>
+        {% markdown %}
+        [Respository](https://github.com/retoor/snek)
+        {% endmarkdown %}
+    </footer>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/src/snek/docs/docs/form_api_javascript.html b/src/snek/docs/docs/form_api_javascript.html
new file mode 100644
index 0000000..c83ee7f
--- /dev/null
+++ b/src/snek/docs/docs/form_api_javascript.html
@@ -0,0 +1,17 @@
+{% extends "docs/base.html" %}
+
+{% block main %}
+{% markdown %}
+# Form API Javascript 
+
+## Dependencies
+ - generic-form.js 
+
+## Usage 
+It's just a HTML component that can be declared using an one liner. Buttons and title are specified server side.
+```html 
+<generic-form url="/url-to-form-api"></generic-form>
+```
+
+{% endmarkdown %}
+{% endblock %}
\ No newline at end of file
diff --git a/src/snek/docs/docs/form_api_python.html b/src/snek/docs/docs/form_api_python.html
new file mode 100644
index 0000000..d7e67bc
--- /dev/null
+++ b/src/snek/docs/docs/form_api_python.html
@@ -0,0 +1,92 @@
+{% extends "docs/base.html" %}
+
+{% block main %}
+{% markdown %}
+# Form API Javascript 
+
+## Dependencies
+ - `snek.system.form.Form`
+ - `snek.system.form.HTMLElement`
+ - `snek.system.form.FormInputElement`
+ - `snek.system.form.FormButtonElement`
+
+## Usage 
+Here is an example with custom validation. 
+This example contains a field that checks if user already exists. 
+If invalid, it adds an error message which automatically invalidates the field. 
+Handling of the error messages will automatically done client side.
+
+Forms are usaly located in `snek/form/[form name].py`.
+
+```python
+from snek.system.form import Form, HTMLElement,FormInputElement,FormButtonElement
+
+class UsernameField(FormInputElement):
+
+    @property
+    async def errors(self):
+        result = await super().errors
+        if self.value and await self.app.services.user.count(username=self.value):
+            result.append("Username is not available.")
+        return result
+
+class RegisterForm(Form):
+
+    title = HTMLElement(tag="h1", text="Register")
+
+    username = UsernameField(
+        name="username", 
+        required=True,
+        min_length=2,
+        max_length=20,
+        regex=r"^[a-zA-Z0-9_]+$",
+        place_holder="Username",
+        type="text"
+    )
+    email = FormInputElement(
+        name="email",
+        required=False,
+        regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
+        place_holder="Email address",
+        type="email"
+    )
+    password = FormInputElement(
+        name="password",
+        required=True,
+        regex=r"^[a-zA-Z0-9_.+-]{6,}",
+        type="password",
+        place_holder="Password"
+    )
+    action = FormButtonElement(
+        name="action",
+        value="submit",
+        text="Register",
+        type="button"
+    )
+```
+
+## Set data 
+
+```python 
+# The input structure is in same format as output structure.
+# Output structure is the result of await form.to_json()
+data = dict(
+    username=dict(value="retoor"),
+    password=dict(value="retoorded")
+)
+form.set_user_data(data)
+
+# Check if form is valid.
+is_valid = await form.is_valid
+
+# Convert form to a record (kv pairs) to be used for persistance. 
+# It does contain an filled uid (UUID4) field already to be used as primary key.
+# Default fields:
+# - uid (automatically generated, it's an UUID4 wich you can use as private key for database)
+# - created_at (automatically generated, it's a string representation of UTC locale)
+# - updated_at (execute await form.updated_at.update() before saving to set value)
+key_value_values = await form.record 
+```
+
+{% endmarkdown %}
+{% endblock %}
\ No newline at end of file
diff --git a/src/snek/docs/docs/index.html b/src/snek/docs/docs/index.html
new file mode 100644
index 0000000..8ced8ab
--- /dev/null
+++ b/src/snek/docs/docs/index.html
@@ -0,0 +1,37 @@
+{% extends "docs/base.html" %}
+
+{% block main %}
+{% markdown %}
+# Snek
+
+# Introduction
+
+Snek is a high customizable chat application. 
+It is made because Rocket Chat didn't fit my needs anymore. It became bloathed and very heavy commercialized. You would get upsell messages on your locally hosted instance!
+
+This documentation is under construction. Only the form API and the small introduction is a bit documented.
+
+## Quick API notes 
+[Small introduction / cheatsheet](/docs/docs/api.html)
+
+## View API
+With the view classes of Snek you can render HTML and Markdown 
+ - [API Python](#)
+ - [API Javascript](#)
+
+## ORM API
+Snek's database model is based on Python dataset library. 
+Snek uses a model/mapper architecture build on top of that library.
+ - [API](#)
+
+## Form API
+Snek does have his own components for creating and rendering forms. 
+All forms are made server side and client side is generated client side using a HTML component.
+It's client side only one line to include a form that can validate and submit.
+Validation is server side using REST. Page won't refresh.
+[API Python](/docs/docs/form_api_python.html) 
+[API Javascript](/docs/docs/form_api_javascript.html)
+
+
+{% endmarkdown %}
+{% endblock %}
\ No newline at end of file