diff --git a/ActIndex.php b/ActIndex.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb3944b49c900926602aeacab36637eb01589b55
--- /dev/null
+++ b/ActIndex.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace ExampleApp;
+
+use AG\WebApp\Action;
+use AG\WebApp\Request;
+use AG\WebApp\Request\RqGET;
+use AG\WebApp\Response;
+
+/**
+ * Start page of example app.
+ * 
+ * @author Alexandr Gorlov <a.gorlov@gmail.com>
+ */
+class ActIndex implements Action
+{
+    private $rqGet;
+
+    public function __construct(Request $req = null)
+    {
+        $this->rqGet = $req ?? new RqGET();
+    }
+
+    public function handle(Response $resp): Response
+    {
+        $test = $this->rqGet->param('test') ?? 'nope';
+
+        return $resp->withBody(
+            "Hello, World 2!<br>" . 
+            '<a href="/login">login</a><br>' .
+            '$_GET[test]=' . htmlentities($test)
+        );
+    }
+}
\ No newline at end of file
diff --git a/ActLk.php b/ActLk.php
new file mode 100644
index 0000000000000000000000000000000000000000..a77a6979091c6be8eeca10fb2bed01a70b4d310d
--- /dev/null
+++ b/ActLk.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace ExampleApp;
+
+use AG\WebApp\Action;
+use AG\WebApp\Action\ActRedirect;
+use AG\WebApp\Request;
+use AG\WebApp\Response;
+use AG\WebApp\Session;
+use AG\WebApp\Session\AppSession;
+use AG\WebApp\AccessDeniedException;
+
+class ActLk implements Action
+{
+    private $sess;
+    private $redirect;
+
+    public function __construct(
+        Session $sess = null
+    ) {
+        $this->sess = $sess ?? new AppSession;
+    }
+
+    public function handle(Response $resp): Response
+    {
+        if (! $this->sess->exists('login')) {
+            throw new AccessDeniedException('Only Authorized Access');
+        }
+
+        //  login and password are ok
+
+        return $resp->withBody(
+            "Hello: " . $this->sess->get('login') . "<br>" .
+            '<a href="/logout">logout</a>'
+        );
+    }
+}
diff --git a/ActLogin.php b/ActLogin.php
new file mode 100644
index 0000000000000000000000000000000000000000..c0f32547b931090b2d83d634bc17b4f999863ed5
--- /dev/null
+++ b/ActLogin.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace ExampleApp;
+
+use AG\WebApp\Action;
+use AG\WebApp\Action\ActRedirect;
+use AG\WebApp\Request;
+use AG\WebApp\Request\RqGET;
+use AG\WebApp\Response;
+use AG\WebApp\Session;
+use AG\WebApp\Session\AppSession;
+
+class ActLogin implements Action
+{
+    private $session;
+    private $redirect;
+
+    public function __construct(
+        Session $sess = null,
+        Action $redirect = null
+    ) {
+        $this->session = $sess ?? new AppSession;
+        $this->redirect = $redirect ?? new ActRedirect('/lk');
+    }
+
+    public function handle(Response $resp): Response
+    {
+        if (true) { //  login and password ok
+            $this->session->set('login', 'user1');
+            return $this->redirect->handle($resp);
+        } else {
+            return $this->response->withBody(
+                "Bad login or password."
+            );
+        }
+    }
+}
diff --git a/ActLogout.php b/ActLogout.php
new file mode 100644
index 0000000000000000000000000000000000000000..123d55faf8f1fb47efdc10db595596c4b4f06a4d
--- /dev/null
+++ b/ActLogout.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace ExampleApp;
+
+use AG\WebApp\Action;
+use AG\WebApp\Action\ActRedirect;
+use AG\WebApp\Request;
+use AG\WebApp\Request\RqGET;
+use AG\WebApp\Response;
+use AG\WebApp\Session;
+use AG\WebApp\Session\AppSession;
+
+class ActLogout implements Action
+{
+    private $session;
+    private $redirect;
+
+    public function __construct(
+        Session $sess = null,
+        Action $redirect = null
+    ) {
+        $this->session = $sess ?? new AppSession;
+        $this->redirect = $redirect ?? new ActRedirect('/');
+    }
+
+    public function handle(Response $resp): Response
+    {
+        if ($this->session->exists('login')) { //  login and password ok
+            $this->session->unset('login');
+            return $this->redirect->handle($resp);
+        }
+
+        return $this->response->withBody(
+            "You are not logged in."
+        );
+    }
+}
diff --git a/README.md b/README.md
index e98e95c1cd67f45323cfa033e08d65320359a346..42f74404be17c460a56e85ded7bc5443649652ca 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,83 @@
 # ObjectMVC
 PHP Object MVC microframework for web apps
