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 @@
+
+
+
+
+
+
+
+
+
+
+ Snek
+ Docs
+
+
+ {% block main %}
+ {% endblock %}
+
+
+
+
+
+
\ 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
+
+```
+
+{% 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