diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a233f9..0172405 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,110 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
---
## [Unreleased]
+## [v2.1.0]
+
+This release focuses on performance, developer experience, and ecosystem maturity.
+
+Vix is no longer just fast.
+It is now structured, documented, and ready to be used in real projects.
+
+---
+
+### Performance
+
+- optimized HTTP hot path in core runtime
+- improved scheduler and task execution model
+- reduced overhead in run queue processing
+- optimized async coroutine fast-path
+- removed redundant error handling in async layer
+
+Result:
+- lower latency
+- better throughput
+- more predictable execution under load
+
+---
+
+### Templates
+
+- complete refactor of template examples
+- introduction of real-world use cases (dashboard, blog, marketing pages)
+- improved layout system (extends, includes, filters)
+
+New examples include:
+- shop dashboard
+- blog home and post pages
+- admin dashboards
+- marketing landing pages
+
+---
+
+### Documentation
+
+- massive addition of documentation across the entire ecosystem
+- new structured docs for:
+ - core modules
+ - async
+ - cache
+ - p2p and sync
+ - middleware and HTTP
+ - database and ORM
+- detailed real-world examples (auth, JWT, caching, rate limit, etc.)
+
+Result:
+- significantly improved onboarding
+- clearer mental model of Vix architecture
+- easier adoption for new developers
+
+---
+
+### Examples
+
+#### Added
+- structured template examples (01 → 12 progression)
+- new real-world scenarios across modules
+- improved consistency across all example categories
+
+#### Removed
+- removed outdated and legacy template examples
+- cleaned old and unstructured demo files
+
+---
+
+### Core & Modules
+
+- improvements across:
+ - core
+ - async
+ - template
+- better internal consistency and structure
+- improved maintainability for future features
+
+---
+
+### Developer Experience
+
+- examples now follow a progressive learning path
+- documentation aligned with real usage patterns
+- clearer separation between basic and advanced concepts
+
+---
+
+### Stability
+
+- improved runtime reliability
+- better performance under load
+- no breaking changes
+
+---
+
+### Summary
+
+v2.1.0 marks a major step toward making Vix a complete developer platform.
+
+From performance to documentation to real-world examples,
+Vix is now designed to be learned, used, and extended.
+
## [v2.0.0] - 2026-03-31
Vix.cpp 2.0 starts here.
diff --git a/README.md b/README.md
index 017c781..4534251 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,51 @@
-
-
-
-## Performance is not a feature it’s a requirement
+
+ 🌍 Website ·
+ 📘 Docs ·
+ ⬇️ Download
+
-Vix.cpp is designed to remove overhead, unpredictability, and GC pauses.
+
-### ⚡ Benchmarks (Dec 2025)
+
-| Framework | Requests/sec | Avg Latency |
-| --------------------------- | ------------ | ----------- |
-| ⭐ **Vix.cpp (pinned CPU)** | **~99,000** | 7–10 ms |
-| Vix.cpp (default) | ~81,400 | 9–11 ms |
-| Go (Fiber) | ~81,300 | ~0.6 ms |
-| Deno | ~48,800 | ~16 ms |
-| Node.js (Fastify) | ~4,200 | ~16 ms |
-| PHP (Slim) | ~2,800 | ~17 ms |
-| FastAPI (Python) | ~750 | ~64 ms |
+
-## Installation
+ |
+
+
-Install the Vix runtime on your system using one of the commands below.
-Note that there are multiple ways to install Vix.
+## Install
#### Linux
-**Ubuntu / Debian deps (example):**
-
```bash
sudo apt update
sudo apt install -y \
@@ -149,27 +129,64 @@ Run C++ like a script:
```bash
vix run main.cpp
-vix dev main.cpp
```
-Vix handles compilation, linking, and execution automatically.
+Open http://localhost:8080
+
+## Why Vix.cpp
+
+Most systems assume perfect conditions.
+Vix is built for when things are not.
+
+- predictable under load
+- no GC pauses
+- offline-first by design
+- deterministic execution
+- minimal setup
+
+---
+
+## Performance
+
+Stable under sustained load.
+
+| Metric | Value |
+|--------------|----------------|
+| Requests/sec | ~66k – 68k |
+| Avg Latency | ~13–20 ms |
+| P99 Latency | ~17–50 ms |
+
+---
+
+## Core principles
+
+- Local-first execution
+- Network is optional
+- Deterministic behavior
+- Failure-tolerant
+- Built for unreliable environments
+
+---
## Learn more
-- 📘 Docs: https://vixcpp.com/docs
-- 🌍 Website: https://vixcpp.com
-- 📦 Registry: https://vixcpp.com/registry
-- 📦 Examples: https://vixcpp.com/docs/examples
+- Docs: https://vixcpp.com/docs
+- Registry: https://vixcpp.com/registry
+- Examples: https://vixcpp.com/docs/examples
+
---
## Contributing
Contributions are welcome.
-If you care about modern C++, performance, and real-world reliability, you’ll feel at home here.
-Please read the contributing guide before opening a PR.
+
+### Focus areas
+
+- performance
+- reliability
+- networking
+- offline-first systems
---
-⭐ If this project resonates with you, consider starring the repository.
MIT License
-
diff --git a/docs/README_REPL.md b/docs/README_REPL.md
deleted file mode 100644
index bee4303..0000000
--- a/docs/README_REPL.md
+++ /dev/null
@@ -1,276 +0,0 @@
-# 🧠 Vix REPL — Interactive Runtime Shell
-
-The **Vix REPL** is an interactive shell built directly into the `vix` binary.
-Just like **python**, **node**, or **deno**, you start it simply by typing:
-
-```bash
-vix
-```
-
-No subcommand. No flags.
-This is the **default interactive mode** of Vix.
-
----
-
-## ✨ What is the Vix REPL?
-
-The Vix REPL is a **developer-friendly interactive environment** designed to:
-
-- Experiment with C++-like expressions
-- Test runtime logic quickly
-- Evaluate math expressions
-- Manipulate variables and JSON data
-- Call built-in Vix runtime APIs
-- Prototype logic before moving to real code
-
-It feels familiar if you’ve used:
-
-- Python REPL
-- Node.js REPL
-- Deno REPL
-
-…but adapted to the **Vix.cpp philosophy**.
-
----
-
-## ▶️ Starting the REPL
-
-```bash
-vix
-```
-
-Example startup:
-
-```
-Vix.cpp v1.x (CLI) — Modern C++ backend runtime
-[GCC 13.3.0] on linux
-Exit: Ctrl+C / Ctrl+D | Clear: Ctrl+L | Type help for help
-vix>
-```
-
----
-
-## 🧮 Math Expressions
-
-You can type expressions directly:
-
-```text
-1 + 2
-10 * (3 + 4)
-```
-
-With variables:
-
-```text
-x = 3
-x + 1
-x * 10
-```
-
----
-
-## 📦 Variables
-
-### Assign values
-
-```text
-x = 42
-name = "Gaspard"
-```
-
-### Print variables
-
-```text
-x
-name
-```
-
----
-
-## 🧩 JSON Support
-
-The REPL supports **strict JSON** using `nlohmann::json`.
-
-### 1. Simple Objects
-```text
-user = {"name":"Gaspard","age":10}
-```
-
-### 2. Arrays
-```text
-items = [1, 2, 3]
-```
-
-### 3. Nested Objects & Arrays
-```text
-profile = {
- "name": "Gaspard",
- "meta": { "country": "UG", "verified": true },
- "tags": ["cpp", "vix", "repl"]
-}
-```
-
-### 4. Array of Objects
-```text
-users = [
- { "id": 1, "name": "Alice" },
- { "id": 2, "name": "Bob" }
-]
-```
-
-### 5. Mixed Types
-```text
-config = {
- "active": true,
- "threshold": 3.14,
- "backup": null
-}
-```
-
-### ❓ Troubleshooting & Common Errors
-
-The JSON parser is **strict**. Here are common syntax mistakes:
-
-| Error Type | Invalid Syntax ❌ | Correct Syntax ✅ |
-| :--- | :--- | :--- |
-| **Missing Colon** | `{"name" "Gaspard"}` | `{"name": "Gaspard"}` |
-| **Comma instead of Colon** | `{"name", "Gaspard"}` | `{"name": "Gaspard"}` |
-| **Trailing Comma** | `{"a": 1,}` | `{"a": 1}` |
-| **Single Quotes** | `{'name': 'Gaspard'}` | `{"name": "Gaspard"}` |
-
----
-
-## 🖨️ print / println
-
-### Basic output
-
-```text
-print("Hello")
-println("Hello world")
-```
-
-### Mix strings and expressions
-
-```text
-x = 3
-println("x =", x)
-println("x+1 =", x+1)
-```
-
----
-
-## ⚙️ Built-in Vix API
-
-The REPL exposes a built-in `Vix` object.
-
-### Working directory
-
-```text
-cwd()
-Vix.cwd()
-```
-
-### Change directory
-
-```text
-Vix.cd("..")
-```
-
-### Process info
-
-```text
-pid()
-Vix.pid()
-```
-
-### Environment variables
-
-```text
-Vix.env("HOME")
-Vix.env("PATH")
-```
-
-### Arguments
-
-```text
-Vix.args()
-```
-
----
-
-## 🛠️ Filesystem helpers
-
-```text
-Vix.mkdir("tmp")
-Vix.mkdir("tmp/logs", true)
-```
-
----
-
-## ▶️ Running CLI commands
-
-You can run CLI commands **from inside the REPL**:
-
-```text
-Vix.run("version")
-Vix.run("help")
-Vix.run("check", "--help")
-```
-
----
-
-## 🧹 Session control
-
-### Clear screen
-
-```text
-clear
-```
-
-or:
-
-```text
-Ctrl + L
-```
-
-### Exit REPL
-
-```text
-exit
-```
-
-or:
-
-```text
-Ctrl + D
-Ctrl + C
-```
-
----
-
-## 🧠 Tips & Best Practices
-
-- Use the REPL to **prototype logic**
-- Validate math & JSON before writing C++
-- Use `println()` for debugging expressions
-- Treat the REPL as your **scratchpad**
-
----
-
-## 🧭 Roadmap (REPL)
-
-Planned features:
-
-- Property access: `user.name`
-- Function definitions
-- History persistence
-- Autocomplete for variables
-- Structured error hints
-- Module imports
-
----
-
-## 🧾 License
-
-MIT License © Gaspard Kirira
-Part of the **Vix.cpp** ecosystem
diff --git a/docs/api.md b/docs/api.md
new file mode 100644
index 0000000..7796249
--- /dev/null
+++ b/docs/api.md
@@ -0,0 +1,53 @@
+# API Reference
+
+This section documents the public API surface of Vix.
+
+It focuses on:
+
+- Core HTTP primitives
+- Routing
+- Request & Response
+- JSON layer
+- WebSocket
+- Configuration
+- Runtime behavior
+
+The goal of this section is precision.
+
+If the Guide shows *how* to use Vix, the API section shows *what exactly
+exists*.
+
+------------------------------------------------------------------------
+
+## Structure
+
+- App
+- Request
+- Response
+- Routing methods
+- JSON helpers
+- WebSocket server
+- Config loader
+
+Each page in this section describes:
+
+- Available methods
+- Signatures
+- Minimal usage examples
+- Behavioral notes
+
+------------------------------------------------------------------------
+
+## Philosophy
+
+The Vix API follows strict principles:
+
+- Explicit over magic
+- Minimal abstraction layers
+- Deterministic behavior
+- No hidden global state
+- No runtime reflection
+
+Everything that happens should be visible in code.
+
+
diff --git a/docs/api/async.md b/docs/api/async.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/api/config.md b/docs/api/config.md
new file mode 100644
index 0000000..f9a974b
--- /dev/null
+++ b/docs/api/config.md
@@ -0,0 +1,158 @@
+# Config API
+
+This page documents the configuration loader in Vix.
+
+Header:
+
+``` cpp
+#include
+```
+
+Core type:
+
+``` cpp
+vix::config::Config
+```
+
+The configuration system is:
+
+- JSON-based
+- Strongly typed
+- Path-addressable via dot notation
+- Safe with fallback defaults
+
+------------------------------------------------------------------------
+
+# Constructor
+
+``` cpp
+vix::config::Config cfg{"config.json"};
+```
+
+Loads and parses the JSON file at construction.
+
+If the file cannot be loaded, behavior depends on implementation
+configuration. In production, always validate at boot time.
+
+------------------------------------------------------------------------
+
+# Getters
+
+All getters accept:
+
+- dot path string
+- fallback value
+
+------------------------------------------------------------------------
+
+## get_string
+
+``` cpp
+std::string value = cfg.get_string("server.host", "127.0.0.1");
+```
+
+------------------------------------------------------------------------
+
+## get_int
+
+``` cpp
+int port = cfg.get_int("server.port", 8080);
+```
+
+------------------------------------------------------------------------
+
+## get_bool
+
+``` cpp
+bool debug = cfg.get_bool("runtime.debug", false);
+```
+
+------------------------------------------------------------------------
+
+## get_double
+
+``` cpp
+double ratio = cfg.get_double("limits.ratio", 0.5);
+```
+
+------------------------------------------------------------------------
+
+# Dot Path Access
+
+Nested JSON can be accessed using dot notation.
+
+Given:
+
+``` json
+{
+ "database": {
+ "host": "localhost",
+ "port": 5432
+ }
+}
+```
+
+Access:
+
+``` cpp
+cfg.get_string("database.host", "127.0.0.1");
+cfg.get_int("database.port", 3306);
+```
+
+------------------------------------------------------------------------
+
+# Minimal Usage Example
+
+``` cpp
+#include
+#include
+
+int main()
+{
+ vix::config::Config cfg{"config.json"};
+
+ std::string host = cfg.get_string("server.host", "0.0.0.0");
+ int port = cfg.get_int("server.port", 8080);
+
+ std::cout << host << ":" << port << "\n";
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+# Environment Override Pattern
+
+Configuration files should not contain secrets in production.
+
+Example override:
+
+``` cpp
+#include
+#include
+
+int main()
+{
+ vix::config::Config cfg{"config.json"};
+
+ int port = cfg.get_int("server.port", 8080);
+
+ if (const char* env = std::getenv("PORT"))
+ port = std::atoi(env);
+
+ return port;
+}
+```
+
+------------------------------------------------------------------------
+
+# Design Notes
+
+- Configuration is read at startup.
+- No global mutable config state.
+- Safe access always requires fallback.
+- Deterministic behavior: no implicit environment merging.
+
+The Config API is intentionally small and predictable.
+
diff --git a/docs/api/http.md b/docs/api/http.md
new file mode 100644
index 0000000..b5cfee4
--- /dev/null
+++ b/docs/api/http.md
@@ -0,0 +1,232 @@
+# HTTP API
+
+This page documents the core HTTP primitives in Vix.
+
+It covers:
+
+- App
+- Routing methods
+- Request
+- Response
+
+All examples are minimal and placed entirely inside `main()`.
+
+------------------------------------------------------------------------
+
+# App
+
+Header:
+
+``` cpp
+#include
+```
+
+Core type:
+
+``` cpp
+vix::App
+```
+
+### Constructor
+
+``` cpp
+App app;
+```
+
+### Run
+
+``` cpp
+app.run(8080);
+```
+
+Starts the HTTP server on the given port (blocking call).
+
+------------------------------------------------------------------------
+
+# Routing Methods
+
+## GET
+
+``` cpp
+app.get(path, handler);
+```
+
+## POST
+
+``` cpp
+app.post(path, handler);
+```
+
+## PUT
+
+``` cpp
+app.put(path, handler);
+```
+
+## DELETE
+
+``` cpp
+app.del(path, handler);
+```
+
+------------------------------------------------------------------------
+
+## Minimal Example
+
+``` cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/", [](Request&, Response& res) {
+ res.send("Hello");
+ });
+
+ app.run(8080);
+}
+```
+
+------------------------------------------------------------------------
+
+# Request
+
+Type:
+
+``` cpp
+vix::Request
+```
+
+Provides access to:
+
+- Path parameters
+- Query parameters
+- Headers
+- Body
+- JSON payload
+
+------------------------------------------------------------------------
+
+## Path parameter
+
+``` cpp
+req.param("id", "0");
+```
+
+Returns string value or fallback.
+
+------------------------------------------------------------------------
+
+## Query parameter
+
+``` cpp
+req.query_value("page", "1");
+```
+
+------------------------------------------------------------------------
+
+## Headers
+
+``` cpp
+req.header("User-Agent");
+req.has_header("Authorization");
+```
+
+------------------------------------------------------------------------
+
+## Body
+
+``` cpp
+std::string body = req.body();
+```
+
+------------------------------------------------------------------------
+
+## JSON
+
+``` cpp
+const auto& j = req.json();
+```
+
+Returns parsed JSON (high-level JSON layer).
+
+------------------------------------------------------------------------
+
+# Response
+
+Type:
+
+``` cpp
+vix::Response
+```
+
+Controls HTTP output.
+
+------------------------------------------------------------------------
+
+## Status
+
+``` cpp
+res.status(201);
+res.set_status(404);
+```
+
+------------------------------------------------------------------------
+
+## Send text
+
+``` cpp
+res.send("Hello");
+```
+
+------------------------------------------------------------------------
+
+## Send JSON
+
+``` cpp
+res.json({"message", "ok"});
+```
+
+------------------------------------------------------------------------
+
+## Auto-send return
+
+If a route handler returns:
+
+- `std::string` → text response
+- JSON object → JSON response
+
+Example:
+
+``` cpp
+app.get("/auto", [](Request&, Response&) {
+ return vix::json::o("message", "auto");
+});
+```
+
+------------------------------------------------------------------------
+
+# Behavior Notes
+
+- If `res.send()` or `res.json()` is called, returned values are
+ ignored.
+- If nothing is sent, the handler must return a value.
+- Status defaults to 200 unless changed.
+- Handlers execute synchronously per request context.
+
+------------------------------------------------------------------------
+
+# Design Philosophy
+
+The HTTP layer is:
+
+- Minimal
+- Explicit
+- Deterministic
+- Zero hidden middleware stack by default
+
+You control exactly what happens in each handler.
+
diff --git a/docs/api/index.md b/docs/api/index.md
new file mode 100644
index 0000000..11fca02
--- /dev/null
+++ b/docs/api/index.md
@@ -0,0 +1,56 @@
+# API Reference
+
+This section documents the public API surface of Vix.
+
+It focuses on:
+
+- Core HTTP primitives
+- Routing
+- Request & Response
+- JSON layer
+- WebSocket
+- Configuration
+- Runtime behavior
+
+The goal of this section is precision.
+
+If the Guide shows *how* to use Vix, the API section shows *what exactly
+exists*.
+
+------------------------------------------------------------------------
+
+## Structure
+
+- App
+- Request
+- Response
+- Routing methods
+- JSON helpers
+- WebSocket server
+- Config loader
+
+Each page in this section describes:
+
+- Available methods
+- Signatures
+- Minimal usage examples
+- Behavioral notes
+
+------------------------------------------------------------------------
+
+## Philosophy
+
+The Vix API follows strict principles:
+
+- Explicit over magic
+- Minimal abstraction layers
+- Deterministic behavior
+- No hidden global state
+- No runtime reflection
+
+Everything that happens should be visible in code.
+
+------------------------------------------------------------------------
+
+Continue with the next API component page.
+
diff --git a/docs/api/json.md b/docs/api/json.md
new file mode 100644
index 0000000..915a12a
--- /dev/null
+++ b/docs/api/json.md
@@ -0,0 +1,260 @@
+# JSON API
+
+This page documents the JSON facilities available in Vix.
+
+Vix provides two JSON layers:
+
+1) Simple JSON (`vix/json/Simple.hpp`)
+2) High-level JSON (`vix/json/json.hpp`)
+
+They serve different purposes and can coexist.
+
+------------------------------------------------------------------------
+
+# 1) Simple JSON
+
+Header:
+
+``` cpp
+#include
+```
+
+Namespace:
+
+``` cpp
+vix::json
+```
+
+Core types:
+
+- `token` → generic JSON value
+- `array_t` → JSON array
+- `kvs` → JSON object storage
+
+------------------------------------------------------------------------
+
+## token
+
+Represents any JSON value.
+
+Supported kinds:
+
+- null
+- bool
+- int64
+- double
+- string
+- array
+- object
+
+Example:
+
+``` cpp
+#include
+#include
+
+using namespace vix::json;
+
+int main()
+{
+ token t = 42;
+
+ if (t.is_i64())
+ std::cout << t.as_i64_or(0) << "\n";
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+## array_t
+
+Dynamic JSON array.
+
+Key methods:
+
+- `push_int(...)`
+- `push_string(...)`
+- `push_bool(...)`
+- `size()`
+- `operator[]`
+
+Example:
+
+``` cpp
+#include
+
+using namespace vix::json;
+
+int main()
+{
+ array_t arr;
+ arr.push_int(1);
+ arr.push_string("two");
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+## kvs
+
+Object-like key/value storage.
+
+Key methods:
+
+- `set_string(key, value)`
+- `set_int(key, value)`
+- `set_bool(key, value)`
+- `get_string_or(key, fallback)`
+- `ensure_object(key)`
+- `ensure_array(key)`
+- `merge_from(other, overwrite)`
+- `erase(key)`
+- `keys()`
+
+Example:
+
+``` cpp
+#include
+
+using namespace vix::json;
+
+int main()
+{
+ kvs obj;
+ obj.set_string("name", "Vix");
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+# 2) High-Level JSON
+
+Header:
+
+``` cpp
+#include
+```
+
+Powered by nlohmann::json.
+
+Namespace helpers:
+
+``` cpp
+vix::json
+```
+
+Core type:
+
+``` cpp
+Json
+```
+
+------------------------------------------------------------------------
+
+## Object Builder
+
+``` cpp
+#include
+
+using namespace vix::json;
+
+int main()
+{
+ auto j = o(
+ "name", "Vix",
+ "version", 1
+ );
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+## Array Builder
+
+``` cpp
+auto arr = a(1, 2, 3);
+```
+
+------------------------------------------------------------------------
+
+## kv initializer
+
+``` cpp
+auto j = kv({
+ {"a", 1},
+ {"b", true}
+});
+```
+
+------------------------------------------------------------------------
+
+## dumps
+
+Serialize with indentation:
+
+``` cpp
+std::string s = dumps(j, 2);
+```
+
+------------------------------------------------------------------------
+
+## loads
+
+Parse string:
+
+``` cpp
+auto j = loads(R"({"a":1})");
+```
+
+------------------------------------------------------------------------
+
+## File IO
+
+``` cpp
+dump_file("out.json", j, 2);
+auto j2 = load_file("out.json");
+```
+
+------------------------------------------------------------------------
+
+## jset / jget (Path Access)
+
+Mutate nested structures using path strings.
+
+``` cpp
+Json j = obj();
+
+jset(j, "user.profile.name", "Ada");
+
+if (auto v = jget(j, "user.profile.name"))
+{
+ // value exists
+}
+```
+
+------------------------------------------------------------------------
+
+# Design Notes
+
+Simple JSON:
+
+- Minimal overhead
+- Strong control
+- Useful for internal state and WebSocket payloads
+
+High-level JSON:
+
+- Expressive builders
+- API responses
+- Parsing and file operations
+
+The JSON API is explicit and deterministic.
+
diff --git a/docs/api/middleware.md b/docs/api/middleware.md
new file mode 100644
index 0000000..d28f95c
--- /dev/null
+++ b/docs/api/middleware.md
@@ -0,0 +1,227 @@
+# Middleware API
+
+This page documents the middleware system in Vix.
+
+Vix supports two middleware styles:
+
+1) Context-based middleware (recommended)
+2) Legacy HTTP middleware (Request/Response based)
+
+Both can be adapted and chained.
+
+------------------------------------------------------------------------
+
+# Headers
+
+Context middleware:
+
+``` cpp
+#include
+```
+
+Legacy middleware:
+
+``` cpp
+#include
+```
+
+------------------------------------------------------------------------
+
+# 1) Context Middleware (Recommended)
+
+Type:
+
+``` cpp
+vix::middleware::MiddlewareFn
+```
+
+Signature:
+
+``` cpp
+(Context& ctx, Next next)
+```
+
+------------------------------------------------------------------------
+
+## Minimal Example
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ vix::middleware::MiddlewareFn mw =
+ [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ // pre logic
+ next();
+ // post logic
+ };
+
+ app.use(mw);
+
+ app.get("/", [](Request&, Response& res)
+ {
+ res.send("Hello");
+ });
+
+ app.run(8080);
+}
+```
+
+------------------------------------------------------------------------
+
+# Registering Middleware
+
+## Global
+
+``` cpp
+app.use(mw);
+```
+
+Applies to all routes.
+
+------------------------------------------------------------------------
+
+## Prefix
+
+``` cpp
+app.use("/api/", mw);
+```
+
+Applies only to routes under `/api/`.
+
+------------------------------------------------------------------------
+
+## Exact Path
+
+``` cpp
+app.use_exact("/ping", mw);
+```
+
+Applies only to the exact path.
+
+------------------------------------------------------------------------
+
+# Chaining Middleware
+
+Multiple middleware can be chained:
+
+``` cpp
+auto chained = vix::middleware::chain(mw1, mw2, mw3);
+
+app.use(chained);
+```
+
+Execution order:
+
+- mw1 pre
+- mw2 pre
+- mw3 pre
+- handler
+- mw3 post
+- mw2 post
+- mw1 post
+
+------------------------------------------------------------------------
+
+# Request State Storage
+
+Context allows storing typed state per request.
+
+``` cpp
+ctx.emplace_state(42);
+
+int& value = ctx.state();
+```
+
+Safe access:
+
+``` cpp
+if (auto* v = ctx.try_state())
+{
+ // state exists
+}
+```
+
+------------------------------------------------------------------------
+
+# 2) Legacy HTTP Middleware
+
+Type:
+
+``` cpp
+vix::HttpMiddleware
+```
+
+Signature:
+
+``` cpp
+(Request&, Response&, Next)
+```
+
+Example:
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ HttpMiddleware mw =
+ [](Request& req, Response& res, auto next)
+ {
+ (void)req;
+ (void)res;
+ next();
+ };
+
+ app.use(mw);
+
+ app.get("/", [](Request&, Response& res)
+ {
+ res.send("Hello");
+ });
+
+ app.run(8080);
+}
+```
+
+------------------------------------------------------------------------
+
+# Adapters
+
+Adapt legacy to context:
+
+``` cpp
+auto adapted = vix::middleware::adapt(mw);
+app.use(adapted);
+```
+
+Adapt context to legacy:
+
+``` cpp
+auto adapted = vix::middleware::adapt_ctx(ctx_mw);
+app.use(adapted);
+```
+
+------------------------------------------------------------------------
+
+# Behavior Notes
+
+- Middleware executes in registration order.
+- If `next()` is not called, the chain stops.
+- Middleware can modify request state before handler execution.
+- Middleware should not block for long operations.
+
+The middleware system is explicit and composable by design.
+
diff --git a/docs/api/p2p.md b/docs/api/p2p.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/api/websocket.md b/docs/api/websocket.md
new file mode 100644
index 0000000..8590501
--- /dev/null
+++ b/docs/api/websocket.md
@@ -0,0 +1,203 @@
+# WebSocket API
+
+This page documents the WebSocket server API in Vix.
+
+It covers:
+
+- WebSocket server
+- Event hooks
+- Typed message protocol
+- Broadcast functions
+- Long polling bridge
+
+All examples are minimal and placed inside `main()`.
+
+------------------------------------------------------------------------
+
+# Server
+
+Header:
+
+``` cpp
+#include
+```
+
+Core type:
+
+``` cpp
+vix::websocket::Server
+```
+
+------------------------------------------------------------------------
+
+## Constructor
+
+``` cpp
+Server ws(cfg, executor);
+```
+
+Parameters:
+
+- `cfg` → configuration object
+- `executor` → thread pool executor
+
+------------------------------------------------------------------------
+
+# Minimal Standalone Example
+
+``` cpp
+#include
+#include
+#include
+
+int main()
+{
+ vix::config::Config cfg{"config.json"};
+
+ auto exec = vix::experimental::make_threadpool_executor(4, 8, 0);
+
+ vix::websocket::Server ws(cfg, std::move(exec));
+
+ ws.on_open([](auto& session) {
+ (void)session;
+ });
+
+ ws.on_typed_message([](auto& session,
+ const std::string& type,
+ const vix::json::kvs& payload)
+ {
+ (void)session;
+ (void)type;
+ (void)payload;
+ });
+
+ ws.listen_blocking();
+
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+# Event Hooks
+
+## on_open
+
+Called when a client connects.
+
+``` cpp
+ws.on_open([](auto& session) {
+ // session is active
+});
+```
+
+------------------------------------------------------------------------
+
+## on_close
+
+Called when a client disconnects.
+
+``` cpp
+ws.on_close([](auto& session) {
+ // cleanup
+});
+```
+
+------------------------------------------------------------------------
+
+## on_typed_message
+
+Called when a typed message is received.
+
+Signature:
+
+``` cpp
+(session, type, payload)
+```
+
+- `type` → string
+- `payload` → `vix::json::kvs`
+
+------------------------------------------------------------------------
+
+# Typed Message Protocol
+
+Expected message shape:
+
+``` json
+{
+ "type": "event.name",
+ "payload": { ... }
+}
+```
+
+Vix automatically parses and routes this to `on_typed_message`.
+
+------------------------------------------------------------------------
+
+# Broadcast
+
+## Broadcast to all
+
+``` cpp
+ws.broadcast_json("chat.message", {
+ "user", "Alice",
+ "text", "Hello"
+});
+```
+
+------------------------------------------------------------------------
+
+## Broadcast to room
+
+``` cpp
+ws.broadcast_room_json("room1", "chat.message", payload);
+```
+
+------------------------------------------------------------------------
+
+# Long Polling Bridge
+
+Header:
+
+``` cpp
+#include
+```
+
+Attach bridge:
+
+``` cpp
+ws.attach_long_polling_bridge(bridge);
+```
+
+Purpose:
+
+- Fallback when WebSocket is blocked
+- HTTP endpoints simulate WebSocket behavior
+
+------------------------------------------------------------------------
+
+# HTTP + WS Combined
+
+Use helper:
+
+``` cpp
+vix::serve_http_and_ws([](auto& app, auto& ws) {
+ // register HTTP routes
+ // register WebSocket handlers
+});
+```
+
+This creates a single runtime handling both protocols.
+
+------------------------------------------------------------------------
+
+# Notes
+
+- `listen_blocking()` blocks the thread.
+- WebSocket handlers should be short and non-blocking.
+- Use broadcast carefully in high-load scenarios.
+- Use room broadcasting for scalable chat systems.
+
+The WebSocket API is minimal by design.
+
diff --git a/docs/architecture.md b/docs/architecture.md
deleted file mode 100644
index 8316f49..0000000
--- a/docs/architecture.md
+++ /dev/null
@@ -1,117 +0,0 @@
-# Architecture — Vix.cpp
-
-Vix.cpp is organized as a **small, sharp core** with optional modules. You can consume modules independently or as an umbrella package.
-
----
-
-## High‑Level View
-
-```
-+----------------------+ +---------------------+
-| Your App | | CLI (vix) |
-| (routes, services) | | new/build/run |
-+----------+-----------+ +----------+----------+
- | |
- v v
-+----------------------+ +---------------------+
-| core |<---->| devtools |
-| App, Router, HTTP | | scripts, presets |
-+----+----+----+-------+ +---------------------+
- | | |
- | | +-------------------+
- | | |
- v v v
-+----+----+----+--------+ +------+-------+ +-------------------+
-| utils | json | | websocket | | orm |
-| Logger | builders | | (WIP) | | Repo/UoW, drivers |
-| UUID/Env | nlohmann | | | | MySQL/SQLite |
-+-----------+-----------+ +--------------+ +--------------------+
-```
-
-- **core** — HTTP server (Asio/Beast), router, request/response, status codes.
-- **utils** — Logger (sync/async), UUID, Time, Env, Validation helpers.
-- **json** — light wrappers/builders around _nlohmann/json_ for ergonomic responses.
-- **orm** — optional: Repository + Unit of Work, QueryBuilder, connection pool.
-- **websocket** — WIP: channels, rooms, backpressure.
-- **cli** — `vix new/build/run` to scaffold and operate projects.
-- **devtools** — local tooling, scripts, presets.
-
----
-
-## Core Components
-
-### `App`
-
-- Owns the HTTP server and route registry.
-- Methods: `get`, `post`, `put`, `del`, `use(middleware)`.
-- `run(port)` starts the event loop; graceful stop via signals.
-
-### Router
-
-- Templates routes with path parameters: `/users/{id}`.
-- Parameter extraction is type‑agnostic (string‑first, convert as needed).
-- Middleware hooks (logging/validation) composed per route or globally.
-
-### HTTP
-
-- Thin wrappers around Beast types.
-- `ResponseWrapper` exposes convenient `json(...)`, `status(...)`, `send(...)` helpers.
-- Intentional minimalism: no hidden thread‑locals or globals.
-
----
-
-## Concurrency Model
-
-- Event‑driven I/O based on Asio.
-- Compute offloading via a **thread pool** (configurable).
-- Lock boundaries minimized; prefer immutable data in hot paths.
-- Graceful shutdown coordinates listener, workers, and in‑flight requests.
-
----
-
-## Error Handling & Logging
-
-- Runtime errors bubble to a predictable handler in core.
-- Structured logs via `utils::Logger` (sync/async) with context (request_id/module).
-- Sanitizer‑friendly builds and optional static analysis (`clang-tidy`, `cppcheck`).
-
----
-
-## JSON Path
-
-- Input: `nlohmann::json` parsing recommended for request bodies.
-- Output: `Vix::json` builders (tokens/obj/array) for zero‑friction responses.
-- Avoids repetitive boilerplate while keeping conversions explicit.
-
----
-
-## ORM Integration (Optional)
-
-- Connection pooling, prepared statements, RAII transactions.
-- Repository/Unit‑of‑Work pattern reduces boilerplate and enforces consistency.
-- Can be used standalone (separate CMake target) or with the umbrella build.
-
----
-
-## Configuration
-
-- Simple JSON at `config/config.json` copied to build dir.
-- ENV helpers: `utils::env_str`, `env_int`, `env_bool` for overrides.
-- Prefer explicit constructor injection for services and repositories.
-
----
-
-## Build System
-
-- CMake ≥ 3.20, generator‑agnostic (Make/Ninja/VS).
-- Presets recommended for debug/asan/release.
-- `compile_commands.json` exported automatically for IDEs.
-
----
-
-## Roadmap Notes
-
-- WebSocket engine (channels/rooms/backpressure).
-- Middlewares: CORS presets, rate limiting, auth helpers.
-- Devtools: profiler hooks, trace exporters.
-- ORM: query planner and driver adapters.
diff --git a/docs/benchmarks.md b/docs/benchmarks.md
deleted file mode 100644
index d85c95f..0000000
--- a/docs/benchmarks.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# ⚡ Benchmarks (Updated — Dec 2025)
-
-All benchmarks were executed using **wrk**
-`8 threads`, `800 connections`, for **30 seconds**, on the same machine:
-**Ubuntu 24.04 — Intel Xeon — C++20 optimized build — Logging disabled**
-
-Results represent steady-state throughput on a simple `"OK"` endpoint.
-
----
-
-## 🚀 Requests per second
-
-| Framework | Requests/sec | Avg Latency | Transfer/sec |
-| ------------------------- | -------------------------- | --------------- | -------------- |
-| ⭐ **Vix.cpp (v1.10.6)** | **~98,942** _(pinned CPU)_ | **7.3–10.8 ms** | **~13.8 MB/s** |
-| **Vix.cpp (default run)** | 81,300 – 81,400 | 9.7–10.8 ms | ≈ 11.3 MB/s |
-| Go (Fiber) | 81,336 | 0.67 ms | 10.16 MB/s |
-| **Deno** | ~48,868 | 16.34 ms | ~6.99 MB/s |
-| Node.js (Fastify) | 4,220 | 16.00 ms | 0.97 MB/s |
-| PHP (Slim) | 2,804 | 16.87 ms | 0.49 MB/s |
-| Crow (C++) | 1,149 | 41.60 ms | 0.35 MB/s |
-| FastAPI (Python) | 752 | 63.71 ms | 0.11 MB/s |
-
-> 🔥 **New record:** When pinned to a single core (`taskset -c 2`)
-> Vix.cpp reaches **~99k req/s**, surpassing Go and matching the fastest C++ microframeworks.
-
----
-
-## 📝 Notes
-
-### ✔ Why Vix.cpp reaches Go-level performance
-
-- zero-cost abstractions
-- custom ThreadPool tuned for HTTP workloads
-- optimized HTTP pipeline
-- fast-path routing
-- Beast-based IO
-- minimal memory allocations
-- predictable threading model
-
----
-
-## 🦕 Deno benchmark (reference)
-
-```bash
-$ wrk -t8 -c800 -d30s --latency http://127.0.0.1:8000
-Requests/sec: 48,868.73
-```
-
-### ✔ Vix.cpp recommended benchmark mode
-
-When benchmarking from inside the Vix.cpp repository (using the built-in example):
-
-```bash
-cd ~/vixcpp/vix
-export VIX_LOG_LEVEL=critical
-export VIX_LOG_ASYNC=false
-
-# Run the optimized example server
-vix run example main
-```
-
-Then, in another terminal:
-
-```bash
-wrk -t8 -c800 -d30s --latency http://127.0.0.1:8080/bench
-```
-
-If you want CPU pinning for more stable results:
-
-```bash
-taskset -c 2 ./build/main
-wrk -t8 -c800 -d30s --latency http://127.0.0.1:8080/bench
-```
-
-#### 🏁 Result: ~98,942 req/s
-
-✔ Fast-path routing gives +1–3%
-
-## Use /fastbench to bypass RequestHandler overhead.
-
-## 🧠 Takeaway
-
-Vix.cpp provides **Go-level performance** with full C++ control and type safety.
-For deeper details, see [docs/architecture.md](./architecture.md) or run your own local tests.
diff --git a/docs/build.md b/docs/build.md
deleted file mode 100644
index f4403bb..0000000
--- a/docs/build.md
+++ /dev/null
@@ -1,185 +0,0 @@
-# Build & Packaging — Vix.cpp
-
-This page explains the different build configurations, debugging tools, and packaging options for **Vix.cpp**.
-
----
-
-## 🏗️ Build Modes
-
-Vix.cpp uses **CMake ≥ 3.20** and supports multiple build types:
-
-| Mode | Description | Flags |
-| ------------------ | -------------------------------------------------------------- | ----------------------------------- |
-| **Debug** | Includes debug symbols, no optimization. Best for development. | `-DCMAKE_BUILD_TYPE=Debug` |
-| **Release** | Optimized for performance. Default for production. | `-DCMAKE_BUILD_TYPE=Release` |
-| **RelWithDebInfo** | Mix of Release + debug symbols. | `-DCMAKE_BUILD_TYPE=RelWithDebInfo` |
-| **MinSizeRel** | Optimized for size. | `-DCMAKE_BUILD_TYPE=MinSizeRel` |
-
-Example:
-
-```bash
-cmake -S . -B build-rel -DCMAKE_BUILD_TYPE=Release
-cmake --build build-rel -j
-```
-
----
-
-## ⚙️ Sanitizers (ASan / UBSan)
-
-Enable runtime memory and undefined behavior checks:
-
-```bash
-cmake -S . -B build-asan -DCMAKE_BUILD_TYPE=Debug -DVIX_ENABLE_SANITIZERS=ON
-cmake --build build-asan -j
-```
-
-This automatically adds:
-
-```
--fsanitize=address,undefined -O1 -g -fno-omit-frame-pointer
-```
-
-Use in **Debug only** — disable for Release builds.
-
----
-
-## 🔍 Static Analysis
-
-Vix.cpp integrates with common static analysis tools.
-
-### Clang-Tidy
-
-```bash
-cmake -S . -B build -DVIX_ENABLE_CLANG_TIDY=ON
-cmake --build build -j
-```
-
-### Cppcheck
-
-```bash
-cmake -S . -B build -DVIX_ENABLE_CPPCHECK=ON
-```
-
----
-
-## 🧩 Link-Time Optimization (LTO)
-
-For higher performance, enable **LTO** in Release builds:
-
-```bash
-cmake -S . -B build-lto -DCMAKE_BUILD_TYPE=Release -DVIX_ENABLE_LTO=ON
-cmake --build build-lto -j
-```
-
-LTO reduces binary size and improves runtime performance by optimizing across translation units.
-
----
-
-## 🧪 Code Coverage (Developers)
-
-For measuring test coverage in Debug builds:
-
-```bash
-cmake -S . -B build-cov -DCMAKE_BUILD_TYPE=Debug -DVIX_ENABLE_COVERAGE=ON
-cmake --build build-cov -j
-```
-
-Run tests, then use `gcov`, `lcov`, or `llvm-cov` to generate reports.
-
----
-
-## 🧱 Packaging / Installation
-
-Build and install all umbrella modules:
-
-```bash
-cmake -S . -B build-pkg -DCMAKE_BUILD_TYPE=Release -DVIX_ENABLE_INSTALL=ON
-cmake --build build-pkg -j
-sudo cmake --install build-pkg --prefix /usr/local
-```
-
-Inspect installation layout:
-
-```bash
-cmake --install build-pkg --prefix /usr/local --dry-run
-```
-
-To uninstall manually, remove installed files or rebuild with a different prefix (e.g., `/opt/vixcpp`).
-
----
-
-## 🧠 Developer Workflow
-
-- Use **Ninja** for faster incremental builds:
- ```bash
- cmake -G Ninja -S . -B build
- ```
-- Regenerate submodules:
- ```bash
- git submodule update --remote --merge
- ```
-- Export compile commands for IDEs:
- ```bash
- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- ```
-
----
-
-## 🧩 Example Preset Configurations
-
-You can define presets in `CMakePresets.json`:
-
-```json
-{
- "version": 3,
- "configurePresets": [
- {
- "name": "release",
- "generator": "Ninja",
- "binaryDir": "build-rel",
- "cacheVariables": {
- "CMAKE_BUILD_TYPE": "Release",
- "VIX_ENABLE_LTO": "ON",
- "VIX_ENABLE_INSTALL": "ON"
- }
- },
- {
- "name": "debug-asan",
- "generator": "Ninja",
- "binaryDir": "build-asan",
- "cacheVariables": {
- "CMAKE_BUILD_TYPE": "Debug",
- "VIX_ENABLE_SANITIZERS": "ON"
- }
- }
- ]
-}
-```
-
-Then run:
-
-```bash
-cmake --preset release
-cmake --build --preset release
-```
-
----
-
-## 🧰 Troubleshooting Build Issues
-
-| Problem | Cause | Solution |
-| --------------------------------- | -------------------- | -------------------------------------------------- |
-| `nlohmann/json.hpp not found` | Missing dependency | Install with `sudo apt install nlohmann-json3-dev` |
-| `undefined reference to spdlog::` | Missing spdlog lib | Install with `sudo apt install libspdlog-dev` |
-| `fatal error: boost/asio.hpp` | Boost not installed | `sudo apt install libboost-all-dev` |
-| `cmake: invalid preset` | Missing CMake ≥ 3.20 | Upgrade CMake via `pip install cmake --upgrade` |
-
----
-
-## ✅ Next Steps
-
-- [Quick Start](./quick-start.md)
-- [Installation](./installation.md)
-- [Benchmarks](./benchmarks.md)
-- [CMake Options](./options.md)
-- [Architecture](./architecture.md)
diff --git a/docs/examples/api-key.md b/docs/examples/api-key.md
new file mode 100644
index 0000000..2643529
--- /dev/null
+++ b/docs/examples/api-key.md
@@ -0,0 +1,197 @@
+# API Key Middleware Guide (Vix.cpp) — Beginner Friendly
+
+## What is an API Key?
+
+An API key is a simple secret string sent by the client to prove it is allowed to access a protected endpoint.
+
+It is NOT as powerful as JWT, but it is:
+
+- Simple
+- Fast
+- Perfect for internal APIs or microservices
+
+---
+
+# How API Key Works in Vix.cpp
+
+Client sends:
+
+Header:
+```bash
+ x-api-key: secret
+```
+OR
+
+Query param:
+```bash
+ ?api_key=secret
+```
+Middleware checks:
+- Is key present?
+- Is key valid?
+- If yes → continue
+- If no → 401 or 403
+
+---
+
+# Minimal Example
+
+File: `api_key_app_simple.cpp`
+
+```cpp
+App app;
+
+// Protect only /secure
+app.use("/secure", middleware::app::api_key_dev("secret"));
+
+app.get("/secure", [](Request& req, Response& res)
+{
+ auto& key = req.state();
+
+ res.json({
+ "ok", true,
+ "api_key", key.value
+ });
+});
+```
+
+# Run
+
+```bash
+vix run api_key_app_simple.cpp
+```
+
+Server runs on:
+```bash
+http://localhost:8080
+```
+
+# Test With curl
+
+## 1 Missing key
+
+```bash
+curl -i http://localhost:8080/secure
+```
+
+Result:
+401 Unauthorized
+
+---
+
+## 2) Invalid key
+
+```bash
+curl -i -H "x-api-key: wrong" http://localhost:8080/secure
+```
+
+Result:
+403 Forbidden
+
+---
+
+## 3) Valid key (Header)
+
+```bash
+curl -i -H "x-api-key: secret" http://localhost:8080/secure
+```
+
+Result:
+200 OK
+
+---
+
+## 4) Valid key (Query param)
+
+```bash
+curl -i "http://localhost:8080/secure?api_key=secret"
+```
+
+Result:
+200 OK
+
+---
+
+# What Happens Internally?
+
+If key is valid:
+```cpp
+req.state().value
+```
+contains:
+
+"secret"
+
+You can use it inside your route.
+
+---
+
+# When Should You Use API Key?
+
+Good for:
+
+- Internal service-to-service auth
+- Dev environments
+- Small private APIs
+
+Not ideal for:
+
+- Complex user systems
+- Role-based permissions
+- Public user authentication
+
+---
+
+# Full Working Example
+
+```cpp
+#include
+#include
+
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Protect /secure
+ app.use("/secure", middleware::app::api_key_dev("secret"));
+
+ // Public route
+ app.get("/", [](Request&, Response& res)
+ {
+ res.send("API Key example: /secure requires x-api-key: secret");
+ });
+
+ // Protected route
+ app.get("/secure", [](Request& req, Response& res)
+ {
+ auto& key = req.state();
+
+ res.json({
+ "ok", true,
+ "api_key", key.value
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+# Summary
+
+API Key = Simple shared secret
+
+Very fast
+Very lightweight
+Very easy to understand
+
+Vix.cpp keeps it clean and minimal.
+
+
diff --git a/docs/examples/async.md b/docs/examples/async.md
new file mode 100644
index 0000000..4bba768
--- /dev/null
+++ b/docs/examples/async.md
@@ -0,0 +1,209 @@
+# Async Worker (Beginner Guide)
+
+Welcome 👋
+
+This page explains how to use Vix async in a simple and practical way.
+If you are new to coroutines or async C++, this guide is for you.
+
+------------------------------------------------------------------------
+
+## What is an Async Worker?
+
+An async worker allows your program to:
+
+- Run tasks without blocking the main thread
+- Wait for timers without freezing
+- Run heavy CPU work in background threads
+- Stop cleanly when receiving Ctrl+C
+
+In simple words:
+
+Async = Do not block.\
+Worker = Do work safely in background.
+
+------------------------------------------------------------------------
+
+# 1️⃣ Minimal Example -- Hello Async
+
+This is the smallest possible example.
+
+``` cpp
+#include
+#include
+#include
+
+using vix::async::core::io_context;
+using vix::async::core::task;
+
+task app(io_context& ctx)
+{
+ std::cout << "Hello async world!\n";
+ ctx.stop();
+ co_return;
+}
+
+int main()
+{
+ io_context ctx;
+
+ auto t = app(ctx);
+ ctx.post(t.handle());
+ ctx.run();
+
+ return 0;
+}
+```
+
+What happens here?
+
+- io_context = async runtime
+- task\<\> = coroutine function
+- ctx.post() = schedule the task
+- ctx.run() = start the event loop
+- ctx.stop() = stop the runtime
+
+------------------------------------------------------------------------
+
+# 2️⃣ Waiting Without Blocking (Timer)
+
+This example waits 1 second without freezing the program.
+
+``` cpp
+#include
+#include
+
+#include
+#include
+#include
+
+using vix::async::core::io_context;
+using vix::async::core::task;
+
+task app(io_context& ctx)
+{
+ std::cout << "Waiting 1 second...\n";
+
+ co_await ctx.timers().sleep_for(std::chrono::seconds(1));
+
+ std::cout << "Done!\n";
+ ctx.stop();
+ co_return;
+}
+
+int main()
+{
+ io_context ctx;
+ auto t = app(ctx);
+ ctx.post(t.handle());
+ ctx.run();
+}
+```
+
+Important:
+
+sleep_for() does NOT block the event loop thread.
+
+------------------------------------------------------------------------
+
+# 3️⃣ Running Heavy Work in Background (CPU Pool)
+
+Never block your event loop with heavy computation.
+
+Instead:
+
+``` cpp
+#include
+#include
+#include
+#include
+
+using vix::async::core::io_context;
+using vix::async::core::task;
+
+task app(io_context& ctx)
+{
+ int result = co_await ctx.cpu_pool().submit([] {
+ int sum = 0;
+ for (int i = 0; i < 100000; ++i)
+ sum += i;
+ return sum;
+ });
+
+ std::cout << "Result: " << result << "\n";
+
+ ctx.stop();
+ co_return;
+}
+
+int main()
+{
+ io_context ctx;
+ auto t = app(ctx);
+ ctx.post(t.handle());
+ ctx.run();
+}
+```
+
+Here:
+
+- The heavy loop runs on a worker thread
+- The event loop stays responsive
+
+------------------------------------------------------------------------
+
+# 4️⃣ Clean Shutdown (Ctrl+C)
+
+Production programs must stop safely.
+
+``` cpp
+#include
+#include
+
+#include
+#include
+#include
+
+using vix::async::core::io_context;
+using vix::async::core::task;
+
+task app(io_context& ctx)
+{
+ auto& sig = ctx.signals();
+
+ sig.add(SIGINT);
+ sig.add(SIGTERM);
+
+ std::cout << "Press Ctrl+C to stop\n";
+
+ sig.on_signal([&](int){
+ std::cout << "Stopping...\n";
+ ctx.stop();
+ });
+
+ co_await sig.async_wait();
+ co_return;
+}
+
+int main()
+{
+ io_context ctx;
+ auto t = app(ctx);
+ ctx.post(t.handle());
+ ctx.run();
+}
+```
+
+------------------------------------------------------------------------
+
+# Final Notes for Beginners
+
+✔ Always use cpu_pool() for heavy work\
+✔ Use timers instead of std::this_thread::sleep_for()\
+✔ Handle SIGINT for production apps\
+✔ Keep event loop clean and responsive
+
+------------------------------------------------------------------------
+
+Generated on 2026-02-17\
+Vix Async Beginner Guide
+
diff --git a/docs/examples/auth.md b/docs/examples/auth.md
new file mode 100644
index 0000000..f5acb0a
--- /dev/null
+++ b/docs/examples/auth.md
@@ -0,0 +1,343 @@
+# Auth and Middleware (Minimal Patterns)
+
+This page shows minimal auth and middleware patterns in Vix.cpp.
+
+Each section is: - one concept - one minimal `main()` - a quick curl
+test
+
+------------------------------------------------------------------------
+
+## 1) API key middleware (protect one route)
+
+A public route plus a secure route that requires `x-api-key`.
+
+``` cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/public", [](Request&, Response& res){
+ res.json({ "ok", true, "scope", "public" });
+ });
+
+ // Install API key middleware only on this prefix
+ middleware::app::install(app, "/secure/", middleware::app::api_key_dev("dev_key_123"));
+
+ app.get("/secure/whoami", [](Request&, Response& res){
+ res.json({ "ok", true, "scope", "secure", "message", "API key accepted" });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://127.0.0.1:8080/public
+curl -i http://127.0.0.1:8080/secure/whoami
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/secure/whoami
+```
+
+------------------------------------------------------------------------
+
+## 2) Prefix protection (protect all /api routes)
+
+Everything under `/api/` is protected.
+
+``` cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ middleware::app::install(app, "/api/", middleware::app::api_key_dev("dev_key_123"));
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({ "ok", true, "pong", true });
+ });
+
+ app.get("/api/users", [](Request&, Response& res){
+ res.json({ "ok", true, "data", json::array({ "u1", "u2" }) });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://127.0.0.1:8080/api/ping
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/api/ping
+```
+
+------------------------------------------------------------------------
+
+## 3) Custom middleware (context style + RequestState)
+
+This shows how to store data in RequestState and read it in the handler.
+
+``` cpp
+#include
+#include
+#include
+#include
+using namespace vix;
+
+struct RequestId{
+ std::string value;
+};
+
+static long long now_ms(){
+ using namespace std::chrono;
+ return (long long)time_point_cast(system_clock::now()).time_since_epoch().count();
+}
+
+static vix::middleware::MiddlewareFn mw_request_id(){
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ RequestId rid;
+ rid.value = std::to_string(now_ms());
+
+ ctx.req().emplace_state(rid);
+ ctx.res().header("x-request-id", rid.value);
+
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ // Adapt context middleware into app middleware
+ app.use(vix::middleware::app::adapt_ctx(mw_request_id()));
+
+ app.get("/who", [](Request& req, Response& res){
+ const auto rid = req.state().value;
+ res.json({ "ok", true, "request_id", rid });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://127.0.0.1:8080/who
+```
+
+------------------------------------------------------------------------
+
+## 4) Role gating (fake auth + admin only)
+
+This is a minimal RBAC-style gate using headers for the demo.
+
+``` cpp
+#include
+#include
+#include
+
+using namespace vix;
+namespace J = vix::json;
+
+struct AuthInfo{
+ bool authed{false};
+ std::string subject;
+ std::string role;
+};
+
+static vix::middleware::MiddlewareFn mw_fake_auth(){
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ AuthInfo a;
+ const std::string user = ctx.req().header("x-user");
+ const std::string role = ctx.req().header("x-role");
+
+ if (!user.empty())
+ {
+ a.authed = true;
+ a.subject = user;
+ a.role = role.empty() ? "user" : role;
+ }
+
+ ctx.req().emplace_state(a);
+ next();
+ };
+}
+
+static vix::middleware::MiddlewareFn mw_require_admin(){
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next){
+ if (!ctx.req().has_state_type() || !ctx.req().state().authed)
+ {
+ ctx.res().status(401).json(J::obj({ "ok", false, "error", "unauthorized" }));
+ return;
+ }
+
+ if (ctx.req().state().role != "admin")
+ {
+ ctx.res().status(403).json(J::obj({ "ok", false, "error", "forbidden", "hint", "admin required" }));
+ return;
+ }
+
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ app.use(vix::middleware::app::adapt_ctx(mw_fake_auth()));
+
+ // Install admin guard only under /admin/
+ vix::middleware::app::install(app, "/admin/", vix::middleware::app::adapt_ctx(mw_require_admin()));
+
+ app.get("/admin/stats", [](Request& req, Response& res)
+ {
+ const auto& a = req.state();
+ res.json({ "ok", true, "admin", true, "subject", a.subject });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://127.0.0.1:8080/admin/stats
+curl -i -H "x-user: gaspard" http://127.0.0.1:8080/admin/stats
+curl -i -H "x-user: gaspard" -H "x-role: admin" http://127.0.0.1:8080/admin/stats
+```
+
+------------------------------------------------------------------------
+
+## 5) Legacy HttpMiddleware style (adapt)
+
+If you have an older middleware signature `(Request, Response, next)`
+you can adapt it.
+
+``` cpp
+#include
+#include
+#include
+
+using namespace vix;
+namespace J = vix::json;
+
+static vix::middleware::HttpMiddleware require_header(std::string header, std::string expected)
+{
+ return [header = std::move(header), expected = std::move(expected)](Request& req, Response& res, vix::middleware::Next next)
+ {
+ const std::string got = req.header(header);
+ if (got != expected)
+ {
+ res.status(401).json(J::obj({
+ "ok", false,
+ "error", "unauthorized",
+ "required_header", header
+ }));
+ return;
+ }
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ vix::middleware::app::install_exact(app, "/api/ping", vix::middleware::app::adapt(require_header("x-demo", "1")));
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({ "ok", true, "pong", true });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://127.0.0.1:8080/api/ping
+curl -i -H "x-demo: 1" http://127.0.0.1:8080/api/ping
+```
+
+------------------------------------------------------------------------
+
+## 6) Chaining middleware
+
+Apply multiple middlewares on the same prefix.
+
+``` cpp
+#include
+#include
+#include
+
+using namespace vix;
+
+static vix::middleware::MiddlewareFn mw_mark()
+{
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ ctx.res().header("x-mw", "on");
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ // Chain: api key then a custom marker middleware
+ vix::middleware::app::install(
+ app,
+ "/secure/",
+ vix::middleware::app::chain(
+ vix::middleware::app::api_key_dev("dev_key_123"),
+ vix::middleware::app::adapt_ctx(mw_mark())
+ )
+ );
+
+ app.get("/secure/hello", [](Request&, Response& res)
+ {
+ res.json({ "ok", true, "message", "Hello secure" });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/secure/hello
+```
+
+------------------------------------------------------------------------
+
+## What this teaches
+
+- Prefix install: protect a group of routes
+- Exact install: protect one route
+- Context middleware: state and headers
+- Legacy middleware adaptation
+- Basic RBAC-style gating
+- Middleware chaining
diff --git a/docs/examples/batch-insert-tx.md b/docs/examples/batch-insert-tx.md
new file mode 100644
index 0000000..bb4e4ee
--- /dev/null
+++ b/docs/examples/batch-insert-tx.md
@@ -0,0 +1,268 @@
+# ORM Example Guide: Batch Insert + Transaction (MySQL)
+
+This guide explains the `batch_insert_tx` example step by step.
+
+Goal: - Connect to MySQL using the ORM connection pool - Run multiple
+INSERT operations efficiently - Wrap everything inside a transaction
+(commit or rollback)
+
+## 1. What this example demonstrates
+
+This example shows how to:
+
+- Create a MySQL driver factory with `make_mysql_factory()`
+- Build a `ConnectionPool` with `PoolConfig`
+- Warm up the pool so it opens connections early
+- Use `Transaction` (RAII) for safe commits and automatic rollbacks
+- Use prepared statements with parameter binding
+- Insert multiple rows inside one transaction
+
+## 2. Full Example Code
+
+``` cpp
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace vix::orm;
+
+int main(int argc, char **argv)
+{
+ const std::string host = (argc > 1 ? argv[1] : "tcp://127.0.0.1:3306");
+ const std::string user = (argc > 2 ? argv[2] : "root");
+ const std::string pass = (argc > 3 ? argv[3] : "");
+ const std::string db = (argc > 4 ? argv[4] : "vixdb");
+
+ try
+ {
+ // DB factory (MySQL driver)
+ auto factory = make_mysql_factory(host, user, pass, db);
+
+ PoolConfig cfg;
+ cfg.min = 1;
+ cfg.max = 8;
+
+ ConnectionPool pool{factory, cfg};
+ pool.warmup();
+
+ // Transaction (RAII rollback if not committed)
+ Transaction tx(pool);
+ auto &c = tx.conn();
+
+ auto st = c.prepare("INSERT INTO users(name,email,age) VALUES(?,?,?)");
+
+ struct Row
+ {
+ const char *name;
+ const char *email;
+ int age;
+ };
+
+ const std::vector rows = {
+ {"Zoe", "zoe@example.com", 23},
+ {"Mina", "mina@example.com", 31},
+ {"Omar", "omar@example.com", 35},
+ };
+
+ std::uint64_t total = 0;
+ for (const auto &r : rows)
+ {
+ st->bind(1, r.name);
+ st->bind(2, r.email);
+ st->bind(3, r.age);
+ total += st->exec();
+ }
+
+ tx.commit();
+ std::cout << "[OK] inserted rows = " << total << "\n";
+ return 0;
+ }
+ catch (const DBError &e)
+ {
+ std::cerr << "[DBError] " << e.what() << "\n";
+ return 1;
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "[ERR] " << e.what() << "\n";
+ return 1;
+ }
+}
+```
+
+## 3. Step by Step Explanation
+
+### 3.1 CLI arguments (connection info)
+
+``` cpp
+const std::string host = (argc > 1 ? argv[1] : "tcp://127.0.0.1:3306");
+const std::string user = (argc > 2 ? argv[2] : "root");
+const std::string pass = (argc > 3 ? argv[3] : "");
+const std::string db = (argc > 4 ? argv[4] : "vixdb");
+```
+
+This allows running the same binary with different databases without
+editing code.
+
+Example:
+
+``` bash
+./batch_insert_tx tcp://127.0.0.1:3306 root "" vixdb
+```
+
+### 3.2 Create the MySQL driver factory
+
+``` cpp
+auto factory = make_mysql_factory(host, user, pass, db);
+```
+
+The factory knows how to create new MySQL connections. The pool will use
+this factory when it needs more connections.
+
+### 3.3 Configure and create the connection pool
+
+``` cpp
+PoolConfig cfg;
+cfg.min = 1;
+cfg.max = 8;
+
+ConnectionPool pool{factory, cfg};
+pool.warmup();
+```
+
+- `min` is the minimum number of connections kept ready.
+- `max` is the maximum number of connections allowed.
+- `warmup()` opens the initial connections early, so the first query
+ is not slow.
+
+Production tip: - Warmup is useful for APIs to avoid a slow first
+request.
+
+### 3.4 Start a transaction (RAII)
+
+``` cpp
+Transaction tx(pool);
+auto &c = tx.conn();
+```
+
+This creates a transaction using one connection acquired from the pool.
+
+RAII rule: - If `tx.commit()` is not called, rollback happens
+automatically.
+
+### 3.5 Prepare the insert statement once
+
+``` cpp
+auto st = c.prepare("INSERT INTO users(name,email,age) VALUES(?,?,?)");
+```
+
+Prepared statements: - Improve performance (parse/plan once) - Avoid SQL
+injection - Allow safe binding
+
+### 3.6 Define rows to insert
+
+``` cpp
+struct Row { const char *name; const char *email; int age; };
+```
+
+Then a vector of rows:
+
+``` cpp
+const std::vector rows = {
+ {"Zoe", "zoe@example.com", 23},
+ {"Mina", "mina@example.com", 31},
+ {"Omar", "omar@example.com", 35},
+};
+```
+
+### 3.7 Bind parameters and execute in a loop
+
+``` cpp
+for (const auto &r : rows)
+{
+ st->bind(1, r.name);
+ st->bind(2, r.email);
+ st->bind(3, r.age);
+ total += st->exec();
+}
+```
+
+Binding rules: - Indexes start at 1 - Types are converted safely - The
+same prepared statement is reused for every row
+
+Note: - This is not a multi-row SQL insert. - It is still fast because
+the statement is prepared once and executed multiple times in one
+transaction.
+
+### 3.8 Commit
+
+``` cpp
+tx.commit();
+```
+
+Without commit: - rollback happens automatically - rows are not inserted
+
+With commit: - all rows become visible and durable
+
+## 4. Required SQL Table
+
+This example expects a `users` table with:
+
+- name
+- email
+- age
+
+Example schema:
+
+``` sql
+CREATE TABLE IF NOT EXISTS users (
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL,
+ age INT NOT NULL
+);
+```
+
+## 5. Error Handling
+
+``` cpp
+catch (const DBError &e)
+{
+ std::cerr << "[DBError] " << e.what() << "\n";
+}
+```
+
+- `DBError` is used for database driver / SQL errors.
+- A second catch handles other exceptions.
+
+Production tip: - Log DBError message internally - Return generic
+messages to HTTP clients
+
+## 6. Production Notes
+
+Use this pattern when:
+
+- You need to insert many rows
+- You want atomic behavior
+- You want speed and safety
+
+Best practices:
+
+- Keep the transaction short
+- Avoid external API calls inside a transaction
+- Use pool warmup at startup
+- Tune `cfg.max` using load tests
+
+## Summary
+
+You learned:
+
+- How to configure a MySQL pool with Vix ORM
+- How to batch insert rows efficiently
+- How to use RAII transactions for safety
+- How to bind parameters with prepared statements
+- How to handle database exceptions
+
diff --git a/docs/examples/body-limit.md b/docs/examples/body-limit.md
new file mode 100644
index 0000000..07cc128
--- /dev/null
+++ b/docs/examples/body-limit.md
@@ -0,0 +1,201 @@
+# Body Limit (Beginner Guide)
+
+Welcome 👋\
+This page explains how to use the **body limit middleware** in Vix.cpp.
+
+Body limits protect your server from:
+
+- very large requests (accidental or malicious)
+- memory pressure (huge JSON uploads)
+- slow uploads (DoS patterns)
+- endpoints that should never accept big bodies
+
+When the request body is too large, Vix returns:
+
+- **413 Payload Too Large**
+
+## What does "body limit" mean?
+
+It means: **do not accept requests bigger than N bytes**.
+
+Example: if you set `max_bytes = 32`:
+
+- 0..32 bytes is allowed
+- 33+ bytes is rejected with 413
+
+## 1) Minimal example
+
+This server:
+
+- keeps `/` public
+- limits `/api/*` requests to **32 bytes**
+- lets GET pass (default behavior)
+- demonstrates a strict route that rejects chunked uploads
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+static void register_routes(App &app)
+{
+ app.get("/", [](Request &, Response &res)
+ { res.send("body_limit example: /api/ping, /api/echo, /api/strict"); });
+
+ app.get("/api/ping", [](Request &, Response &res)
+ { res.json({"ok", true, "msg", "pong"}); });
+
+ app.post("/api/echo", [](Request &req, Response &res)
+ { res.json({"ok", true,
+ "bytes", static_cast(req.body().size()),
+ "content_type", req.header("content-type")}); });
+
+ app.post("/api/strict", [](Request &req, Response &res)
+ { res.json({"ok", true,
+ "msg", "strict accepted",
+ "bytes", static_cast(req.body().size())}); });
+}
+
+int main()
+{
+ App app;
+
+ // /api: max 32 bytes (demo), chunked allowed
+ app.use("/api", middleware::app::body_limit_dev(
+ 32, // max_bytes
+ false, // apply_to_get
+ true // allow_chunked
+ ));
+
+ // /api/strict: max 32 bytes, chunked NOT allowed
+ app.use("/api/strict", middleware::app::body_limit_dev(
+ 32, // max_bytes
+ false, // apply_to_get
+ false // allow_chunked (strict)
+ ));
+
+ register_routes(app);
+
+ app.run(8080);
+ return 0;
+}
+```
+
+## 2) Test with curl
+
+Run:
+
+``` bash
+vix run body_limit_app.cpp
+```
+
+### Small body (OK)
+
+``` bash
+curl -i -X POST http://localhost:8080/api/echo -H "Content-Type: text/plain" --data "hello"
+```
+
+### Large body (413 Payload Too Large)
+
+``` bash
+python3 - <<'PY'
+import requests
+print(requests.post("http://localhost:8080/api/echo", data="x"*64).status_code)
+PY
+```
+
+### GET is ignored by default
+
+``` bash
+curl -i http://localhost:8080/api/ping
+```
+
+### Strict mode: reject chunked bodies
+
+This simulates a request with `Transfer-Encoding: chunked` (no
+Content-Length).\
+If `allow_chunked=false`, the server returns **411 Length Required**.
+
+``` bash
+curl -i -X POST http://localhost:8080/api/strict -H "Transfer-Encoding: chunked" -H "Content-Type: text/plain" --data "hello"
+```
+
+## 3) A safer production preset: only limit write methods
+
+Usually, you only want body limits on:
+
+- POST
+- PUT
+- PATCH
+
+Vix provides an alias for that:
+
+``` cpp
+app.use("/", middleware::app::body_limit_write_dev(16));
+```
+
+Meaning:
+
+- GET is not limited
+- only write methods are limited to 16 bytes
+
+This is perfect for:
+
+- login endpoints
+- webhook endpoints
+- small JSON APIs
+- protecting uploads unless you explicitly allow them
+
+## 4) Conditional body limit with `should_apply` (advanced but useful)
+
+Sometimes you want to limit only some paths.
+
+Example idea:
+
+- allow unlimited `/health` and `/api/ping`
+- limit `/upload` and `/api/*`
+
+You can do it using the `should_apply` callback in `body_limit_dev()`.
+
+``` cpp
+app.use("/", middleware::app::body_limit_dev(
+ 16, // max_bytes
+ false, // apply_to_get
+ true, // allow_chunked
+ [](const vix::middleware::Context& ctx){
+ const auto m = ctx.req().method();
+ if (m != "POST" && m != "PUT" && m != "PATCH")
+ return false;
+
+ const auto p = ctx.req().path();
+ return (p == "/upload" || p.rfind("/api/", 0) == 0);
+ }
+));
+```
+
+If you're a beginner, you can skip this section and use
+`body_limit_write_dev()`.
+
+## Common beginner mistakes
+
+1) Setting the limit too low\
+ If you limit to 32 bytes but your JSON request is 200 bytes,
+ everything fails.
+
+2) Forgetting chunked uploads exist\
+ Some clients stream data. If you want strict enforcement, set
+ `allow_chunked=false`.
+
+3) Applying to GET by accident\
+ Usually GET has no body. Keep `apply_to_get=false` unless you really
+ need it.
+
+## Summary
+
+- `body_limit_dev(max_bytes, apply_to_get, allow_chunked)` is the main
+ preset
+- For most apps, use `body_limit_write_dev(max_bytes)`
+- Too large body -\> 413
+- Strict mode with `allow_chunked=false` can return 411
+
diff --git a/docs/examples/caching.md b/docs/examples/caching.md
new file mode 100644
index 0000000..84e1a5a
--- /dev/null
+++ b/docs/examples/caching.md
@@ -0,0 +1,214 @@
+# HTTP Caching Guide (Vix.cpp) — Beginner Friendly
+
+Caching means: **save a response**, then reuse it for the next request.
+
+This makes your API:
+
+- Faster
+- Cheaper (less CPU)
+- More scalable
+
+In this guide, we cache **GET** responses under `/api/*`.
+
+---
+
+## What gets cached?
+
+Usually only:
+
+- GET requests
+- Safe endpoints (no user-specific secrets unless you vary by headers)
+
+You typically do NOT cache:
+
+- POST
+- PUT
+- PATCH
+- DELETE
+
+---
+
+## Minimal Caching Example
+
+This caches GET `/api/*` for 30 seconds:
+
+```cpp
+App app;
+
+app.use("/api/", middleware::app::http_cache({
+ .ttl_ms = 30'000,
+ .allow_bypass = true,
+ .bypass_header = "x-vix-cache",
+ .bypass_value = "bypass",
+}));
+
+app.get("/api/users", [](Request&, Response& res){
+ res.text("users from origin");
+});
+
+app.run(8080);
+```
+
+---
+
+## Run
+
+```bash
+vix run examples/http_cache_app_simple.cpp
+```
+
+---
+
+## Test
+
+### 1) First request = MISS (origin)
+
+```bash
+curl -i http://localhost:8080/api/users
+```
+
+### 2) Second request = HIT (cached)
+
+```bash
+curl -i http://localhost:8080/api/users
+```
+
+### 3) Force origin (bypass)
+
+```bash
+curl -i -H "x-vix-cache: bypass" http://localhost:8080/api/users
+```
+
+---
+
+## Debug Header
+
+If you enable debug headers:
+
+```cpp
+.add_debug_header = true,
+.debug_header = "x-vix-cache-status",
+```
+
+You will see:
+
+- MISS
+- HIT
+- BYPASS
+
+Example:
+
+```bash
+curl -i http://localhost:8080/api/users
+```
+
+Look for:
+
+x-vix-cache-status: HIT
+
+---
+
+## Vary Headers (different cache per language)
+
+If you return different content depending on headers, you must vary the cache key:
+
+Example: `Accept-Language`
+
+```cpp
+app.use("/api/", middleware::app::http_cache({
+ .ttl_ms = 30'000,
+ .vary_headers = {"accept-language"},
+ .add_debug_header = true,
+ .debug_header = "x-vix-cache-status",
+}));
+```
+
+Test:
+
+```bash
+curl -i -H "Accept-Language: fr" http://localhost:8080/api/users
+curl -i -H "Accept-Language: en" http://localhost:8080/api/users
+```
+
+These should be **two separate cache entries**.
+
+---
+
+## Custom Cache Injection (advanced but useful)
+
+Sometimes you want to inject your own cache instance.
+
+Example:
+
+- MemoryStore
+- Custom eviction policy
+- Shared cache between middlewares
+
+```cpp
+auto cache = middleware::app::make_default_cache({
+ .ttl_ms = 30'000,
+});
+
+app.use("/api/", middleware::app::http_cache_mw({
+ .prefix = "/api/",
+ .only_get = true,
+ .ttl_ms = 30'000,
+ .cache = cache,
+ .add_debug_header = true,
+ .debug_header = "x-vix-cache-status",
+}));
+```
+
+---
+
+# Complete Example (copy-paste)
+
+This is a full working file you can run.
+
+Save as: `http_cache_app_simple.cpp`
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+static void register_routes(App& app)
+{
+ app.get("/", [](Request&, Response& res)
+ {
+ res.text("home (not cached)");
+ });
+
+ app.get("/api/users", [](Request&, Response& res)
+ {
+ res.text("users from origin");
+ });
+}
+
+int main()
+{
+ App app;
+
+ // Cache GET requests under /api/*
+ app.use("/api/", middleware::app::http_cache({
+ .ttl_ms = 30'000,
+ .allow_bypass = true,
+ .bypass_header = "x-vix-cache",
+ .bypass_value = "bypass",
+ }));
+
+ register_routes(app);
+
+ app.run(8080);
+ return 0;
+}
+```
+
+## Run
+
+```bash
+vix run http_cache_app_simple.cpp
+```
+
+
diff --git a/docs/examples/compression.md b/docs/examples/compression.md
new file mode 100644
index 0000000..5367f87
--- /dev/null
+++ b/docs/examples/compression.md
@@ -0,0 +1,177 @@
+# Compression Middleware Guide
+
+## What is HTTP Compression?
+
+Compression reduces the size of HTTP responses before sending them to the client.
+
+Benefits:
+
+- Faster network transfer
+- Lower bandwidth usage
+- Better performance on mobile or slow connections
+
+In Vix.cpp, compression is middleware-based and automatic.
+
+---
+
+## How Compression Works
+
+1. Client sends:
+ Accept-Encoding: gzip, br
+
+2. Server checks:
+ - Is compression enabled?
+ - Is response size >= min_size?
+ - Does client support compression?
+
+3. If yes:
+ - Response is compressed
+ - Vary header is added (if enabled)
+
+---
+
+## Minimal Example
+
+```cpp
+App app;
+
+auto mw = vix::middleware::app::adapt_ctx(
+ vix::middleware::performance::compression({
+ .min_size = 8,
+ .add_vary = true,
+ .enabled = true,
+ }));
+
+app.use(std::move(mw));
+
+app.get("/x", [](Request&, Response& res)
+{
+ res.send(std::string(20, 'a'));
+});
+
+app.run(8080);
+```
+
+---
+
+## Run
+
+```bash
+vix run compression_app_simple.cpp
+```
+
+---
+
+## Test With curl
+
+### 1) No Accept-Encoding
+
+```bash
+curl -i http://localhost:8080/x
+```
+
+Result:
+No compression applied.
+
+---
+
+### 2) With Accept-Encoding
+
+```bash
+curl -i -H "Accept-Encoding: gzip, br" http://localhost:8080/x
+```
+
+If body is large enough:
+Compression is applied.
+
+---
+
+### 3) Small body (below min_size)
+
+```bash
+curl -i -H "Accept-Encoding: gzip" http://localhost:8080/small
+```
+
+No compression because body < min_size.
+
+---
+
+## Important Options
+
+.min_size
+Minimum response size required to compress.
+
+.enabled
+Enable or disable compression.
+
+.add_vary
+Adds:
+Vary: Accept-Encoding
+
+This is important for proper caching behavior.
+
+---
+
+# Complete Working Example
+
+Save as: compression_app_simple.cpp
+
+```cpp
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Install compression globally
+ auto mw = vix::middleware::app::adapt_ctx(
+ vix::middleware::performance::compression({
+ .min_size = 8,
+ .add_vary = true,
+ .enabled = true,
+ }));
+
+ app.use(std::move(mw));
+
+ app.get("/", [](Request&, Response& res)
+ {
+ res.send("Compression middleware installed.");
+ });
+
+ // Large body (should compress if client supports it)
+ app.get("/x", [](Request&, Response& res)
+ {
+ res.status(200).send(std::string(20, 'a'));
+ });
+
+ // Small body (no compression)
+ app.get("/small", [](Request&, Response& res)
+ {
+ res.status(200).send("aaaa");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## Summary
+
+Compression middleware:
+
+- Automatically checks Accept-Encoding
+- Compresses only when useful
+- Keeps your code clean
+- Improves performance without changing route logic
+
+Vix.cpp keeps compression simple and explicit.
+
diff --git a/docs/examples/cookies.md b/docs/examples/cookies.md
new file mode 100644
index 0000000..40a8f50
--- /dev/null
+++ b/docs/examples/cookies.md
@@ -0,0 +1,197 @@
+# Cookies Guide
+
+Cookies are small key/value strings stored by the browser and sent back on future requests.
+
+They are useful for:
+
+- sessions (login)
+- user preferences
+- CSRF tokens
+- small state across requests
+
+In HTTP, the server sends a cookie using the header:
+
+Set-Cookie: name=value; options...
+
+The browser then sends it back using:
+
+Cookie: name=value; other=value
+
+---
+
+## Minimal Example: Set a Cookie
+
+This endpoint sets a cookie named `hello` with value `vix`.
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/cookie", [](Request&, Response& res)
+ {
+ vix::middleware::cookies::Cookie c;
+ c.name = "hello";
+ c.value = "vix";
+ c.max_age = 3600; // 1 hour
+
+ vix::middleware::cookies::set(res, c);
+
+ res.text("cookie set");
+ });
+
+ app.run(8080);
+}
+```
+
+---
+
+## Run
+
+```bash
+vix run cookie_app_simple.cpp
+```
+
+---
+
+## Test With curl
+
+### 1) See the Set-Cookie header
+
+```bash
+curl -i http://localhost:8080/cookie
+```
+
+You should see something like:
+
+Set-Cookie: hello=vix; Path=/; Max-Age=3600; HttpOnly; SameSite=Lax
+
+---
+
+### 2) Send the cookie back manually
+
+```bash
+curl -i http://localhost:8080/echo-cookie -H "Cookie: hello=vix"
+```
+
+(We add this route in the complete example below.)
+
+---
+
+### 3) Let curl store cookies automatically
+
+```bash
+# Save cookies into jar.txt
+curl -i -c jar.txt http://localhost:8080/cookie
+
+# Reuse cookies from jar.txt
+curl -i -b jar.txt http://localhost:8080/echo-cookie
+```
+
+---
+
+## Most Important Cookie Options
+
+### Path
+Controls which URLs receive the cookie.
+Default is `/`.
+
+### Max-Age
+How long the cookie lives in seconds.
+- `max_age = 3600` => 1 hour
+- `max_age = -1` => omit Max-Age (session cookie)
+
+### HttpOnly
+If true, JavaScript cannot read the cookie.
+This is safer for session cookies.
+
+### Secure
+If true, cookie is only sent over HTTPS.
+Use this in production.
+
+### SameSite
+Helps protect against CSRF.
+
+Common values:
+
+- Lax (default, good for most apps)
+- Strict (more locked down)
+- None (required for cross-site cookies, but must use Secure=true)
+
+---
+
+# Complete Example (set + read)
+
+Save as: cookie_app_simple.cpp
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+static void register_routes(App& app)
+{
+ // 1) Set a cookie
+ app.get("/cookie", [](Request&, Response& res)
+ {
+ vix::middleware::cookies::Cookie c;
+ c.name = "hello";
+ c.value = "vix";
+ c.max_age = 3600;
+ c.http_only = true;
+ c.secure = false;
+ c.same_site = "Lax";
+
+ vix::middleware::cookies::set(res, c);
+ res.text("cookie set");
+ });
+
+ // 2) Read a cookie from the request
+ app.get("/echo-cookie", [](Request& req, Response& res)
+ {
+ auto v = vix::middleware::cookies::get(req, "hello");
+
+ res.json({
+ "ok", true,
+ "cookie_hello", v ? *v : "",
+ "has_cookie", (bool)v
+ });
+ });
+}
+
+int main()
+{
+ App app;
+ register_routes(app);
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## Quick Demo Commands
+
+```bash
+vix run cookie_app_simple.cpp
+```
+
+```bash
+curl -i -c jar.txt http://localhost:8080/cookie
+curl -i -b jar.txt http://localhost:8080/echo-cookie
+```
+
+---
+
+## Summary
+
+- Use `cookies::set(res, cookie)` to send Set-Cookie
+- Use `cookies::get(req, "name")` to read Cookie
+- In production, enable Secure=true + HTTPS for session cookies
+
diff --git a/docs/examples/cors.md b/docs/examples/cors.md
new file mode 100644
index 0000000..4a87839
--- /dev/null
+++ b/docs/examples/cors.md
@@ -0,0 +1,216 @@
+# CORS Middleware Guide
+
+## What is CORS?
+
+CORS means **Cross-Origin Resource Sharing**.
+
+Browsers block frontend applications from calling APIs hosted on a different origin unless the server explicitly allows it.
+
+An origin is:
+- protocol (http / https)
+- domain
+- port
+
+Example:
+```bash
+- http://localhost:5173
+- http://localhost:8080
+```
+These are different origins → CORS is required.
+
+---
+
+## Why CORS exists
+
+Without CORS, any website could call your API using a logged-in user's browser.
+
+CORS allows the server to say:
+
+- Which origins are allowed
+- Which HTTP methods are allowed
+- Which headers are allowed
+- Whether credentials are allowed
+
+---
+
+# 1) Basic CORS Example
+
+This allows only `https://example.com` to call `/api`.
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+
+ app.get("/api", [](Request &, Response &res)
+ {
+ res.header("X-Request-Id", "req_123");
+ res.json({ "ok", true });
+ });
+
+ app.run(8080);
+}
+```
+
+### Test
+
+```bash
+curl -i http://localhost:8080/api -H "Origin: https://example.com"
+```
+
+Expected:
+- 200 OK
+- Access-Control-Allow-Origin header present
+
+---
+
+# 2) Strict CORS with Preflight (OPTIONS)
+
+Browsers send a **preflight request** before certain requests (POST, PUT, custom headers).
+
+This is an OPTIONS request.
+
+You should define explicit OPTIONS routes so the middleware can respond correctly.
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+
+ app.options("/api", [](Request &, Response &res)
+ {
+ res.status(204).send();
+ });
+
+ app.get("/api", [](Request &, Response &res)
+ {
+ res.json({ "ok", true });
+ });
+
+ app.run(8080);
+}
+```
+
+### Test allowed origin
+
+```bash
+curl -i -X OPTIONS http://localhost:8080/api -H "Origin: https://example.com" -H "Access-Control-Request-Method: POST"
+```
+
+Expected: 204 + CORS headers.
+
+### Test blocked origin
+
+```bash
+curl -i -X OPTIONS http://localhost:8080/api -H "Origin: https://evil.com" -H "Access-Control-Request-Method: POST"
+```
+
+Expected: 403 Forbidden.
+
+---
+
+# 3) CORS in Production (Important)
+
+In real applications:
+
+- Apply CORS only on API routes (not public static routes)
+- Combine with:
+ - Security headers
+ - CSRF protection
+ - Authentication
+- Never allow "*" with credentials
+
+Correct order:
+
+```cpp
+app.use("/api", middleware::app::security_headers_dev());
+app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+app.use("/api", middleware::app::csrf_dev());
+```
+
+Order matters.
+
+---
+
+# Common Beginner Mistakes
+
+1) Forgetting OPTIONS route
+2) Allowing "*" in production
+3) Not understanding that CORS is enforced by browsers, not curl
+4) Confusing CORS with authentication (they are different)
+
+---
+
+# Complete Working Example
+
+Save as: `cors_app_full.cpp`
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/api", middleware::app::security_headers_dev());
+ app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+
+ app.options("/api/data", [](Request &, Response &res)
+ {
+ res.status(204).send();
+ });
+
+ app.get("/api/data", [](Request &, Response &res)
+ {
+ res.json({
+ "ok", true,
+ "message", "CORS working"
+ });
+ });
+
+ app.get("/", [](Request &, Response &res)
+ {
+ res.send("Public route");
+ });
+
+ app.run(8080);
+}
+```
+
+Run:
+
+```bash
+vix run cors_app_full.cpp
+```
+
+---
+
+# Summary
+
+CORS controls which origins can call your API.
+
+Use:
+- `cors_dev()` for development
+- Explicit OPTIONS routes
+- Combine with CSRF and security headers
+- Restrict allowed origins in production
+
+CORS is a browser security feature, not an authentication system.
+
diff --git a/docs/examples/csrf.md b/docs/examples/csrf.md
new file mode 100644
index 0000000..4605fc1
--- /dev/null
+++ b/docs/examples/csrf.md
@@ -0,0 +1,297 @@
+# CSRF (Beginner Guide)
+
+This guide explains CSRF protection in Vix.cpp with tiny examples you can copy paste.
+
+CSRF means Cross Site Request Forgery. It matters when you use cookies for auth (sessions) because browsers attach cookies automatically to cross site requests.
+
+If your API accepts a state changing request (POST, PUT, PATCH, DELETE) and the browser sends cookies automatically, an attacker can trick a user into sending requests from another site unless you protect it.
+
+Vix.cpp CSRF middleware uses a simple model:
+
+- Server sets a CSRF token in a cookie (for example `csrf_token=abc`)
+- Client must echo the same token in a header (for example `x-csrf-token: abc`)
+- If cookie and header do not match, the request is rejected
+
+---
+
+## 1) Minimal CSRF on `/api` prefix
+
+This is the smallest server:
+
+- `GET /api/csrf` sets a CSRF cookie and returns the token
+- `POST /api/update` requires the header token to match the cookie token
+
+```cpp
+/**
+ *
+ * @file csrf_strict_server.cpp - CSRF middleware example (Vix.cpp)
+ *
+ */
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Protect all /api routes with CSRF
+ // Default cookie: csrf_token
+ // Default header: x-csrf-token
+ // Default protect_get: false
+ app.use("/api", middleware::app::csrf_dev());
+
+ // Issue token (cookie + JSON response for convenience)
+ app.get("/api/csrf", [](Request &, Response &res)
+ {
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.json({"csrf_token", "abc"});
+ });
+
+ // Protected write route
+ app.post("/api/update", [](Request &, Response &res)
+ {
+ res.json({"ok", true, "message", "CSRF passed"});
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### Test with curl (cookie jar)
+
+```bash
+# 1) Get token (cookie)
+curl -i -c cookies.txt http://localhost:8080/api/csrf
+
+# 2) FAIL: missing header
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -d "x=1"
+
+# 3) FAIL: wrong token
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update \
+ -H "x-csrf-token: wrong" -d "x=1"
+
+# 4) OK: header token matches cookie token
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update \
+ -H "x-csrf-token: abc" -d "x=1"
+```
+
+Expected:
+
+- Missing token header -> 403 (or 401 depending on config)
+- Wrong token -> 403
+- Matching token -> 200
+
+---
+
+## 2) CSRF + CORS (browser realistic)
+
+When you call an API from a browser on another origin, you usually need both:
+
+- CORS to allow the origin
+- CSRF to protect cookie based write requests
+
+Important detail: browsers send OPTIONS preflight requests. If you want the CORS middleware to answer preflight correctly, define explicit OPTIONS routes for endpoints you call from the browser.
+
+### Minimal pattern
+
+```cpp
+/**
+ *
+ * @file security_cors_csrf_server.cpp - CORS + CSRF (Vix.cpp)
+ *
+ */
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Apply on /api prefix (order matters for a production style pipeline)
+ app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+ app.use("/api", middleware::app::csrf_dev("csrf_token", "x-csrf-token", false));
+
+ // Explicit OPTIONS routes for browser preflight
+ app.options("/api/update", [](Request &, Response &res){ res.status(204).send(); });
+ app.options("/api/csrf", [](Request &, Response &res){ res.status(204).send(); });
+
+ // Token endpoint
+ app.get("/api/csrf", [](Request &, Response &res)
+ {
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.json({"csrf_token", "abc"});
+ });
+
+ // Protected write endpoint
+ app.post("/api/update", [](Request &, Response &res)
+ {
+ res.json({"ok", true, "message", "CORS ok + CSRF ok"});
+ });
+
+ app.get("/", [](Request &, Response &res){ res.send("public"); });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### Test preflight (curl)
+
+```bash
+# Allowed origin preflight should return 204 + CORS headers
+curl -i -X OPTIONS http://localhost:8080/api/update \
+ -H "Origin: https://example.com" \
+ -H "Access-Control-Request-Method: POST" \
+ -H "Access-Control-Request-Headers: Content-Type, X-CSRF-Token"
+
+# Blocked origin preflight should return 403
+curl -i -X OPTIONS http://localhost:8080/api/update \
+ -H "Origin: https://evil.com" \
+ -H "Access-Control-Request-Method: POST"
+```
+
+---
+
+## 3) Strict mode (protect GET too)
+
+Most APIs do not need CSRF on GET because GET should be read only. But if you expose a dangerous GET endpoint (bad design, but it happens), you can protect it too.
+
+```cpp
+// Strict CSRF preset also protects GET
+app.use("/api", middleware::app::csrf_strict_dev("csrf_token", "x-csrf-token"));
+```
+
+Rule of thumb:
+
+- protect_get = false is typical
+- protect_get = true only if you have state changes on GET or you want extreme hardening
+
+---
+
+## Common beginner mistakes
+
+1) Confusing CORS with CSRF
+CORS controls which origins can read responses. CSRF controls whether a cookie based write request is allowed.
+
+2) Missing OPTIONS routes for browser calls
+If preflight is not handled properly, the browser will block your requests even if your API works with curl.
+
+3) Cookie SameSite and Secure flags
+- SameSite=Lax often blocks cookies in some cross site POST cases
+- For true cross site cookies in modern browsers you need HTTPS and SameSite=None; Secure
+- For local dev HTTP, SameSite=Lax is fine for curl demos
+
+4) CSRF is not needed for Authorization header auth
+If you only use `Authorization: Bearer ` and do not rely on cookies, CSRF is usually not required because the browser will not attach Authorization headers automatically.
+
+---
+
+## Production notes (practical)
+
+- Use CSRF when you use Session cookies.
+- Prefer short lived CSRF tokens or rotate them on login.
+- Combine with security headers and rate limiting on `/api`.
+
+Recommended order for `/api`:
+
+1) security headers
+2) CORS
+3) auth (session or jwt)
+4) CSRF (if cookie based)
+5) rate limit
+6) business routes
+
+---
+
+# Complete example (copy paste)
+
+This single file is a realistic production demo:
+
+- Security headers on all `/api` responses
+- CORS for selected origins
+- CSRF protection for write requests
+- Explicit OPTIONS routes for browser preflight
+- Two endpoints: `/api/csrf` and `/api/update`
+
+Save as: `security_cors_csrf_headers_server.cpp`
+
+```cpp
+/**
+ *
+ * @file security_cors_csrf_headers_server.cpp - CORS + CSRF + Security Headers (Vix.cpp)
+ *
+ */
+#include
+#include
+
+using namespace vix;
+
+static void register_options(App& app)
+{
+ auto options_noop = [](Request &, Response &res){ res.status(204).send(); };
+
+ app.options("/api/update", options_noop);
+ app.options("/api/csrf", options_noop);
+}
+
+static void register_routes(App& app)
+{
+ app.get("/api/csrf", [](Request &, Response &res)
+ {
+ // Local dev: SameSite=Lax is fine.
+ // Cross site in browsers: use HTTPS + SameSite=None; Secure.
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.header("X-Request-Id", "req_csrf_1");
+ res.json({"csrf_token", "abc"});
+ });
+
+ app.post("/api/update", [](Request &, Response &res)
+ {
+ res.header("X-Request-Id", "req_update_1");
+ res.json({"ok", true, "message", "CORS ok + CSRF ok + HEADERS ok"});
+ });
+
+ app.get("/", [](Request &, Response &res){ res.send("public route"); });
+}
+
+int main()
+{
+ App app;
+
+ // Apply on ALL /api/*
+ // Order matters: headers first, then CORS, then CSRF.
+ app.use("/api", middleware::app::security_headers_dev()); // HSTS off by default
+ app.use("/api", middleware::app::cors_dev({
+ "http://localhost:5173",
+ "http://0.0.0.0:5173",
+ "https://example.com"
+ }));
+ app.use("/api", middleware::app::csrf_dev("csrf_token", "x-csrf-token", false));
+
+ register_options(app);
+ register_routes(app);
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### Run
+
+```bash
+vix run security_cors_csrf_headers_server.cpp
+```
+
+### Curl test
+
+```bash
+curl -i -c cookies.txt http://localhost:8080/api/csrf
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -d "x=1"
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -H "x-csrf-token: abc" -d "x=1"
+```
+
diff --git a/docs/examples/db-production-guide.md b/docs/examples/db-production-guide.md
new file mode 100644
index 0000000..7387148
--- /dev/null
+++ b/docs/examples/db-production-guide.md
@@ -0,0 +1,145 @@
+# Vix DB Production Guide
+
+This guide explains how to use the Vix C++ DB module safely in
+production environments.
+
+It focuses on:
+
+- Connection pooling strategy
+- Transactions best practices
+- Error handling
+- Migrations strategy
+- Performance recommendations
+- Security considerations
+
+# 1. Connection Pooling Strategy
+
+## Recommended Settings
+
+``` cpp
+cfg.mysql.pool.min = 2;
+cfg.mysql.pool.max = 16;
+```
+
+Guidelines:
+
+- Small apps: 2--4 connections
+- Medium apps: 8--16 connections
+- High traffic APIs: tune based on load testing
+
+Why pooling matters:
+
+- Avoids connection creation overhead
+- Improves latency
+- Reduces database stress
+
+Never create Database per request. Create it once at application
+startup.
+
+# 2. Transaction Best Practices
+
+Always use RAII transactions:
+
+``` cpp
+Transaction tx(db.pool());
+// work
+tx.commit();
+```
+
+Rules:
+
+- Keep transactions short
+- Do not perform network calls inside transactions
+- Commit explicitly
+- Let rollback happen automatically on exceptions
+
+# 3. Error Handling
+
+Always wrap DB logic in try/catch:
+
+``` cpp
+try {
+ Transaction tx(db.pool());
+ // DB logic
+ tx.commit();
+} catch (const std::exception& e) {
+ log_error(e.what());
+}
+```
+
+Never expose raw DB errors to HTTP clients.
+
+# 4. Migrations in Production
+
+Strategy:
+
+- Use versioned migrations
+- Never modify old migrations
+- Always add new migration files
+
+Recommended flow:
+
+1. Deploy code
+2. Run migrations
+3. Restart services if needed
+
+Keep migrations idempotent.
+
+# 5. Performance Optimization
+
+Use prepared statements everywhere.
+
+Bad:
+
+``` cpp
+"SELECT * FROM users WHERE id = " + id
+```
+
+Good:
+
+``` cpp
+st->bind(1, id);
+```
+
+Add proper DB indexes:
+
+- Index foreign keys
+- Index frequently filtered columns
+- Avoid over-indexing
+
+Measure before optimizing.
+
+# 6. Security Best Practices
+
+- Never store plaintext passwords
+- Use environment variables for DB credentials
+- Limit DB user privileges
+- Use TLS connections in production
+- Rotate credentials periodically
+
+# 7. Deployment Checklist
+
+Before production:
+
+- Pool size tuned
+- Indexes verified
+- Migrations tested
+- Error logging enabled
+- Backups configured
+- Monitoring enabled
+
+# Final Advice
+
+Database is critical infrastructure.
+
+Treat it as:
+
+- Stateful
+- Sensitive
+- Performance-critical
+
+Design carefully. Test under load. Monitor continuously.
+
+Vix DB gives you control. Production reliability depends on your
+discipline.
+
diff --git a/docs/examples/db-quickstart.md b/docs/examples/db-quickstart.md
new file mode 100644
index 0000000..203ed61
--- /dev/null
+++ b/docs/examples/db-quickstart.md
@@ -0,0 +1,87 @@
+# Vix DB Quickstart (5 Minutes)
+
+This is the fastest way to get started with the Vix C++ DB module.
+
+Goal: connect, create table, insert, query.
+
+## 1️⃣ Configure Database
+
+``` cpp
+#include
+#include
+
+using namespace vix::db;
+
+DbConfig make_cfg()
+{
+ DbConfig cfg;
+ cfg.engine = Engine::MySQL;
+ cfg.mysql.host = "tcp://127.0.0.1:3306";
+ cfg.mysql.user = "root";
+ cfg.mysql.password = "";
+ cfg.mysql.database = "vixdb";
+ cfg.mysql.pool.min = 1;
+ cfg.mysql.pool.max = 4;
+ return cfg;
+}
+```
+
+## 2️⃣ Full Working Example
+
+``` cpp
+int main()
+{
+ Database db(make_cfg());
+
+ Transaction tx(db.pool());
+
+ // Create table
+ tx.conn().prepare(
+ "CREATE TABLE IF NOT EXISTS users ("
+ "id BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "name VARCHAR(255) NOT NULL,"
+ "age INT NOT NULL)"
+ )->exec();
+
+ // Insert
+ auto insert = tx.conn().prepare(
+ "INSERT INTO users (name, age) VALUES (?, ?)"
+ );
+ insert->bind(1, std::string("Alice"));
+ insert->bind(2, static_cast(22));
+ insert->exec();
+
+ // Query
+ auto query = tx.conn().prepare(
+ "SELECT id, name, age FROM users"
+ );
+
+ auto rs = query->query();
+ while (rs->next())
+ {
+ const auto& row = rs->row();
+ std::cout
+ << row.getInt64(0) << " "
+ << row.getString(1) << " "
+ << row.getInt64(2) << "\n";
+ }
+
+ tx.commit();
+ return 0;
+}
+```
+
+## 3️⃣ What You Just Used
+
+Database\
+Connection Pool\
+Prepared Statements\
+Transaction (RAII)
+
+## 🎯 That's it.
+
+You now have a working database setup in Vix C++.
+
+Next step: - Add migrations - Add error handling - Integrate with your
+HTTP routes
+
diff --git a/docs/examples/db-transactions.md b/docs/examples/db-transactions.md
new file mode 100644
index 0000000..8d01a8c
--- /dev/null
+++ b/docs/examples/db-transactions.md
@@ -0,0 +1,153 @@
+# Vix DB Transactions Guide
+
+This guide explains how transactions work in Vix DB and how to use them
+correctly in real applications.
+
+Transactions ensure that multiple database operations behave as a single
+atomic unit.
+
+If something fails, everything is rolled back.
+
+# 1. What is a Transaction
+
+A transaction guarantees:
+
+- Atomicity
+- Consistency
+- Isolation
+- Durability
+
+In simple terms:
+
+Either everything succeeds, or nothing is applied.
+
+# 2. Basic RAII Transaction
+
+``` cpp
+#include
+using namespace vix::db;
+
+void create_user(Database& db)
+{
+ Transaction tx(db.pool());
+
+ auto st = tx.conn().prepare(
+ "INSERT INTO users (name, age) VALUES (?, ?)"
+ );
+
+ st->bind(1, std::string("Alice"));
+ st->bind(2, static_cast(25));
+ st->exec();
+
+ tx.commit();
+}
+```
+
+Important:
+
+If commit() is not called, rollback happens automatically when tx goes
+out of scope.
+
+This is RAII safety.
+
+# 3. Multiple Operations in One Transaction
+
+``` cpp
+Transaction tx(db.pool());
+
+// Insert user
+auto insert_user = tx.conn().prepare(
+ "INSERT INTO users (name, age) VALUES (?, ?)"
+);
+insert_user->bind(1, "Bob");
+insert_user->bind(2, static_cast(30));
+insert_user->exec();
+
+// Insert profile
+auto insert_profile = tx.conn().prepare(
+ "INSERT INTO profiles (user_id, bio) VALUES (?, ?)"
+);
+insert_profile->bind(1, static_cast(1));
+insert_profile->bind(2, "Engineer");
+insert_profile->exec();
+
+tx.commit();
+```
+
+If the second insert fails, both inserts are rolled back.
+
+# 4. Automatic Rollback on Exception
+
+``` cpp
+try
+{
+ Transaction tx(db.pool());
+
+ auto st = tx.conn().prepare("DELETE FROM users WHERE id = ?");
+ st->bind(1, static_cast(5));
+ st->exec();
+
+ throw std::runtime_error("Something failed");
+
+ tx.commit();
+}
+catch (...)
+{
+ // No manual rollback needed
+}
+```
+
+Because commit() was not called, rollback happens automatically.
+
+# 5. Best Practices
+
+Keep transactions short.
+
+Do not:
+
+- Perform HTTP calls inside a transaction
+- Wait for external APIs
+- Sleep or block unnecessarily
+
+Do:
+
+- Execute DB operations quickly
+- Commit immediately
+- Handle errors properly
+
+# 6. Nested Transactions
+
+Avoid nested transactions unless your database supports savepoints.
+
+If needed, use explicit savepoint logic at the SQL level.
+
+# 7. Production Advice
+
+Transactions lock resources.
+
+Long transactions reduce concurrency and performance.
+
+Monitor:
+
+- Slow queries
+- Deadlocks
+- Lock wait timeouts
+
+Design carefully.
+
+# Summary
+
+Transactions in Vix DB are:
+
+- RAII safe
+- Automatic rollback
+- Explicit commit required
+
+Use them for:
+
+- Multi-step writes
+- Data integrity guarantees
+- Critical operations
+
+Correct transaction usage is essential for production-grade systems.
+
diff --git a/docs/examples/db.md b/docs/examples/db.md
new file mode 100644
index 0000000..7aba174
--- /dev/null
+++ b/docs/examples/db.md
@@ -0,0 +1,170 @@
+# Vix DB Module – Beginner Guide
+
+This guide introduces the Vix C++ database module in a simple and practical way.
+
+The goal is to help beginners understand:
+
+- How to connect to a database
+- How to run queries
+- How to use transactions
+- How to run migrations
+
+---
+
+## 1. Basic Connection (MySQL)
+
+```cpp
+#include
+#include
+
+using namespace vix::db;
+
+int main()
+{
+ DbConfig cfg;
+ cfg.engine = Engine::MySQL;
+ cfg.mysql.host = "tcp://127.0.0.1:3306";
+ cfg.mysql.user = "root";
+ cfg.mysql.password = "";
+ cfg.mysql.database = "vixdb";
+
+ Database db(cfg);
+
+ auto conn = db.pool().acquire();
+ if (!conn->ping())
+ {
+ std::cerr << "DB ping failed\n";
+ return 1;
+ }
+
+ std::cout << "DB connected successfully\n";
+ return 0;
+}
+```
+
+What happens here:
+
+1. We configure the database connection.
+2. We create a Database object.
+3. We acquire a connection from the pool.
+4. We ping the database to verify connectivity.
+
+---
+
+## 2. Simple Query with Prepared Statements
+
+```cpp
+auto conn = db.pool().acquire();
+auto st = conn->prepare("SELECT id, name FROM users WHERE age > ?");
+
+st->bind(1, 18);
+
+auto rs = st->query();
+while (rs->next())
+{
+ const auto &row = rs->row();
+ std::cout << row.getInt64(0) << " "
+ << row.getString(1) << "\n";
+}
+```
+
+Why prepared statements?
+
+- Prevent SQL injection
+- Handle type-safe parameter binding
+- Improve performance
+
+---
+
+## 3. Transactions (RAII Style)
+
+Transactions are automatically rolled back if not committed.
+
+```cpp
+Transaction tx(db.pool());
+
+auto st = tx.conn().prepare(
+ "INSERT INTO users (name, age) VALUES (?, ?)"
+);
+
+st->bind(1, std::string("Alice"));
+st->bind(2, static_cast(20));
+st->exec();
+
+tx.commit();
+```
+
+If commit() is not called, the transaction rolls back automatically.
+
+---
+
+## 4. Code-Based Migration
+
+```cpp
+class CreateUsersTable final : public Migration
+{
+public:
+ std::string id() const override { return "2026-01-22-create-users"; }
+
+ void up(Connection &c) override
+ {
+ c.prepare(
+ "CREATE TABLE IF NOT EXISTS users ("
+ "id BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "name VARCHAR(255) NOT NULL,"
+ "age INT NOT NULL);"
+ )->exec();
+ }
+
+ void down(Connection &c) override
+ {
+ c.prepare("DROP TABLE IF EXISTS users;")->exec();
+ }
+};
+```
+
+Migrations allow you to version your schema safely.
+
+---
+
+## 5. File-Based Migrations
+
+Place files inside:
+
+```
+migrations/
+ 001_create_users.up.sql
+ 001_create_users.down.sql
+```
+
+Then run:
+
+```cpp
+FileMigrationsRunner runner(tx.conn(), "migrations");
+runner.applyAll();
+```
+
+---
+
+## Key Concepts for Beginners
+
+Connection Pool:
+- Reuses database connections
+- Improves performance
+
+Prepared Statements:
+- Use ? placeholders
+- Bind values safely
+
+Transactions:
+- Ensure atomic operations
+- Commit or rollback
+
+Migrations:
+- Keep database schema versioned
+- Safe evolution of your database
+
+---
+
+You are now ready to use Vix DB in real applications.
+
diff --git a/docs/examples/delete_user.md b/docs/examples/delete_user.md
deleted file mode 100644
index 9dec9fe..0000000
--- a/docs/examples/delete_user.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Example — delete_user.cpp
-
-```cpp
-#include
-#include
-#include
-
-using namespace vix;
-namespace J = vix::json;
-
-int main()
-{
- App app;
-
- // DELETE /users/{id}
- app.del("/users/{id}", [](Request &req, Response &res)
- {
- const std::string id = req.param("id");
-
- // In a real app you'd remove the resource from DB or memory here
- res.json({
- "action", "delete",
- "status", "deleted",
- "user_id", id
- }); });
-
- app.run(8080);
- return 0;
-}
-```
diff --git a/docs/examples/error-handling.md b/docs/examples/error-handling.md
new file mode 100644
index 0000000..73dff55
--- /dev/null
+++ b/docs/examples/error-handling.md
@@ -0,0 +1,210 @@
+# ORM Example Guide: Error Handling
+
+This guide explains the `error_handling` example.
+
+Goal: - Show what happens when the database connection is invalid -
+Demonstrate how to catch `DBError` cleanly - Encourage safe production
+error handling patterns
+
+This example intentionally uses a wrong database name to trigger errors.
+
+# 1. What this example demonstrates
+
+You will learn:
+
+- Where database errors happen (factory, pool warmup, queries)
+- Why `pool.warmup()` is important
+- How to catch `DBError` separately from other exceptions
+- How to write safe CLI-style error handling
+
+# 2. Full Example Code
+
+``` cpp
+#include
+
+#include
+#include
+
+using namespace vix::orm;
+
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ try
+ {
+ // Intentionally wrong DB name to show error handling
+ const std::string host = "tcp://127.0.0.1:3306";
+ const std::string user = "root";
+ const std::string pass = "";
+ const std::string db = "db_does_not_exist";
+
+ auto factory = make_mysql_factory(host, user, pass, db);
+
+ PoolConfig cfg;
+ cfg.min = 1;
+ cfg.max = 8;
+
+ ConnectionPool pool{factory, cfg};
+
+ // will throw if factory returns invalid connection (recommended after our warmup fix),
+ // or later when first query fails.
+ pool.warmup();
+
+ UnitOfWork uow{pool};
+ auto &con = uow.conn();
+
+ auto st = con.prepare("SELECT 1");
+ (void)st->exec();
+
+ std::cout << "[INFO] This message may not be reached if connection fails.\n";
+ return 0;
+ }
+ catch (const DBError &e)
+ {
+ std::cerr << "[DBError] " << e.what() << "\n";
+ return 1;
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "[std::exception] " << e.what() << "\n";
+ return 1;
+ }
+}
+```
+
+# 3. Step by Step Explanation
+
+## 3.1 Intentional failure
+
+``` cpp
+const std::string db = "db_does_not_exist";
+```
+
+This database does not exist, so MySQL will fail during connection or
+query.
+
+This is a controlled demo to show how errors look and how to handle
+them.
+
+## 3.2 Create factory and pool
+
+``` cpp
+auto factory = make_mysql_factory(host, user, pass, db);
+ConnectionPool pool{factory, cfg};
+```
+
+The factory creates MySQL connections. The pool stores and reuses them.
+
+## 3.3 Why warmup matters
+
+``` cpp
+pool.warmup();
+```
+
+Warmup tries to pre-create connections early.
+
+Benefits:
+
+- Fail fast at startup (not during first real request)
+- Catch invalid credentials immediately
+- Avoid "first request slow" latency
+
+In this example, warmup is expected to throw because the database is
+invalid.
+
+## 3.4 UnitOfWork and query
+
+``` cpp
+UnitOfWork uow{pool};
+auto st = con.prepare("SELECT 1");
+st->exec();
+```
+
+If warmup did not throw, the next likely failure point is the first
+query.
+
+Either way, errors become exceptions.
+
+# 4. Catching DBError vs std::exception
+
+``` cpp
+catch (const DBError &e)
+{
+ std::cerr << "[DBError] " << e.what() << "\n";
+}
+```
+
+`DBError` is the dedicated Vix ORM exception type for database errors,
+such as:
+
+- Connection failures
+- Authentication failures
+- Database not found
+- Query syntax errors
+- Constraint violations
+
+Then a generic catch for everything else:
+
+``` cpp
+catch (const std::exception &e)
+{
+ std::cerr << "[std::exception] " << e.what() << "\n";
+}
+```
+
+This separation makes logs easier to understand.
+
+# 5. Production Advice
+
+## 5.1 Fail fast at startup
+
+Call `pool.warmup()` in your application startup:
+
+- you detect DB misconfiguration immediately
+- you avoid serving traffic with broken DB access
+
+## 5.2 Do not leak DB errors to clients
+
+If you build an HTTP API:
+
+- log full DBError internally
+- return a generic error to clients
+
+Example mapping:
+
+- DBError: "database unavailable"
+- client message: "temporary server issue"
+
+## 5.3 Add context in logs
+
+In production, log:
+
+- host
+- database name
+- error message
+- operation context (connect, warmup, query)
+
+Do not log secrets like passwords.
+
+# 6. Typical causes of DBError
+
+- Wrong host or port
+- Wrong username/password
+- Database missing
+- Permissions missing
+- Network blocked (firewall)
+- Connection limit reached
+- Invalid SQL syntax
+- Foreign key constraint failure
+
+# Summary
+
+This example demonstrates:
+
+- How to force a predictable DB failure
+- Why warmup is important
+- How to catch DBError cleanly
+- How to structure safe production error handling
+
diff --git a/docs/examples/errors.md b/docs/examples/errors.md
new file mode 100644
index 0000000..c7d5587
--- /dev/null
+++ b/docs/examples/errors.md
@@ -0,0 +1,235 @@
+# Errors + Status Codes
+
+This section shows how to handle errors and HTTP status codes in Vix.cpp.
+
+Each example is minimal and self-contained.
+
+---
+
+## 1. Simple 404 Response
+
+Return a JSON error with explicit status.
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/not-found", [](Request&, Response& res)
+ {
+ res.status(404).json({
+ "ok", false,
+ "error", "Resource not found"
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Test:
+
+ curl -i http://localhost:8080/not-found
+
+---
+
+## 2. 400 Bad Request (Validation-style)
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/bad", [](Request&, Response& res)
+ {
+ res.status(400).json({
+ "ok", false,
+ "error", "Invalid input"
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 3. 401 Unauthorized
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/private", [](Request&, Response& res)
+ {
+ res.status(401).json({
+ "ok", false,
+ "error", "Unauthorized"
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 4. 403 Forbidden
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/admin", [](Request&, Response& res)
+ {
+ res.status(403).json({
+ "ok", false,
+ "error", "Forbidden"
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 5. 500 Internal Server Error
+
+You can manually return 500:
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/error", [](Request&, Response& res)
+ {
+ res.status(500).json({
+ "ok", false,
+ "error", "Internal Server Error"
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 6. Throwing an Exception
+
+If a handler throws, Vix will convert it into a 500 response
+(depending on your dev/production configuration).
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/boom", [](Request&, Response&)
+ {
+ throw std::runtime_error("Something went wrong");
+ return "unreachable";
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 7. Using set_status() + send()
+
+```cpp
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/created", [](Request&, Response& res)
+ {
+ res.set_status(201);
+ res.send("Created");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## 8. Returning JSON Automatically
+
+If nothing is sent explicitly, returning JSON auto-sends the response.
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/auto-error", [](Request&, Response&)
+ {
+ return vix::json::o(
+ "ok", false,
+ "error", "Auto-sent error"
+ );
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+---
+
+## What this teaches
+
+- How to set HTTP status codes
+- How to return structured JSON errors
+- How exceptions behave
+- The difference between res.status() and set_status()
+- Auto-send return style
+
diff --git a/docs/examples/etag.md b/docs/examples/etag.md
new file mode 100644
index 0000000..667feaa
--- /dev/null
+++ b/docs/examples/etag.md
@@ -0,0 +1,215 @@
+# ETag Middleware Guide
+
+## What is an ETag?
+
+ETag stands for **Entity Tag**.
+
+It is an HTTP response header used for **cache validation**.
+
+Instead of re-downloading a resource every time, the client can say:
+
+> "I already have version X. Has it changed?"
+
+If not changed → server replies:
+
+ 304 Not Modified
+
+No body is sent.\
+This saves bandwidth and improves performance.
+
+## How ETag Works
+
+1. Server sends response with:
+
+```{=html}
+
+```
+ ETag: "abc123"
+
+2. Client stores it.
+
+3. On next request, client sends:
+
+```{=html}
+
+```
+ If-None-Match: "abc123"
+
+4. Server compares:
+
+- If same → `304 Not Modified`
+- If different → `200 OK` with new body + new ETag
+
+# Minimal Example
+
+Save as: `etag_app_simple.cpp`
+
+``` cpp
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace vix;
+
+static void print_help()
+{
+ std::cout
+ << "Vix ETag example running:\n"
+ << " http://localhost:8080/x\n\n"
+ << "Try:\n"
+ << " curl -i http://localhost:8080/x\n"
+ << " curl -i -H 'If-None-Match: ' http://localhost:8080/x\n"
+ << " curl -I http://localhost:8080/x\n";
+}
+
+int main()
+{
+ App app;
+
+ // Install ETag middleware globally
+ auto mw = vix::middleware::app::adapt_ctx(
+ vix::middleware::performance::etag({
+ .weak = true,
+ .add_cache_control_if_missing = false,
+ .min_body_size = 1
+ }));
+
+ app.use(std::move(mw));
+
+ app.get("/x", [](Request &, Response &res)
+ {
+ res.text("Hello ETag world");
+ });
+
+ app.head("/x", [](Request &, Response &res)
+ {
+ res.status(200);
+ });
+
+ print_help();
+ app.run(8080);
+ return 0;
+}
+```
+
+## Run
+
+``` bash
+vix run etag_app_simple.cpp
+```
+
+## Test Step by Step
+
+### 1) First request
+
+``` bash
+curl -i http://localhost:8080/x
+```
+
+Response will contain:
+
+ ETag: W/"..."
+
+Copy that value.
+
+### 2) Send If-None-Match
+
+``` bash
+curl -i -H 'If-None-Match: W/"...your_etag_here..."' http://localhost:8080/x
+```
+
+If unchanged →
+
+ 304 Not Modified
+
+No body returned.
+
+### 3) HEAD request
+
+``` bash
+curl -I http://localhost:8080/x
+```
+
+HEAD returns headers only.\
+ETag is still calculated.
+
+# Middleware Options Explained
+
+``` cpp
+vix::middleware::performance::etag({
+ .weak = true,
+ .add_cache_control_if_missing = false,
+ .min_body_size = 1
+});
+```
+
+### weak
+
+- `true` → `W/"hash"`
+- `false` → `"hash"` (strong)
+
+Weak ETags are recommended for dynamic APIs.
+
+### add_cache_control_if_missing
+
+If true and response has no Cache-Control header, middleware can inject
+a default one.
+
+### min_body_size
+
+Only compute ETag if body \>= this size.
+
+Helps skip tiny responses.
+
+# When to Use ETag
+
+Use ETag for:
+
+- JSON APIs
+- Static content
+- CDN friendly responses
+- Any idempotent GET endpoint
+
+Avoid for:
+
+- Non-deterministic responses
+- Streaming endpoints
+
+# Production Pattern
+
+Typical production setup:
+
+ Compression
+ ETag
+ Cache-Control
+
+Example:
+
+``` cpp
+app.use(adapt_ctx(compression(...)));
+app.use(adapt_ctx(etag({...})));
+```
+
+Order matters.
+
+# Common Mistakes
+
+1. Forgetting GET route (HEAD alone is not enough)
+2. Sending different body order (JSON fields shuffled)
+3. Mixing weak/strong inconsistently
+4. Not handling 304 correctly on client side
+
+# Summary
+
+ETag gives you:
+
+- Conditional requests
+- Bandwidth savings
+- Faster responses
+- Cleaner caching logic
+
+Minimal, powerful, and production-ready.
+
diff --git a/docs/examples/form.md b/docs/examples/form.md
new file mode 100644
index 0000000..d0aed40
--- /dev/null
+++ b/docs/examples/form.md
@@ -0,0 +1,134 @@
+# Form & Body Parsers Guide
+
+Beginner-friendly guide for:
+
+- application/x-www-form-urlencoded
+- application/json
+- multipart/form-data
+
+Each section includes: - Minimal server - curl tests - Expected behavior
+
+# 1) Form Parser (application/x-www-form-urlencoded)
+
+## Minimal example
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/form", middleware::app::form_dev(128));
+
+ app.post("/form", [](Request &req, Response &res)
+ {
+ auto& fb = req.state();
+
+ auto it = fb.fields.find("b");
+ res.send(it == fb.fields.end() ? "" : it->second);
+ });
+
+ app.run(8080);
+}
+```
+
+## Test
+
+``` bash
+curl -i -X POST http://localhost:8080/form \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ --data "a=1&b=hello+world"
+```
+
+# 2) JSON Parser (application/json)
+
+## Minimal example
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/json", middleware::app::json_dev(256, true, true));
+
+ app.post("/json", [](Request &req, Response &res)
+ {
+ auto &jb = req.state();
+ res.json({
+ "ok", true,
+ "raw", jb.value.dump()
+ });
+ });
+
+ app.run(8080);
+}
+```
+
+## Test
+
+``` bash
+curl -i -X POST http://localhost:8080/json \
+ -H "Content-Type: application/json" \
+ --data '{"x":1}'
+```
+
+# 3) Multipart Parser (File Uploads)
+
+## Minimal example
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/mp", middleware::app::multipart_save_dev("uploads"));
+
+ app.post("/mp", [](Request &req, Response &res)
+ {
+ auto &form = req.state();
+ res.json(middleware::app::multipart_json(form));
+ });
+
+ app.run(8080);
+}
+```
+
+## Test
+
+``` bash
+curl -i -X POST http://localhost:8080/mp \
+ -F "a=1" -F "file=@/etc/hosts"
+```
+
+Files are saved to ./uploads/
+
+# Error Codes Summary
+
+ Code Meaning
+ ------ --------------------------
+ 400 Invalid body
+ 413 Payload too large
+ 415 Unsupported Content-Type
+
+# Recommended Usage
+
+- Use form_dev() for HTML forms
+- Use json_dev() for APIs
+- Use multipart_save_dev() for file uploads
+
+Keep max_bytes small in production.
+
diff --git a/docs/examples/graceful-shutdown.md b/docs/examples/graceful-shutdown.md
new file mode 100644
index 0000000..50a28d2
--- /dev/null
+++ b/docs/examples/graceful-shutdown.md
@@ -0,0 +1,197 @@
+# Graceful Shutdown (Vix.cpp)
+
+Graceful shutdown ensures your server:
+
+- Stops accepting new connections
+- Finishes in-flight requests
+- Releases resources safely
+- Shuts down cleanly without corruption
+
+Vix provides built-in support for safe shutdown using:
+
+- `run()`
+- `listen()`
+- `close()`
+- `wait()`
+- `request_stop_from_signal()`
+
+# 1. Basic Blocking Mode (run)
+
+The simplest mode:
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/", [](Request&, Response& res) {
+ res.json({"ok", true});
+ });
+
+ app.run(8080); // blocks until stopped
+}
+```
+
+Press `Ctrl+C` to stop the server.
+
+Vix will stop the server loop cleanly.
+
+# 2. Background Mode (listen + wait)
+
+Use this when you need more control.
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/", [](Request&, Response& res) {
+ res.send("Running...");
+ });
+
+ app.listen(8080, [](){
+ console.log("Server is running on http://localhost:8080");
+ });
+
+ app.wait(); // wait until shutdown
+}
+```
+
+# 3. Programmatic Shutdown
+
+You can stop the server from inside the application:
+
+``` cpp
+app.get("/stop", [&](Request&, Response& res) {
+ res.send("Stopping...");
+ app.close();
+});
+```
+
+`close()` requests graceful stop. Use `wait()` if running in background
+mode.
+
+# 4. Signal-Safe Shutdown (Production Pattern)
+
+For production systems, handle SIGINT / SIGTERM:
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+static App* g_app = nullptr;
+
+void signal_handler(int)
+{
+ if (g_app)
+ g_app->request_stop_from_signal();
+}
+
+int main()
+{
+ App app;
+ g_app = &app;
+
+ std::signal(SIGINT, signal_handler);
+ std::signal(SIGTERM, signal_handler);
+
+ app.get("/", [](Request&, Response& res) {
+ res.json({"ok", true});
+ });
+
+ app.run(8080);
+}
+```
+
+This is safe to call inside signal handlers.
+
+# 5. Shutdown Callback
+
+You can run cleanup logic:
+
+``` cpp
+app.set_shutdown_callback([]() {
+ vix::console.info("Server shutting down...");
+});
+```
+
+Useful for:
+
+- Closing database connections
+- Flushing logs
+- Stopping background workers
+- Releasing file handles
+
+# 6. Production Best Practices
+
+When building serious systems:
+
+- Use `listen()` + `wait()`
+- Install signal handlers
+- Avoid long blocking tasks
+- Ensure DB pools close cleanly
+- Stop background threads before exit
+
+# 7. Complete Production Example
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+static App* g_app = nullptr;
+
+void signal_handler(int)
+{
+ if (g_app)
+ g_app->request_stop_from_signal();
+}
+
+int main()
+{
+ App app;
+ g_app = &app;
+
+ std::signal(SIGINT, signal_handler);
+ std::signal(SIGTERM, signal_handler);
+
+ app.set_shutdown_callback([]() {
+ vix::console.info("Cleaning resources...");
+ });
+
+ app.get("/", [](Request&, Response& res) {
+ res.json({"message", "Graceful server running"});
+ });
+
+ app.listen(8080);
+ app.wait();
+
+ return 0;
+}
+```
+
+# Summary
+
+Graceful shutdown in Vix is:
+
+- Explicit
+- Signal-safe
+- Non-blocking
+- Production-ready
+
+Use:
+
+- `run()` for simple apps
+- `listen()` + `wait()` for production
+- `request_stop_from_signal()` for signal handling
+- `set_shutdown_callback()` for cleanup
+
diff --git a/docs/examples/group-advanced-patterns.md b/docs/examples/group-advanced-patterns.md
new file mode 100644
index 0000000..2bddfff
--- /dev/null
+++ b/docs/examples/group-advanced-patterns.md
@@ -0,0 +1,198 @@
+# Advanced Group Patterns
+
+This guide explains advanced architectural patterns using `group()` in Vix.cpp.
+
+These patterns are useful for:
+
+- Large APIs
+- Multi-tenant systems
+- Versioned APIs
+- Modular backend design
+- Enterprise-grade structure
+
+---
+
+## 1) Versioned API Pattern (v1 / v2)
+
+Structure:
+
+/api/v1/...
+/api/v2/...
+
+Example:
+
+```cpp
+App app;
+
+app.group("/api", [&](App::Group& api) {
+
+ api.group("/v1", [&](App::Group& v1) {
+ v1.get("/users", [](Request&, Response& res){
+ res.json({"version","v1","data","users list"});
+ });
+ });
+
+ api.group("/v2", [&](App::Group& v2) {
+ v2.get("/users", [](Request&, Response& res){
+ res.json({"version","v2","data","users list (new schema)"});
+ });
+ });
+
+});
+
+app.run(8080);
+```
+
+Why this is powerful:
+- Clean API evolution
+- Backward compatibility
+- Zero route collision
+
+---
+
+## 2) Multi‑Tenant Group Pattern
+
+Structure:
+
+/tenant/{id}/...
+
+You isolate logic per tenant.
+
+```cpp
+app.group("/tenant", [&](App::Group& tenant){
+
+ tenant.get("/{id}/dashboard", [](Request& req, Response& res){
+ auto id = req.param("id");
+ res.json({"tenant", id});
+ });
+
+});
+```
+
+Best practice:
+- Inject tenant ID into request state via middleware
+- Apply tenant‑level RBAC inside the group
+
+---
+
+## 3) Admin Isolation Pattern
+
+Separate public API from admin API.
+
+```cpp
+app.group("/admin", [&](App::Group& admin){
+
+ admin.use(middleware::app::jwt_auth("secret"));
+ admin.use(middleware::app::rbac_admin());
+
+ admin.get("/stats", [](Request&, Response& res){
+ res.json({"admin", true});
+ });
+
+});
+```
+
+Benefits:
+- All admin logic isolated
+- Security applied once
+- No repetition
+
+---
+
+## 4) Feature Module Mounting
+
+Simulate plugin-style mounting.
+
+```cpp
+void mountUsers(App::Group& api)
+{
+ api.group("/users", [&](App::Group& users){
+ users.get("/", [](Request&, Response& res){
+ res.send("Users list");
+ });
+ });
+}
+
+int main()
+{
+ App app;
+ auto api = app.group("/api");
+
+ mountUsers(api);
+
+ app.run(8080);
+}
+```
+
+This allows:
+- Clean separation by domain
+- Team-based development
+- Independent modules
+
+---
+
+## 5) Security Layer Stacking
+
+Order matters:
+
+Headers → CORS → Auth → RBAC → Rate limit
+
+```cpp
+api.use(middleware::app::security_headers_dev());
+api.use(middleware::app::cors_dev());
+api.use(middleware::app::jwt_auth("secret"));
+api.use(middleware::app::rbac_admin());
+api.use(middleware::app::rate_limit_dev(60, std::chrono::minutes(1)));
+```
+
+This ensures:
+- Preflight handled correctly
+- Auth before permission checks
+- Protection against abuse
+
+---
+
+## 6) Enterprise Folder Architecture
+
+Recommended structure:
+
+```
+/src
+ /api
+ v1_users.cpp
+ v1_orders.cpp
+ v2_users.cpp
+ /admin
+ dashboard.cpp
+ /modules
+ billing.cpp
+ analytics.cpp
+```
+
+Each file exports a mount function:
+
+```cpp
+void mount(App::Group& group);
+```
+
+Main app only wires modules together.
+
+---
+
+## Key Takeaway
+
+`group()` is not just route prefixing.
+
+It is an architectural boundary:
+
+- Security boundary
+- Version boundary
+- Tenant boundary
+- Domain boundary
+
+Mastering groups = building scalable backend systems.
+
+---
+
+Vix.cpp Advanced Routing Patterns.
+
diff --git a/docs/examples/group-api.md b/docs/examples/group-api.md
new file mode 100644
index 0000000..3e8d15a
--- /dev/null
+++ b/docs/examples/group-api.md
@@ -0,0 +1,177 @@
+# Route Groups Guide
+
+This guide explains how to use **route groups** in Vix.cpp.
+
+Groups let you:
+
+- Share a common URL prefix
+- Apply middleware to multiple routes at once
+- Organize APIs cleanly
+- Nest sub-groups (ex: /api/admin)
+
+---
+
+# 1) What is a Route Group?
+
+Instead of writing:
+```bash
+ /api/users
+ /api/products
+ /api/admin/dashboard
+```
+You define:
+```cpp
+ app.group("/api", ...)
+```
+And all routes inside automatically start with `/api`.
+
+---
+
+# 2) Basic Group Example
+
+```cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.group("/api", [&](App::Group &api)
+ {
+ api.get("/ping", [](Request&, Response& res){
+ res.json({"ok", true});
+ });
+ });
+
+ app.run(8080);
+}
+```
+
+Now:
+```bash
+ GET /api/ping
+```
+---
+
+# 3) Protecting a Route Inside a Group
+
+You can protect only one route:
+
+```cpp
+api.protect("/secure", middleware::app::api_key_dev("secret"));
+
+api.get("/secure", [](Request &req, Response &res)
+{
+ auto &k = req.state();
+ res.json({
+ "ok", true,
+ "api_key", k.value
+ });
+});
+```
+
+Test:
+```bash
+ curl -i http://localhost:8080/api/secure
+ curl -i -H "x-api-key: secret" http://localhost:8080/api/secure
+```
+---
+
+# 4) Nested Groups (Admin Example)
+
+Groups can be nested:
+
+```cpp
+api.group("/admin", [&](App::Group &admin)
+{
+ admin.use(middleware::app::jwt_auth("dev_secret"));
+ admin.use(middleware::app::rbac_admin());
+
+ admin.get("/dashboard", [](Request &req, Response &res)
+ {
+ auto &authz = req.state();
+ res.json({
+ "ok", true,
+ "sub", authz.subject,
+ "role", "admin"
+ });
+ });
+});
+```
+
+This creates:
+```bash
+ /api/admin/dashboard
+```
+All admin routes share the same middleware.
+
+---
+
+# 5) Builder Style Group
+
+You can also create a group first:
+
+```cpp
+auto api = app.group("/api");
+
+api.get("/public", [](Request &, Response &res)
+{
+ res.send("Public endpoint");
+});
+
+api.use(middleware::app::api_key_dev("secret"));
+
+api.get("/secure", [](Request &req, Response &res)
+{
+ auto &k = req.state();
+ res.json({"ok", true});
+});
+```
+
+Everything after `api.use(...)` is protected.
+
+---
+
+# 6) When to Use Groups
+
+Use groups when:
+
+- You build REST APIs
+- You want prefix-based protection
+- You need nested areas (admin, internal, public)
+- You want clean structure
+
+---
+
+# 7) Recommended Production Pattern
+
+Typical structure:
+```bash
+ /api
+ /public
+ /auth
+ /admin
+ /internal
+```
+Example:
+```cpp
+ app.group("/api", ...)
+ api.group("/admin", ...)
+ api.group("/auth", ...)
+```
+Keep middleware close to the group it protects.
+
+---
+
+# Summary
+
+Groups in Vix.cpp give you:
+
+- Clean URL organization
+- Middleware inheritance
+- Nested API design
+- Scalable backend structure
+
+They are essential for real-world applications.
+
diff --git a/docs/examples/group-vs-prefix.md b/docs/examples/group-vs-prefix.md
new file mode 100644
index 0000000..31467c9
--- /dev/null
+++ b/docs/examples/group-vs-prefix.md
@@ -0,0 +1,389 @@
+# Groups vs Prefix Middleware
+
+This guide explains the difference between:
+
+- Prefix middleware: `app.use("/api", mw)` and `middleware::app::install(app, "/api/", mw)`
+- Route groups: `app.group("/api", ...)` and `api.use(...)` / `api.protect(...)`
+
+Both are valid. The best choice depends on how you want to structure your routes.
+
+------------------------------------------------------------------------
+
+## 1) Mental model
+
+### Prefix middleware
+You attach middleware to a path prefix.
+
+- The middleware runs for every route whose path starts with that prefix.
+- You usually keep route registration at the top level `app.get(...)`, `app.post(...)`.
+
+Example:
+- Apply API key to everything under `/api/`
+
+### Groups
+A group is a scoped router builder.
+
+- You register routes inside a `group("/api", ...)` block.
+- You can install middleware once on the group and it applies to routes in that group.
+- You can nest groups to model your API structure.
+
+Example:
+- `/api` group contains public routes
+- `/api/admin` group contains protected admin routes
+
+------------------------------------------------------------------------
+
+## 2) Prefix middleware patterns
+
+### 2.1) Protect a whole prefix with `app.use()`
+This is the simplest prefix pattern.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Everything under /api is protected by API key
+ app.use("/api", middleware::app::api_key_dev("secret"));
+
+ app.get("/", [](Request&, Response& res){
+ res.send("home");
+ });
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({"ok", true, "msg", "pong"});
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/api/ping
+curl -i -H "x-api-key: secret" http://127.0.0.1:8080/api/ping
+```
+
+### 2.2) Protect a prefix with `middleware::app::install()`
+This is useful when you want to be explicit about routing helpers.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ middleware::app::install(app, "/api/", middleware::app::api_key_dev("secret"));
+
+ app.get("/api/users", [](Request&, Response& res){
+ res.json({"ok", true, "data", json::array({"u1","u2"})});
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### 2.3) Protect only one exact route
+Use `install_exact` if you want a single route protected, not the whole prefix.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+static vix::middleware::HttpMiddleware require_header(std::string h, std::string v)
+{
+ return [h = std::move(h), v = std::move(v)](Request& req, Response& res, vix::middleware::Next next)
+ {
+ if (req.header(h) != v)
+ {
+ res.status(401).json(vix::json::obj({"ok", false, "error", "unauthorized"}));
+ return;
+ }
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ middleware::app::install_exact(app, "/api/ping",
+ middleware::app::adapt(require_header("x-demo","1")));
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({"ok", true});
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+## 3) Group patterns
+
+### 3.1) Group with a protected sub-path using `protect()`
+This makes the intent very clear: only that sub-path is protected.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.group("/api", [&](App::Group& api)
+ {
+ api.get("/public", [](Request&, Response& res){
+ res.send("public");
+ });
+
+ api.protect("/secure", middleware::app::api_key_dev("secret"));
+
+ api.get("/secure", [](Request& req, Response& res){
+ auto& k = req.state();
+ res.json({"ok", true, "api_key", k.value});
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/api/public
+curl -i http://127.0.0.1:8080/api/secure
+curl -i -H "x-api-key: secret" http://127.0.0.1:8080/api/secure
+```
+
+### 3.2) Group builder style (return value)
+This is compact for simple APIs.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ auto api = app.group("/api");
+
+ api.get("/public", [](Request&, Response& res){
+ res.send("public");
+ });
+
+ api.use(middleware::app::api_key_dev("secret"));
+
+ api.get("/secure", [](Request&, Response& res){
+ res.json({"ok", true});
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### 3.3) Nested groups for clean structure
+This is where groups shine the most.
+
+- `/api` public stuff
+- `/api/admin` secured stuff
+- install JWT + RBAC once on the admin group
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.group("/api", [&](App::Group& api)
+ {
+ api.get("/health", [](Request&, Response& res){
+ res.json({"ok", true});
+ });
+
+ api.group("/admin", [&](App::Group& admin)
+ {
+ admin.use(middleware::app::jwt_auth("dev_secret"));
+ admin.use(middleware::app::rbac_admin());
+
+ admin.get("/dashboard", [](Request& req, Response& res)
+ {
+ auto& authz = req.state();
+ res.json({"ok", true, "sub", authz.subject, "role", "admin"});
+ });
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+------------------------------------------------------------------------
+
+## 4) When to use which
+
+### Use prefix middleware when
+- You already have a flat route list and want a quick protection layer.
+- You want one line like `app.use("/api", ...)` and keep everything else unchanged.
+- You want to attach cross cutting middleware globally or by prefix easily.
+
+### Use groups when
+- You want your route tree to look like your API structure.
+- You want nested scopes like `/api/v1`, `/api/admin`, `/api/internal`.
+- You want to install auth once at the right level, not repeat `use("/api/admin", ...)` patterns.
+- You want the code to read like: "inside admin, everything is protected".
+
+Practical rule:
+- Small apps: prefix is fastest to write.
+- Medium and large apps: groups scale better, especially with nesting.
+
+------------------------------------------------------------------------
+
+## 5) Common mistakes
+
+1) Mixing prefix strings inconsistently
+- `/api` vs `/api/` can lead to confusion. Pick one style and keep it consistent.
+
+2) Installing auth on the wrong level
+- If you do `app.use("/api", jwt)` you may protect routes that should be public.
+- With groups, you can isolate `admin.use(jwt)` only inside `/api/admin`.
+
+3) Duplicating middleware per route
+- Prefer a group or prefix so you do not repeat the same install code everywhere.
+
+------------------------------------------------------------------------
+
+# Complete Example (copy paste)
+
+This single file demonstrates both approaches side by side:
+- `/p/*` uses prefix protection
+- `/g/*` uses groups with protect and nested auth
+
+Save as: `group_vs_prefix_demo.cpp`
+
+```cpp
+#include
+#include
+#include
+
+using namespace vix;
+
+static void install_prefix_routes(App& app)
+{
+ // Prefix protected section
+ app.use("/p/secure", middleware::app::api_key_dev("secret"));
+
+ app.get("/p/public", [](Request&, Response& res){
+ res.send("prefix public");
+ });
+
+ app.get("/p/secure/who", [](Request& req, Response& res){
+ auto& k = req.state();
+ res.json({"ok", true, "mode", "prefix", "api_key", k.value});
+ });
+}
+
+static void install_group_routes(App& app)
+{
+ app.group("/g", [&](App::Group& g)
+ {
+ g.get("/public", [](Request&, Response& res){
+ res.send("group public");
+ });
+
+ g.protect("/secure", middleware::app::api_key_dev("secret"));
+
+ g.get("/secure/who", [](Request& req, Response& res){
+ auto& k = req.state();
+ res.json({"ok", true, "mode", "group", "api_key", k.value});
+ });
+
+ g.group("/admin", [&](App::Group& admin)
+ {
+ admin.use(middleware::app::jwt_auth("dev_secret"));
+ admin.use(middleware::app::rbac_admin());
+
+ admin.get("/dashboard", [](Request& req, Response& res)
+ {
+ auto& authz = req.state();
+ res.json({"ok", true, "mode", "group_admin", "sub", authz.subject});
+ });
+ });
+ });
+}
+
+int main()
+{
+ App app;
+
+ app.get("/", [](Request&, Response& res){
+ res.send(
+ "Try:\n"
+ " /p/public\n"
+ " /p/secure/who (needs x-api-key: secret)\n"
+ " /g/public\n"
+ " /g/secure/who (needs x-api-key: secret)\n"
+ " /g/admin/dashboard (needs JWT admin token)\n"
+ );
+ });
+
+ install_prefix_routes(app);
+ install_group_routes(app);
+
+ std::cout
+ << "Running:\n"
+ << " http://localhost:8080/\n"
+ << " http://localhost:8080/p/public\n"
+ << " http://localhost:8080/p/secure/who\n"
+ << " http://localhost:8080/g/public\n"
+ << " http://localhost:8080/g/secure/who\n"
+ << " http://localhost:8080/g/admin/dashboard\n\n"
+ << "API key: secret\n";
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Run:
+
+```bash
+vix run group_vs_prefix_demo.cpp
+```
+
+Quick tests:
+
+```bash
+curl -i http://localhost:8080/p/public
+curl -i http://localhost:8080/p/secure/who
+curl -i -H "x-api-key: secret" http://localhost:8080/p/secure/who
+
+curl -i http://localhost:8080/g/public
+curl -i http://localhost:8080/g/secure/who
+curl -i -H "x-api-key: secret" http://localhost:8080/g/secure/who
+```
+
diff --git a/docs/examples/headers.md b/docs/examples/headers.md
new file mode 100644
index 0000000..b9faf93
--- /dev/null
+++ b/docs/examples/headers.md
@@ -0,0 +1,287 @@
+# Security headers
+
+This guide shows how to add security headers in Vix.cpp, and how to combine them with CORS and CSRF safely.
+
+What you get from the preset:
+
+- X-Content-Type-Options: nosniff
+- X-Frame-Options: DENY (or equivalent)
+- Referrer-Policy
+- Permissions-Policy
+- Optional Strict-Transport-Security (HSTS) when enabled
+
+Notes:
+
+- Security headers are cheap and should usually be enabled for API responses.
+- Order matters when stacking middleware.
+- If you need cross-site cookies in browsers, you must use HTTPS and SameSite=None; Secure.
+
+---
+
+## 1) Minimal security headers on /api
+
+This is the smallest pattern: apply headers only under a prefix.
+
+```cpp
+/**
+ *
+ * @file security_headers_server.cpp - Security headers middleware example (Vix.cpp)
+ *
+ */
+// Run:
+// vix run security_headers_server.cpp
+//
+// Tests:
+// curl -i http://localhost:8080/api/ping
+// curl -i http://localhost:8080/
+
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Apply security headers only on /api
+ app.use("/api", middleware::app::security_headers_dev()); // HSTS is OFF by default
+
+ app.get("/api/ping", [](Request &, Response &res)
+ {
+ res.json({"ok", true, "message", "headers applied"});
+ });
+
+ // Public route (no forced headers)
+ app.get("/", [](Request &, Response &res)
+ {
+ res.send("public route");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+What to look for:
+
+```bash
+curl -i http://localhost:8080/api/ping
+```
+
+You should see the security headers in the response.
+
+---
+
+## 2) Realistic stack: Security headers + CORS + CSRF (same prefix)
+
+This is the common API pattern:
+
+1) Security headers first (so they also apply to errors)
+2) CORS second (so preflight and browser rules work)
+3) CSRF third (protect write operations)
+
+```cpp
+/**
+ *
+ * @file security_cors_csrf_headers_server.cpp - CORS + CSRF + Security Headers (Vix.cpp)
+ *
+ */
+// Run:
+// vix run security_cors_csrf_headers_server.cpp
+//
+// Quick tests are listed below.
+
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Apply on ALL /api/*
+ // Order matters: headers first, then CORS, then CSRF.
+ app.use("/api", middleware::app::security_headers_dev()); // HSTS off by default
+
+ app.use("/api", middleware::app::cors_dev({
+ "http://localhost:5173",
+ "http://0.0.0.0:5173",
+ "https://example.com"
+ }));
+
+ // CSRF expects: cookie "csrf_token" and header "x-csrf-token" by default
+ app.use("/api", middleware::app::csrf_dev("csrf_token", "x-csrf-token", false));
+
+ // Explicit OPTIONS routes (lets CORS middleware answer preflight)
+ app.options("/api/update", [](Request &, Response &res){ res.status(204).send(); });
+ app.options("/api/csrf", [](Request &, Response &res){ res.status(204).send(); });
+
+ // Routes
+ app.get("/api/csrf", [](Request &, Response &res)
+ {
+ // For cross-origin cookie in browsers:
+ // - Use HTTPS
+ // - SameSite=None; Secure
+ //
+ // For local dev over HTTP:
+ // - SameSite=Lax is fine, but cookie might not be sent cross-site.
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.header("X-Request-Id", "req_csrf_1");
+ res.json({"csrf_token", "abc"});
+ });
+
+ app.post("/api/update", [](Request &, Response &res)
+ {
+ res.header("X-Request-Id", "req_update_1");
+ res.json({"ok", true, "message", "CORS + CSRF + HEADERS"});
+ });
+
+ app.get("/", [](Request &, Response &res)
+ {
+ res.send("public route");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+### Terminal tests (curl)
+
+Preflight allowed (204 + CORS headers):
+
+```bash
+curl -i -X OPTIONS http://localhost:8080/api/update \
+ -H "Origin: https://example.com" \
+ -H "Access-Control-Request-Method: POST" \
+ -H "Access-Control-Request-Headers: Content-Type, X-CSRF-Token"
+```
+
+Preflight blocked (403):
+
+```bash
+curl -i -X OPTIONS http://localhost:8080/api/update \
+ -H "Origin: https://evil.com" \
+ -H "Access-Control-Request-Method: POST"
+```
+
+Get CSRF cookie (sets csrf_token=abc):
+
+```bash
+curl -i -c cookies.txt http://localhost:8080/api/csrf \
+ -H "Origin: https://example.com"
+```
+
+Fail: missing CSRF header:
+
+```bash
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update \
+ -H "Origin: https://example.com" \
+ -d "x=1"
+```
+
+Fail: wrong token:
+
+```bash
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update \
+ -H "Origin: https://example.com" \
+ -H "X-CSRF-Token: wrong" \
+ -d "x=1"
+```
+
+OK: correct token:
+
+```bash
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update \
+ -H "Origin: https://example.com" \
+ -H "X-CSRF-Token: abc" \
+ -d "x=1"
+```
+
+---
+
+## Common mistakes
+
+### 1) Wrong order
+
+If you put CSRF before CORS, browser preflight can fail in confusing ways.
+
+Recommended order on the same prefix:
+
+Security headers -> CORS -> CSRF -> Auth -> Rate limit -> Handlers
+
+### 2) Cross-site cookies on HTTP
+
+If your frontend is on another origin, browsers often require:
+
+- SameSite=None
+- Secure
+- HTTPS
+
+If you stay on HTTP locally, cookie behavior can differ from production.
+
+### 3) Forgetting OPTIONS routes
+
+Browsers send OPTIONS preflight requests. If you do not handle OPTIONS correctly,
+your CORS middleware might not return the expected headers.
+
+---
+
+## Full copy-paste example (recommended)
+
+This is the single-file version you can run immediately.
+
+Save as headers_stack_server.cpp:
+
+```cpp
+#include
+#include
+
+using namespace vix;
+
+static void register_routes(App &app)
+{
+ app.options("/api/csrf", [](Request &, Response &res){ res.status(204).send(); });
+ app.options("/api/update", [](Request &, Response &res){ res.status(204).send(); });
+
+ app.get("/api/csrf", [](Request &, Response &res)
+ {
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.json({"csrf_token", "abc"});
+ });
+
+ app.post("/api/update", [](Request &, Response &res)
+ {
+ res.json({"ok", true, "message", "protected update"});
+ });
+
+ app.get("/", [](Request &, Response &res)
+ {
+ res.send("public route");
+ });
+}
+
+int main()
+{
+ App app;
+
+ // Stack (order matters)
+ app.use("/api", middleware::app::security_headers_dev());
+ app.use("/api", middleware::app::cors_dev({"https://example.com"}));
+ app.use("/api", middleware::app::csrf_dev("csrf_token", "x-csrf-token", false));
+
+ register_routes(app);
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Run:
+
+```bash
+vix run headers_stack_server.cpp
+```
+
diff --git a/docs/examples/hello-http.md b/docs/examples/hello-http.md
new file mode 100644
index 0000000..4746cff
--- /dev/null
+++ b/docs/examples/hello-http.md
@@ -0,0 +1,298 @@
+# Hello HTTP
+
+This page shows **all the common "Hello" styles** in Vix.cpp, using the
+smallest possible snippets.
+
+Each snippet is a complete `main()` you can copy into a real file (for
+example `main.cpp`) and run.
+
+------------------------------------------------------------------------
+
+## 1) Hello as plain text (explicit send)
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/", [](Request&, Response& res)
+ {
+ res.send("Hello, Vix!");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://localhost:8080/
+```
+
+------------------------------------------------------------------------
+
+## 2) Hello as plain text (return style)
+
+If you return a value and you did not send anything explicitly, Vix
+auto-sends it.
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/txt", [](Request&, Response&)
+ {
+ return "Hello, Vix!";
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://localhost:8080/txt
+```
+
+------------------------------------------------------------------------
+
+## 3) Hello as JSON (explicit json)
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/json", [](Request&, Response& res)
+ {
+ res.json({
+ "message", "Hello",
+ "framework", "Vix.cpp",
+ "ok", true
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -s http://localhost:8080/json
+```
+
+------------------------------------------------------------------------
+
+## 4) Hello as JSON (return object style)
+
+``` cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/auto-json", [](Request&, Response&)
+ {
+ return vix::json::o(
+ "message", "Hello",
+ "mode", "auto-return",
+ "ok", true
+ );
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -s http://localhost:8080/auto-json
+```
+
+------------------------------------------------------------------------
+
+## 5) Hello with status code + JSON
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/created", [](Request&, Response& res)
+ {
+ res.status(201).json({
+ "message", "Created",
+ "ok", true
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://localhost:8080/created
+```
+
+------------------------------------------------------------------------
+
+## 6) Hello with headers + text
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/headers", [](Request&, Response& res)
+ {
+ res.header("X-Powered-By", "Vix.cpp");
+ res.send("Hello with headers");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://localhost:8080/headers
+```
+
+------------------------------------------------------------------------
+
+## 7) Hello with path param
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/hello/{name}", [](Request& req, Response& res)
+ {
+ const auto name = req.param("name");
+ res.json({
+ "message", "Hello",
+ "name", name
+ });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -s http://localhost:8080/hello/Ada
+```
+
+------------------------------------------------------------------------
+
+## 8) Hello with query param
+
+``` cpp
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/hello", [](Request& req, Response& res)
+ {
+ const auto name = req.query_value("name", "world");
+ res.send(std::string("Hello, ") + name + "!");
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i "http://localhost:8080/hello?name=Ada"
+```
+
+------------------------------------------------------------------------
+
+## 9) Mixing send + return (return gets ignored)
+
+If you already sent a response (send/json), any returned value is
+ignored.
+
+``` cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/mix", [](Request&, Response& res)
+ {
+ res.status(200).send("Hello (explicit)");
+
+ // Already sent -> ignored
+ return vix::json::o("ignored", true);
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+``` bash
+curl -i http://localhost:8080/mix
+```
+
+------------------------------------------------------------------------
+
+## What this teaches
+
+- The two styles: **explicit send** vs **auto-send return**
+- Text and JSON responses
+- Status codes and headers
+- Path and query parameters
+- The "already sent" rule
+
diff --git a/docs/examples/hello_routes.md b/docs/examples/hello_routes.md
deleted file mode 100644
index 607fbfc..0000000
--- a/docs/examples/hello_routes.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Example — hello_routes
-
-Minimal GET routes and path params.
-
-```cpp
-#include
-using namespace vix;
-
-int main()
-{
- App app;
-
- app.get("/hello", [](Request &, Response &res)
- { res.json({"message", "Hello, Vix!"}); });
-
- app.run(8080);
-}
-```
diff --git a/docs/examples/index.md b/docs/examples/index.md
new file mode 100644
index 0000000..c3c3943
--- /dev/null
+++ b/docs/examples/index.md
@@ -0,0 +1,642 @@
+# Auth and Middleware (Minimal Patterns)
+
+This page shows minimal auth and middleware patterns in Vix.cpp.
+
+Rule of this doc:
+- one concept
+- one minimal `main()`
+- a quick curl test
+
+## 1) API key middleware (protect one route)
+
+A public route plus a secure route that requires `x-api-key`.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.get("/public", [](Request&, Response& res){
+ res.json({ "ok", true, "scope", "public" });
+ });
+
+ // Install API key middleware only on this prefix
+ middleware::app::install(app, "/secure/", middleware::app::api_key_dev("dev_key_123"));
+
+ app.get("/secure/whoami", [](Request&, Response& res){
+ res.json({ "ok", true, "scope", "secure", "message", "API key accepted" });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/public
+curl -i http://127.0.0.1:8080/secure/whoami
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/secure/whoami
+```
+
+## 2) Prefix protection (protect all /api routes)
+
+Everything under `/api/` is protected.
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ middleware::app::install(app, "/api/", middleware::app::api_key_dev("dev_key_123"));
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({ "ok", true, "pong", true });
+ });
+
+ app.get("/api/users", [](Request&, Response& res){
+ res.json({ "ok", true, "data", json::array({ "u1", "u2" }) });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/api/ping
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/api/ping
+```
+
+## 3) Custom middleware (context style + RequestState)
+
+Store data into request state and read it in the handler.
+
+```cpp
+#include
+#include
+#include
+#include
+using namespace vix;
+
+struct RequestId { std::string value; };
+
+static long long now_ms()
+{
+ using namespace std::chrono;
+ return (long long)time_point_cast(system_clock::now())
+ .time_since_epoch().count();
+}
+
+static vix::middleware::MiddlewareFn mw_request_id()
+{
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ RequestId rid;
+ rid.value = std::to_string(now_ms());
+
+ ctx.req().emplace_state(rid);
+ ctx.res().header("x-request-id", rid.value);
+
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ app.use(vix::middleware::app::adapt_ctx(mw_request_id()));
+
+ app.get("/who", [](Request& req, Response& res){
+ res.json({ "ok", true, "request_id", req.state().value });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/who
+```
+
+## 4) Role gating (fake auth + admin only)
+
+Minimal RBAC style gate using headers for the demo.
+
+```cpp
+#include
+#include
+#include
+
+using namespace vix;
+namespace J = vix::json;
+
+struct AuthInfo
+{
+ bool authed{false};
+ std::string subject;
+ std::string role;
+};
+
+static vix::middleware::MiddlewareFn mw_fake_auth()
+{
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ AuthInfo a;
+ const std::string user = ctx.req().header("x-user");
+ const std::string role = ctx.req().header("x-role");
+
+ if (!user.empty())
+ {
+ a.authed = true;
+ a.subject = user;
+ a.role = role.empty() ? "user" : role;
+ }
+
+ ctx.req().emplace_state(a);
+ next();
+ };
+}
+
+static vix::middleware::MiddlewareFn mw_require_admin()
+{
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ if (!ctx.req().has_state_type() || !ctx.req().state().authed)
+ {
+ ctx.res().status(401).json(J::obj({ "ok", false, "error", "unauthorized" }));
+ return;
+ }
+
+ if (ctx.req().state().role != "admin")
+ {
+ ctx.res().status(403).json(J::obj({ "ok", false, "error", "forbidden", "hint", "admin required" }));
+ return;
+ }
+
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ app.use(vix::middleware::app::adapt_ctx(mw_fake_auth()));
+
+ vix::middleware::app::install(app, "/admin/", vix::middleware::app::adapt_ctx(mw_require_admin()));
+
+ app.get("/admin/stats", [](Request& req, Response& res)
+ {
+ const auto& a = req.state();
+ res.json({ "ok", true, "admin", true, "subject", a.subject });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/admin/stats
+curl -i -H "x-user: gaspard" http://127.0.0.1:8080/admin/stats
+curl -i -H "x-user: gaspard" -H "x-role: admin" http://127.0.0.1:8080/admin/stats
+```
+
+## 5) Legacy HttpMiddleware style (adapt)
+
+If you have an older middleware signature `(Request, Response, next)` you can adapt it.
+
+```cpp
+#include
+#include
+#include
+
+using namespace vix;
+namespace J = vix::json;
+
+static vix::middleware::HttpMiddleware require_header(std::string header, std::string expected)
+{
+ return [header = std::move(header), expected = std::move(expected)](Request& req, Response& res, vix::middleware::Next next)
+ {
+ const std::string got = req.header(header);
+ if (got != expected)
+ {
+ res.status(401).json(J::obj({
+ "ok", false,
+ "error", "unauthorized",
+ "required_header", header
+ }));
+ return;
+ }
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ vix::middleware::app::install_exact(
+ app,
+ "/api/ping",
+ vix::middleware::app::adapt(require_header("x-demo", "1"))
+ );
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({ "ok", true, "pong", true });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i http://127.0.0.1:8080/api/ping
+curl -i -H "x-demo: 1" http://127.0.0.1:8080/api/ping
+```
+
+## 6) Chaining middleware
+
+Apply multiple middlewares on the same prefix.
+
+```cpp
+#include
+#include
+#include
+
+using namespace vix;
+
+static vix::middleware::MiddlewareFn mw_mark()
+{
+ return [](vix::middleware::Context& ctx, vix::middleware::Next next)
+ {
+ ctx.res().header("x-mw", "on");
+ next();
+ };
+}
+
+int main()
+{
+ App app;
+
+ vix::middleware::app::install(
+ app,
+ "/secure/",
+ vix::middleware::app::chain(
+ vix::middleware::app::api_key_dev("dev_key_123"),
+ vix::middleware::app::adapt_ctx(mw_mark())
+ )
+ );
+
+ app.get("/secure/hello", [](Request&, Response& res){
+ res.json({ "ok", true, "message", "Hello secure" });
+ });
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Try:
+
+```bash
+curl -i -H "x-api-key: dev_key_123" http://127.0.0.1:8080/secure/hello
+```
+
+## What this teaches
+
+- Prefix install: protect a group of routes
+- Exact install: protect one route
+- Context middleware: state and headers
+- Legacy middleware adaptation
+- Basic RBAC style gating
+- Middleware chaining
+
+---
+
+# RBAC (Roles + Permissions) using JWT
+
+## What is RBAC
+
+RBAC means Role Based Access Control.
+
+You check:
+- roles (admin, user, editor)
+- permissions (products:write, orders:read)
+
+In Vix.cpp:
+- JWT extracts claims
+- RBAC builds `Authz`
+- `require_role()` and `require_perm()` enforce rules
+
+## Request flow
+
+1. Client sends JWT: `Authorization: Bearer `
+2. JWT middleware validates signature
+3. RBAC builds an `Authz` context
+4. Role and permission middlewares run
+5. Handler executes
+
+## Minimal RBAC pattern
+
+```cpp
+App app;
+
+vix::middleware::auth::JwtOptions jwt_opt{};
+jwt_opt.secret = "dev_secret";
+jwt_opt.verify_exp = false;
+
+vix::middleware::auth::RbacOptions rbac_opt{};
+rbac_opt.require_auth = true;
+rbac_opt.use_resolver = false;
+
+auto jwt_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::jwt(jwt_opt));
+auto ctx_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::rbac_context(rbac_opt));
+auto role_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::require_role("admin"));
+auto perm_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::require_perm("products:write"));
+
+app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path() == "/admin"; }, std::move(jwt_mw)));
+app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path() == "/admin"; }, std::move(ctx_mw)));
+app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path() == "/admin"; }, std::move(role_mw)));
+app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path() == "/admin"; }, std::move(perm_mw)));
+```
+
+## Reading `Authz` in a handler
+
+```cpp
+app.get("/admin", [](Request& req, Response& res){
+ auto& authz = req.state();
+ res.json({
+ "ok", true,
+ "sub", authz.subject,
+ "has_admin", authz.has_role("admin"),
+ "has_products_write", authz.has_perm("products:write")
+ });
+});
+```
+
+## Common statuses
+
+- 401: missing token, invalid token, invalid signature
+- 403: authenticated but missing required role or permission
+
+---
+
+# Rate limiting (minimal)
+
+Rate limiting protects your API from brute force, spam, and bursts.
+
+The model is a token bucket:
+- capacity: max burst
+- refill_per_sec: tokens per second
+- empty bucket returns 429
+
+## Minimal limiter on /api
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/api", middleware::app::rate_limit_custom_dev(5.0, 0.0));
+
+ app.get("/api/ping", [](Request& req, Response& res){
+ res.json({ "ok", true, "msg", "pong", "xff", req.header("x-forwarded-for") });
+ });
+
+ app.run(8080);
+}
+```
+
+Try:
+
+```bash
+for i in $(seq 1 6); do
+ echo "---- $i"
+ curl -i http://localhost:8080/api/ping
+done
+```
+
+---
+
+# CSRF (cookie + header)
+
+CSRF is relevant mainly for browser sessions using cookies.
+
+Vix default:
+- cookie: `csrf_token`
+- header: `x-csrf-token`
+
+## Minimal CSRF on /api
+
+```cpp
+#include
+#include
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ app.use("/api", middleware::app::csrf_dev());
+
+ app.get("/api/csrf", [](Request&, Response& res){
+ res.header("Set-Cookie", "csrf_token=abc; Path=/; SameSite=Lax");
+ res.json({ "csrf_token", "abc" });
+ });
+
+ app.post("/api/update", [](Request&, Response& res){
+ res.json({ "ok", true, "message", "CSRF passed" });
+ });
+
+ app.run(8080);
+}
+```
+
+Try:
+
+```bash
+curl -i -c cookies.txt http://localhost:8080/api/csrf
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -d "x=1"
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -H "x-csrf-token: wrong" -d "x=1"
+curl -i -b cookies.txt -X POST http://localhost:8080/api/update -H "x-csrf-token: abc" -d "x=1"
+```
+
+---
+
+# Complete example (Session + RBAC + Rate limit)
+
+This is a single file that shows:
+- cookie sessions for browser style auth
+- RBAC protected admin API using JWT
+- rate limit on /api
+
+Save as `security_complete.cpp`.
+
+```cpp
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace vix;
+
+// Example admin token (HS256, secret=dev_secret)
+// payload: {"sub":"user123","roles":["admin"],"perms":["products:write"]}
+static const std::string TOKEN_OK =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
+ "eyJzdWIiOiJ1c2VyMTIzIiwicm9sZXMiOlsiYWRtaW4iXSwicGVybXMiOlsicHJvZHVjdHM6d3JpdGUiXX0."
+ "w1y3nA2F1kq0oJ0x8wWc5wQx8zF4h2d6V7mYp0jYk3Q";
+
+static void install_session(App& app)
+{
+ app.use(middleware::app::session_dev(
+ "dev_session_secret",
+ "sid",
+ std::chrono::hours(24 * 7),
+ false,
+ "Lax",
+ true,
+ "/",
+ true
+ ));
+}
+
+static void install_api_security(App& app)
+{
+ // Rate limit all /api traffic
+ app.use("/api", middleware::app::rate_limit_dev(60, std::chrono::minutes(1)));
+
+ // JWT + RBAC only for /api/admin
+ vix::middleware::auth::JwtOptions jwt_opt{};
+ jwt_opt.secret = "dev_secret";
+ jwt_opt.verify_exp = false;
+
+ vix::middleware::auth::RbacOptions rbac_opt{};
+ rbac_opt.require_auth = true;
+ rbac_opt.use_resolver = false;
+
+ auto jwt_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::jwt(jwt_opt));
+ auto ctx_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::rbac_context(rbac_opt));
+ auto role_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::require_role("admin"));
+ auto perm_mw = vix::middleware::app::adapt_ctx(vix::middleware::auth::require_perm("products:write"));
+
+ app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path().rfind("/api/admin", 0) == 0; },
+ std::move(jwt_mw)
+ ));
+ app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path().rfind("/api/admin", 0) == 0; },
+ std::move(ctx_mw)
+ ));
+ app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path().rfind("/api/admin", 0) == 0; },
+ std::move(role_mw)
+ ));
+ app.use(vix::middleware::app::when(
+ [](const Request& r){ return r.path().rfind("/api/admin", 0) == 0; },
+ std::move(perm_mw)
+ ));
+}
+
+static void install_routes(App& app)
+{
+ app.get("/", [](Request&, Response& res){
+ res.send(
+ "Vix security complete example:\n"
+ " GET /session increments a counter stored in a signed cookie\n"
+ " GET /api/ping rate limited\n"
+ " GET /api/admin/stats requires JWT + role admin + perm products:write\n"
+ );
+ });
+
+ app.get("/session", [](Request& req, Response& res){
+ auto& s = req.state();
+ int n = s.get("n") ? std::stoi(*s.get("n")) : 0;
+ s.set("n", std::to_string(++n));
+ res.text("n=" + std::to_string(n));
+ });
+
+ app.get("/api/ping", [](Request&, Response& res){
+ res.json({ "ok", true, "pong", true });
+ });
+
+ app.get("/api/admin/stats", [](Request& req, Response& res){
+ auto& authz = req.state();
+ res.json({
+ "ok", true,
+ "sub", authz.subject,
+ "is_admin", authz.has_role("admin"),
+ "can_write_products", authz.has_perm("products:write")
+ });
+ });
+}
+
+int main()
+{
+ App app;
+
+ install_session(app);
+ install_api_security(app);
+ install_routes(app);
+
+ std::cout
+ << "Running:\n"
+ << " http://localhost:8080/\n"
+ << " http://localhost:8080/session\n"
+ << " http://localhost:8080/api/ping\n"
+ << " http://localhost:8080/api/admin/stats\n\n"
+ << "Admin token:\n " << TOKEN_OK << "\n\n"
+ << "Try:\n"
+ << " curl -i http://localhost:8080/session\n"
+ << " curl -i http://localhost:8080/api/ping\n"
+ << " curl -i http://localhost:8080/api/admin/stats\n"
+ << " curl -i -H \"Authorization: Bearer " << TOKEN_OK << "\" http://localhost:8080/api/admin/stats\n";
+
+ app.run(8080);
+ return 0;
+}
+```
+
+Run:
+
+```bash
+vix run security_complete.cpp
+```
+
+
diff --git a/docs/examples/ip-filter.md b/docs/examples/ip-filter.md
new file mode 100644
index 0000000..bd0737c
--- /dev/null
+++ b/docs/examples/ip-filter.md
@@ -0,0 +1,164 @@
+# IP Filter (Beginner Guide)
+
+Welcome 👋\
+This page explains how to protect routes using the **IP filter
+middleware** in Vix.cpp.
+
+With an IP filter you can:
+
+- allow only trusted IPs (allowlist)
+- block known bad IPs (denylist)
+- protect `/api/*` while keeping public routes open
+
+## What is an IP filter?
+
+An IP filter checks the client IP address **before** your route handler
+runs.
+
+If the IP is not allowed, the middleware stops the request early and
+returns:
+
+- **403 Forbidden**
+
+## Where does the server get the client IP?
+
+In real production deployments you usually have a reverse proxy (Nginx,
+cloud load balancer).\
+That proxy sends the client IP through headers such as:
+
+- `X-Forwarded-For` (most common)
+- `X-Real-IP`
+
+When `X-Forwarded-For` contains multiple values like:
+
+ client, proxy1, proxy2
+
+Vix uses the **first IP** (the real client).
+
+# 1) Minimal IP filter on `/api/*`
+
+This example:
+
+- keeps `/` public
+- protects `/api/hello`
+- allows only `10.0.0.1` and `127.0.0.1`
+- explicitly denies `9.9.9.9` (deny wins)
+
+``` cpp
+#include
+#include
+
+using namespace vix;
+
+int main()
+{
+ App app;
+
+ // Apply on /api/*
+ app.use("/api", middleware::app::ip_filter_allow_deny_dev(
+ "x-forwarded-for",
+ {"10.0.0.1", "127.0.0.1"}, // allow
+ {"9.9.9.9"}, // deny (priority)
+ true // fallback to x-real-ip, etc.
+ ));
+
+ app.get("/", [](Request &, Response &res) {
+ res.send("public route");
+ });
+
+ app.get("/api/hello", [](Request &req, Response &res) {
+ res.json({
+ "ok", true,
+ "message", "Hello from /api/hello",
+ "x_forwarded_for", req.header("x-forwarded-for"),
+ "x_real_ip", req.header("x-real-ip")
+ });
+ });
+
+ app.run(8080);
+}
+```
+
+# 2) Test with curl
+
+Start:
+
+``` bash
+vix run ip_filter_server.cpp
+```
+
+Public route (no middleware):
+
+``` bash
+curl -i http://localhost:8080/
+```
+
+Allowed IP:
+
+``` bash
+curl -i http://localhost:8080/api/hello -H "X-Forwarded-For: 10.0.0.1"
+```
+
+Not allowed (not in allow list):
+
+``` bash
+curl -i http://localhost:8080/api/hello -H "X-Forwarded-For: 1.2.3.4"
+```
+
+Denied explicitly (deny wins):
+
+``` bash
+curl -i http://localhost:8080/api/hello -H "X-Forwarded-For: 9.9.9.9"
+```
+
+X-Forwarded-For chain:
+
+``` bash
+curl -i http://localhost:8080/api/hello -H "X-Forwarded-For: 10.0.0.1, 127.0.0.1"
+```
+
+# 3) Common beginner mistakes
+
+## Mistake 1: trusting X-Forwarded-For directly on the internet
+
+If your server is directly exposed (no proxy), attackers can forge
+headers.
+
+Production rule:
+
+- only trust `X-Forwarded-For` if it comes from a trusted proxy
+- otherwise use remote address (socket IP) or `X-Real-IP` set by your
+ proxy
+
+## Mistake 2: forgetting that allowlist blocks everything else
+
+If you configure an allow list, any IP not in it is blocked.
+
+## Mistake 3: wrong header name
+
+Your middleware reads the header you give it.
+
+If you configured:
+
+- `"x-forwarded-for"`
+
+Then your requests must send:
+
+- `X-Forwarded-For: ...`
+
+Header names are case-insensitive in HTTP, but spelling must match.
+
+# 4) When to use allow, deny, or both
+
+- **Allow only**: admin dashboards, internal APIs, webhooks from known
+ providers
+- **Deny only**: block a list of abusive IPs
+- **Allow + deny**: allow trusted range but always block specific
+ offenders (deny priority)
+
+# Summary
+
+- Install IP filter on a prefix: `app.use("/api", ...)`
+- Use allowlist for strict protection
+- Use denylist for explicit blocks
+- Prefer running behind a proxy that sets `X-Forwarded-For` safely
diff --git a/docs/examples/json-basics.md b/docs/examples/json-basics.md
new file mode 100644
index 0000000..4bac1b4
--- /dev/null
+++ b/docs/examples/json-basics.md
@@ -0,0 +1,448 @@
+# Simple JSON Model Guide
+
+`vix/json/Simple.hpp` defines a minimal JSON-like value model for lightweight internal Vix APIs.
+
+It is:
+- header-only
+- dependency-free (does not depend on `nlohmann::json`)
+- designed for structured data exchange between modules without parsing text
+
+If you want to parse or serialize JSON text, use the regular Vix JSON helpers based on `nlohmann::json`.
+
+---
+
+## Include
+
+```cpp
+#include
+using namespace vix::json;
+```
+
+---
+
+## What is Simple?
+
+Simple is a tiny DOM-like value system that can represent:
+
+- null
+- bool
+- integer (stored as `int64`)
+- floating point (stored as `double`)
+- string
+- arrays (`array_t`)
+- objects (`kvs`)
+
+It is meant for:
+- internal payloads between modules
+- in-memory structured data
+- building small trees of values for adapters and bridges
+
+It is not meant for:
+- large untrusted JSON text parsing
+- full JSON schema validation
+- streaming or incremental parsing
+
+---
+
+## Core types
+
+### `token`
+
+A `token` is a tagged variant that stores either:
+- a primitive value, or
+- a `shared_ptr` / `shared_ptr` for recursion
+
+Internally:
+
+```cpp
+using value_t = std::variant<
+ std::monostate, // null
+ bool, // boolean
+ std::int64_t, // integer
+ double, // floating point
+ std::string, // string
+ std::shared_ptr, // array
+ std::shared_ptr