+
+# Example Application
+
+index.php:
+```php
+(new ApplicationStd(
+    [
+        '/' => new ActIndex(),
+        '/login' => new ActLogin(),
+        '/logout' => new ActLogout(),
+        '/lk' => new ActLk(),
+    ],
+    new RespStd
+))->start();
+```
+
+## Actions
+
+**ActIndex.php**
+
+```php
+class ActIndex implements Action
+{
+    public function handle(Response $resp): Response
+    {
+        return $resp->withBody(
+            "Hello, World 2!<br>" . 
+            '<a href="/login">login</a>'
+        );
+    }
+}
+```
+
+If we need database or GET params, put it in constructor:
+
+In this example $_GET['test'] -> with RqGET object
+
+```php
+
+class ActIndex implements Action
+{
+    private $rqGet;
+
+    public function __construct(Request $rqGet = null)
+    {
+        $this->rqGet = $rqGet ?? new RqGET();
+    }
+
+    public function handle(Response $resp): Response
+    {
+        $test = $this->rqGet->param('test') ?? 'nothing';
+
+        return $resp->withBody(
+            "Hello, World 2!<br>" . 
+            '<a href="/login">login</a>' .
+            '$_GET[test]=' . htmlentities($test)
+        );
+    }
+}
+```
+
+GET request, POST request, Database, Config, Environment, Session:
+```php
+public function __construct(
+    Request $req = null, 
+    AppPDO $db = null, 
+    Config $config = null, 
+    Env $env = null,
+    Session $sess = null,
+    Tpl $tpl
+    // or anything you need for your Action
+) 
+{
+    $this->rqPOST = $req ?? new RqGET();
+    $this->rqGET = $req ?? new RqGET();
+    $this->db = $db ?? new AppPDO;
+    $this->config = $config ?? new AppConfig;
+    $this->env = $env ?? new AppEnv;
+    $this->tpl = $tpl ?? new AppTpl
+}
+```
diff --git a/composer.json b/composer.json
index 3bad53f725c8afceb4f8612dff4f8e3143cb1c91..d5f58e36c694ca598f1e25aa9f2f862c3d2fdae6 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,34 @@
 {
+    "name": "agorlov/ObjectMVC",
+    "description": "PHP Object MVC micro framework for web apps",
+    "type": "library",
+    "license": "free",
+    "authors": [
+        {
+            "name": "Alexandr Gorlov",
+            "email": "a.gorlov@gmail.com"
+        }
+    ],
     "require": {
+        "php": ">= 7.1"
+    },
+    "require-dev": {
+        "codeception/codeception": "^2.5.1",
         "squizlabs/php_codesniffer": "^3.4"
-    }
+    },
+
+    "autoload": {
+        "psr-4": {
+            "AG\\WebApp\\": "src",
+            "ExampleApp\\": "./"
+        }
+    },
+    "scripts": {
+        "phpcs": [
+            "phpcs --standard=PSR2 --colors src/"
+        ],
+        "phpcs-fix": [
+            "phpcbf --standard=PSR2 src/"
+        ]
+    }    
 }
diff --git a/index.php b/index.php
index 005ffd666b439cacb55c4c42ebd40814da9026d9..40dd81839a1d4873aa20ad44b50731a0d3c1aa33 100644
--- a/index.php
+++ b/index.php
@@ -2,378 +2,31 @@
 
 
 /**
- * Object MVC Prototype
+ * Object MVC Example app 
  *
  * @author Alexandr Gorlov <a.gorlov@gmail.com>
  */
 
-//require __DIR__ . '/vendor/autoload.php';
-
-// config
-// env
-// http-request
-// session
-// $db
-
-
-interface App
-{
-    public function start(): void;
-}
-
-class NotFoundException extends Exception
-{
-}
-
-class AccessDeniedException extends Exception
-{
-}
-
-
-class ApplicationStd implements App
-{
-    private $actions;
-    private $SERVER;
-
-    /**
-     * Application constructor.
-     *
-     * @param Response|array $action
-     */
-    public function __construct(array $actions, Response $response = null, Request $SERVER = null)
-    {
-
-        $this->SERVER = $SERVER ?? new RqSERVER();
-        $this->actions = $actions;
-        $this->response = $response; // ?? new AppResponse;
-    }
-
-    public function start(): void
-    {
-        try {
-            $requestUri = $this->SERVER->param('REQUEST_URI');
-
-            if (! array_key_exists($requestUri, $this->actions)) {
-                throw new NotFoundException('Page=' . $requestUri . ' not found in actions list!');
-            }
-
-            $resp = $this->actions[$requestUri]->handle($this->response);
-            $resp->print();
-          
-
-            //foreach ($this->response->headers() as $header) {
-            //    header($header);
-            //}
-
-            //if ()
-
-            //echo $this->response->body();
-
-            //$this->response->handle()
-        } catch (NotFoundException $e) {
-            header("Status: 404 Not Found");
-            echo '404! ' . $e->getMessage(); //$twig->render('404.twig', ['message' => $e->getMessage()]);
-        } catch (AccessDeniedException $e) {
-            header("Status: 403 Access denied");
-            echo '403! ' . $e->getMessage(); //$twig->render('403.twig', ['message' => $e->getMessage()]);
-        } catch (Exception $e) {
-            header("Status: 500 Application Error");
-            echo "<h1>Error</h1>";
-            echo "<pre>" . $e . "</pre>";
-        }
-    }
-}
-
-interface Request
-{
-    public function param($param);
-}
-
-interface Response
-{
-    public function print(): void;
-    public function withBody(string $body): Response;
-    public function withHeaders(array $headers): Response;
-}
-
-class RespStd implements Response
-{
-    private $headers;
-    private $body;
-    public function __construct($body = '', $headers = [])
-    {
-        $this->body = $body;
-        $this->headers = $headers;
-    }
-
-    public function withBody(string $body): Response
-    {
-        return new self($body, $this->headers);
-    }
-
-    public function withHeaders(array $headers): Response
-    {
-        return new self($this->body, $headers);
-    }
-
-
-    public function print(): void
-    {
-        foreach ($this->headers as $header) {
-            header($header);
-        }
-
-        echo $this->body;
-    }
-}
-
-class RqSERVER implements Request
-{
-
-    private $request;
-
-    public function __construct(array $request = null)
-    {
-        $this->request = $request ?? $_SERVER;
-    }
-
-    public function param($param)
-    {
-        return $this->request[$param] ?? null;
-    }
-}
-
-class RqGET implements Request
-{
-    private $request;
-
-    public function __construct(array $request = null)
-    {
-        $this->request = $request ?? $_GET;
-    }
-
-    public function param($param)
-    {
-        return $this->request[$param] ?? null;
-    }
-}
-
-class RqPOST implements Request
-{
-    private $request;
-
-    public function __construct(array $request = null)
-    {
-        $this->request = $request ?? $_POST;
-    }
-
-    public function param($param)
-    {
-        return $this->request[$param] ?? null;
-    }
-}
-
-interface Config
-{
-    //...
-}
-
-interface Session
-{
-    public function exists($param): bool;
-
-    public function get($param);
-
-    public function set($param, $value): void;
-
-    public function unset($param): void;
-}
-
-class AppSession implements Session
-{
-    public function exists($param): bool
-    {
-        $this->sessionStart();
-        return array_key_exists($param, $_SESSION);
-    }
-
-    public function get($param)
-    {
-        $this->sessionStart();
-        return $_SESSION[$param] ?? null;
-    }
-
-    public function set($param, $value): void
-    {
-        $this->sessionStart();
-        $_SESSION[$param] = $value;
-        session_commit();
-    }
-
-    public function unset($param): void
-    {
-        $this->sessionStart();
-        unset($_SESSION[$param]);
-        session_commit();
-    }
-
-    private function sessionStart()
-    {
-        if (session_status() == PHP_SESSION_NONE) {
-            session_start();
-        }
-    }
-}
-
-class AppPDO extends PDO
-{
-    public function __construct(AppConfig $config)
-    {
-//        parent::__construct($dsn, $username, $passwd, $options);
-    }
-}
-
-
-interface Action
-{
-    public function handle(Response $resp): Response;
-}
-
-class ActIndex implements Action
-{
-    private $rqGet;
-
-    public function __construct(Request $req = null /*, PDO $db, Config $config, Env $env, Session $sess, Tpl $tpl*/)
-    {
-        $this->rqGet = $req ?? new RqGET();
-//        $this->db = $db ?? new AppPDO;
-//        $this->config = $config ?? new AppConfig;
-//        $this->env = $env ?? new AppEnv;
-//        $this->session = $sesss ?? new AppSession;
-//        $this->tpl = $tpl ?? new AppTpl;
-    }
-
-    public function handle(Response $resp): Response
-    {
-        return $resp->withBody("Hello, World 2!");
-    }
-}
-
-
-class ActRedirect implements Action
-{
-    private $url;
-
-    public function __construct($url)
-    {
-        $this->url = $url;
-    }
-
-    public function handle(Response $resp): Response
-    {
-        return $resp
-            ->withBody('Redirect: ' . $this->url)
-            ->withHeaders([ 'Location: ' . $this->url ]);
-    }
-}
-
-
-class ActLogin implements Action
-{
-    private $session;
-    private $redirect;
-
-    public function __construct(
-        Session $sess = null,
-        Action $redirect = null // Request $req = null , PDO $db, Config $config, Env $env, Session $sess, Tpl $tpl
-    ) {
-        $this->session = $sess ?? new AppSession;
-        $this->redirect = $redirect ?? new ActRedirect('/lk');
-//        $this->rqGet = $req ?? new RqGET();
-//        $this->db = $db ?? new AppPDO;
-//        $this->config = $config ?? new AppConfig;
-//        $this->env = $env ?? new AppEnv;
-//        $this->tpl = $tpl ?? new AppTpl;
-    }
-
-    public function handle(Response $resp): Response
-    {
-        if (true) { //  login and password ok
-            $this->session->set('login', 'user1');
-            return $this->redirect->handle($resp);
-        } else {
-            return $this->response->withBody(
-                "Bad login or password."
-            );
-        }
-    }
-}
-
-
-class ActLogout implements Action
-{
-    private $session;
-    private $redirect;
-
-    public function __construct(
-        Session $sess = null,
-        Action $redirect = null // Request $req = null , PDO $db, Config $config, Env $env, Session $sess, Tpl $tpl
-    ) {
-        $this->session = $sess ?? new AppSession;
-        $this->redirect = $redirect ?? new ActRedirect('/');
-//        $this->rqGet = $req ?? new RqGET();
-//        $this->db = $db ?? new AppPDO;
-//        $this->config = $config ?? new AppConfig;
-//        $this->env = $env ?? new AppEnv;
-//        $this->tpl = $tpl ?? new AppTpl;
-    }
-
-    public function handle(Response $resp): Response
-    {
-        if ($this->session->exists('login')) { //  login and password ok
-            $this->session->unset('login');
-            return $this->redirect->handle($resp);
-        }
-
-        return $this->response->withBody(
-            "You are not logged in."
-        );
-    }
-}
-
-
-
-class ActLk implements Action
-{
-    private $sess;
-    private $redirect;
-
-    public function __construct(
-        Session $sess = null
-        //Action $redirect = null // Request $req = null , PDO $db, Config $config, Env $env, Session $sess, Tpl $tpl
-    ) {
-        $this->sess = $sess ?? new AppSession;
-        //$this->redirect = $redirect ?? new ActRedirect('/');
-//        $this->rqGet = $req ?? new RqGET();
-//        $this->db = $db ?? new AppPDO;
-//        $this->config = $config ?? new AppConfig;
-//        $this->env = $env ?? new AppEnv;
-//        $this->tpl = $tpl ?? new AppTpl;
-    }
-
-    public function handle(Response $resp): Response
-    {
-        if (! $this->sess->exists('login')) { //  login and password ok
-            throw new AccessDeniedException('Only Authorized Access');
-        }
-
-        return $resp->withBody(
-            "Hello: " . $this->sess->get('login')
-        );
-    }
-}
-
-
+require_once './vendor/autoload.php';
+
+use AG\WebApp\App;
+use AG\WebApp\AccessDeniedException;
+use AG\WebApp\NotFoundException;
+use AG\WebApp\ApplicationStd;
+use AG\WebApp\Request;
+use AG\WebApp\Request\RqGET;
+use AG\WebApp\Request\RqPOST;
+use AG\WebApp\Response;
+use AG\WebApp\Response\RespStd;
+use AG\WebApp\Action;
+use AG\WebApp\Action\ActRedirect;
+use AG\WebApp\Session;
+use AG\WebApp\Session\AppSession;
+
+use ExampleApp\ActIndex;
+use ExampleApp\ActLogin;
+use ExampleApp\ActLogout;
+use ExampleApp\ActLk;
 
 (new ApplicationStd(
     [
@@ -382,12 +35,5 @@ class ActLk implements Action
         '/logout' => new ActLogout(),
         '/lk' => new ActLk(),
     ],
-    new RespStd // AppResponse
-    /*
-    new class() implements Request {
-    public function param($param) {
-    return '/login';
-    }
-    }
-    */
+    new RespStd
 ))->start();
diff --git a/src/AccessDeniedException.php b/src/AccessDeniedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..e88de677d13691745bda10cc85dddbc8668a283b
--- /dev/null
+++ b/src/AccessDeniedException.php
@@ -0,0 +1,8 @@
+<?php
+namespace AG\WebApp;
+
+use Exception;
+
+class AccessDeniedException extends Exception
+{
+}
diff --git a/src/Action.php b/src/Action.php
new file mode 100644
index 0000000000000000000000000000000000000000..d995027ba809c3f38518f3312c87792c76a5efa8
--- /dev/null
+++ b/src/Action.php
@@ -0,0 +1,9 @@
+<?php
+namespace AG\WebApp;
+
+//use AG\Response;
+
+interface Action
+{
+    public function handle(Response $resp): Response;
+}
diff --git a/src/Action/ActRedirect.php b/src/Action/ActRedirect.php
new file mode 100644
index 0000000000000000000000000000000000000000..80b6e8fc7b7e743047b2c4e579def77753b3e3a0
--- /dev/null
+++ b/src/Action/ActRedirect.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace AG\WebApp\Action;
+
+use AG\WebApp\Action;
+use AG\WebApp\Response;
+
+class ActRedirect implements Action
+{
+    private $url;
+
+    public function __construct($url)
+    {
+        $this->url = $url;
+    }
+
+    public function handle(Response $resp): Response
+    {
+        return $resp
+            ->withBody('Redirect: ' . $this->url)
+            ->withHeaders([ 'Location: ' . $this->url ]);
+    }
+}
diff --git a/src/App.php b/src/App.php
new file mode 100644
index 0000000000000000000000000000000000000000..93245472f8fc8b3f57189ad8b488be18db84f356
--- /dev/null
+++ b/src/App.php
@@ -0,0 +1,7 @@
+<?php
+namespace AG\WebApp;
+
+interface App
+{
+    public function start(): void;
+}
diff --git a/src/AppPDO.php b/src/AppPDO.php
new file mode 100644
index 0000000000000000000000000000000000000000..f23f6b45c66e0e4797a633dc4b323565b7c94b79
--- /dev/null
+++ b/src/AppPDO.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace AG\WebApp;
+
+class AppPDO extends PDO
+{
+    public function __construct(AppConfig $config)
+    {
+//        parent::__construct($dsn, $username, $passwd, $options);
+    }
+}
\ No newline at end of file
diff --git a/src/ApplicationStd.php b/src/ApplicationStd.php
new file mode 100644
index 0000000000000000000000000000000000000000..d3e4bd833399610ea28b14fac68a34ff47f17743
--- /dev/null
+++ b/src/ApplicationStd.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace AG\WebApp;
+
+use Exception;
+use AG\WebApp\Request\RqSERVER;
+
+class ApplicationStd implements App
+{
+    private $actions;
+    private $SERVER;
+
+    /**
+     * Application constructor.
+     *
+     * @param Response|array $action
+     */
+    public function __construct(array $actions, Response $response = null, Request $SERVER = null)
+    {
+
+        $this->SERVER = $SERVER ?? new RqSERVER();
+        $this->actions = $actions;
+        $this->response = $response; // ?? new AppResponse;
+    }
+
+    public function start(): void
+    {
+        try {
+            $requestUri = $this->SERVER->param('REQUEST_URI');
+
+            if (! array_key_exists($requestUri, $this->actions)) {
+                throw new NotFoundException('Page=' . $requestUri . ' not found in actions list!');
+            }
+
+            $resp = $this->actions[$requestUri]->handle($this->response);
+            $resp->print();
+        } catch (NotFoundException $e) {
+            header("Status: 404 Not Found");
+            echo '404! ' . $e->getMessage();
+        } catch (AccessDeniedException $e) {
+            header("Status: 403 Access denied");
+            echo '403! ' . $e->getMessage();
+        } catch (Exception $e) {
+            header("Status: 500 Application Error");
+            echo "<h1>Error</h1>";
+            echo "<pre>" . $e . "</pre>";
+        }
+    }
+}
diff --git a/src/Config.php b/src/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..a89017f33078828e647bf2aa30e0e924557cba8d
--- /dev/null
+++ b/src/Config.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace AG\WebApp;
+
+interface Config
+{
+    //...
+}
diff --git a/src/NotFoundException.php b/src/NotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5c42c1f9faec92cd00108f398194bdd0f3f3a70
--- /dev/null
+++ b/src/NotFoundException.php
@@ -0,0 +1,8 @@
+<?php
+namespace AG\WebApp;
+
+use Exception;
+
+class NotFoundException extends Exception
+{
+}
diff --git a/src/Request.php b/src/Request.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbc3de511de430f09b0c0a7b3a68a88c4994ffbc
--- /dev/null
+++ b/src/Request.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace AG\WebApp;
+
+interface Request
+{
+    public function param($param);
+}
diff --git a/src/Request/RqGET.php b/src/Request/RqGET.php
new file mode 100644
index 0000000000000000000000000000000000000000..81dfec6226b0624fc5ac5ccb6be696015a6327fc
--- /dev/null
+++ b/src/Request/RqGET.php
@@ -0,0 +1,19 @@
+<?php
+namespace AG\WebApp\Request;
+
+use AG\WebApp\Request;
+
+class RqGET implements Request
+{
+    private $request;
+
+    public function __construct(array $request = null)
+    {
+        $this->request = $request ?? $_GET;
+    }
+
+    public function param($param)
+    {
+        return $this->request[$param] ?? null;
+    }
+}
diff --git a/src/Request/RqPOST.php b/src/Request/RqPOST.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5388ecfa912a29c609a3b9569058fe8bb029ba1
--- /dev/null
+++ b/src/Request/RqPOST.php
@@ -0,0 +1,19 @@
+<?php
+namespace AG\WebApp\Request;
+
+use AG\WebApp\Request;
+
+class RqPOST implements Request
+{
+    private $request;
+
+    public function __construct(array $request = null)
+    {
+        $this->request = $request ?? $_POST;
+    }
+
+    public function param($param)
+    {
+        return $this->request[$param] ?? null;
+    }
+}
diff --git a/src/Request/RqSERVER.php b/src/Request/RqSERVER.php
new file mode 100644
index 0000000000000000000000000000000000000000..59929c069f5d26020e5fe1d98972edc8840d15e8
--- /dev/null
+++ b/src/Request/RqSERVER.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace AG\WebApp\Request;
+
+use AG\WebApp\Request;
+
+class RqSERVER implements Request
+{
+
+    private $request;
+
+    public function __construct(array $request = null)
+    {
+        $this->request = $request ?? $_SERVER;
+    }
+
+    public function param($param)
+    {
+        return $this->request[$param] ?? null;
+    }
+}
diff --git a/src/Response.php b/src/Response.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7aab0dd08c21dadf01ab76f5b8233d51f982830
--- /dev/null
+++ b/src/Response.php
@@ -0,0 +1,9 @@
+<?php
+namespace AG\WebApp;
+
+interface Response
+{
+    public function print(): void;
+    public function withBody(string $body): Response;
+    public function withHeaders(array $headers): Response;
+}
diff --git a/src/Response/RespStd.php b/src/Response/RespStd.php
new file mode 100644
index 0000000000000000000000000000000000000000..df369b64f7eb4f2e913fcb9ef937c9c55dae9843
--- /dev/null
+++ b/src/Response/RespStd.php
@@ -0,0 +1,35 @@
+<?php
+namespace AG\WebApp\Response;
+
+use AG\WebApp\Response;
+
+class RespStd implements Response
+{
+    private $headers;
+    private $body;
+    public function __construct($body = '', $headers = [])
+    {
+        $this->body = $body;
+        $this->headers = $headers;
+    }
+
+    public function withBody(string $body): Response
+    {
+        return new self($body, $this->headers);
+    }
+
+    public function withHeaders(array $headers): Response
+    {
+        return new self($this->body, $headers);
+    }
+
+
+    public function print(): void
+    {
+        foreach ($this->headers as $header) {
+            header($header);
+        }
+
+        echo $this->body;
+    }
+}
diff --git a/src/Session.php b/src/Session.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab60aea14b9e4d280de71393239ba8dfc9a6663b
--- /dev/null
+++ b/src/Session.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace AG\WebApp;
+
+interface Session
+{
+    public function exists($param): bool;
+
+    public function get($param);
+
+    public function set($param, $value): void;
+
+    public function unset($param): void;
+}
diff --git a/src/Session/AppSession.php b/src/Session/AppSession.php
new file mode 100644
index 0000000000000000000000000000000000000000..a2311c9999c1f0c0dbc361a0f2098d19d672f30c
--- /dev/null
+++ b/src/Session/AppSession.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace AG\WebApp\Session;
+
+use AG\WebApp\Session;
+
+/**
+ * @todo rename to SessionStd ?
+ */
+class AppSession implements Session
+{
+    public function exists($param): bool
+    {
+        $this->sessionStart();
+        return array_key_exists($param, $_SESSION);
+    }
+
+    public function get($param)
+    {
+        $this->sessionStart();
+        return $_SESSION[$param] ?? null;
+    }
+
+    public function set($param, $value): void
+    {
+        $this->sessionStart();
+        $_SESSION[$param] = $value;
+        session_commit();
+    }
+
+    public function unset($param): void
+    {
+        $this->sessionStart();
+        unset($_SESSION[$param]);
+        session_commit();
+    }
+
+    private function sessionStart()
+    {
+        if (session_status() == PHP_SESSION_NONE) {
+            session_start();
+        }
+    }
+}