feat: implement MoloApp plans 01-15 with integration

Full C++23 framework tree: runtime, observability, security,
data, app, realtime, supervisor, clients, CLI, example plus
enterprise tenancy, audit, operability, governance,
supplychain. Postgres via docker compose for tests.
This commit is contained in:
2026-10-23 18:20:04 +02:00
parent 54068f1953
commit 3c4334cec9
1068 changed files with 100899 additions and 2 deletions
+53
View File
@@ -0,0 +1,53 @@
#include "App.hpp"
namespace molo::example::app {
std::shared_ptr<fw::Application> build_application(Services& services) {
seed_services(services);
load_templates(services);
load_embedded(services);
auto app = std::make_shared<fw::Application>();
app->use(fw::MiddlewareSlot::Errors, fw::errors_middleware());
app->use(fw::MiddlewareSlot::Observability, fw::request_id_middleware());
app->use(fw::MiddlewareSlot::SessionAuth,
[](fw::Request req, fw::Next next) -> fw::Response {
fw::Response res = next(std::move(req));
res.headers.set("X-Frame-Options", "DENY");
res.headers.set("X-Content-Type-Options", "nosniff");
return res;
});
fw::Router index;
register_index(index, services);
app->include_router("", index);
fw::Router routing;
register_routing_demo(routing, services);
app->include_router("/routing", routing, "routing.");
fw::Router data;
register_data_demo(data, services);
app->include_router("", data);
fw::Router security;
register_security_demo(security, services);
app->include_router("", security);
fw::Router formats;
register_formats_demo(formats, services);
app->include_router("", formats);
fw::Router realtime;
register_realtime_demo(realtime, services);
app->include_router("", realtime);
fw::Router ops;
register_ops_demo(ops, services);
app->include_router("", ops);
register_chain_demo(app, services);
return app;
}
} // namespace molo::example::app
+69
View File
@@ -0,0 +1,69 @@
#pragma once
// Demo application assembly: shared Services (the DI skeleton), the root
// Application with middleware, routers, and mounted sub-applications.
// Gap: real molo::di::Container and plugin registry in 05-request-routing.md.
#include <map>
#include <memory>
#include <string>
#include "../fw/App.hpp"
#include "../fw/Data.hpp"
#include "../fw/Jobs.hpp"
#include "../fw/Kv.hpp"
#include "../fw/Net.hpp"
#include "../fw/Observ.hpp"
#include "../fw/Templates.hpp"
namespace molo::example::app {
struct Services {
std::shared_ptr<fw::KvStore> kv = std::make_shared<fw::KvStore>();
std::shared_ptr<fw::Cache> cache = std::make_shared<fw::Cache>();
std::shared_ptr<fw::Pubsub> pubsub = std::make_shared<fw::Pubsub>();
std::shared_ptr<fw::EventBus> events = std::make_shared<fw::EventBus>();
std::shared_ptr<fw::Metrics> metrics = std::make_shared<fw::Metrics>();
std::shared_ptr<fw::Telemetry> telemetry =
std::make_shared<fw::Telemetry>();
std::shared_ptr<fw::SessionStore> sessions =
std::make_shared<fw::SessionStore>();
std::shared_ptr<fw::Auth> auth = std::make_shared<fw::Auth>();
std::shared_ptr<fw::OrmDb> sqlite =
std::make_shared<fw::OrmDb>(fw::OrmBackend::Sqlite);
std::shared_ptr<fw::OrmDb> postgres =
std::make_shared<fw::OrmDb>(fw::OrmBackend::Postgres);
std::shared_ptr<fw::UploadStore> uploads =
std::make_shared<fw::UploadStore>();
std::shared_ptr<fw::WebdavStore> webdav =
std::make_shared<fw::WebdavStore>();
std::shared_ptr<fw::Supervisor> supervisor =
std::make_shared<fw::Supervisor>();
std::shared_ptr<fw::TaskQueue> tasks = std::make_shared<fw::TaskQueue>();
std::shared_ptr<fw::ReplicationLog> repl =
std::make_shared<fw::ReplicationLog>();
std::shared_ptr<fw::OpenApi> openapi = std::make_shared<fw::OpenApi>();
std::shared_ptr<fw::Environment> templates =
std::make_shared<fw::Environment>();
std::map<std::string, std::string> embedded;
std::string static_root = "example/static";
std::string cookie_secret = "living-example-secret";
};
std::shared_ptr<fw::Application> build_application(Services& services);
void register_index(fw::Router& router, Services& services);
void register_routing_demo(fw::Router& router, Services& services);
void register_chain_demo(std::shared_ptr<fw::Application> app,
Services& services);
void register_data_demo(fw::Router& router, Services& services);
void register_security_demo(fw::Router& router, Services& services);
void register_formats_demo(fw::Router& router, Services& services);
void register_realtime_demo(fw::Router& router, Services& services);
void register_ops_demo(fw::Router& router, Services& services);
void load_templates(Services& services);
void load_embedded(Services& services);
void seed_services(Services& services);
} // namespace molo::example::app
+141
View File
@@ -0,0 +1,141 @@
#include "App.hpp"
#include "../fw/Http.hpp"
#include "../fw/Router.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
namespace {
fw::OrmDb* pick_db(Services& services, const fw::Request& req) {
if (fw::parse_backend(req.query_or("backend", "sqlite")) ==
fw::OrmBackend::Postgres)
return services.postgres.get();
return services.sqlite.get();
}
std::string rows_json(const std::vector<fw::OrmRow>& rows) {
std::string out = "[";
bool first = true;
for (const auto& r : rows) {
if (!first) out += ",";
first = false;
out += "{";
bool fc = true;
for (const auto& [k, v] : r.columns) {
if (!fc) out += ",";
fc = false;
out += "\"" + fw::json_escape(k) + "\":\"" + fw::json_escape(v) + "\"";
}
out += "}";
}
return out + "]";
}
} // namespace
void register_data_demo(fw::Router& router, Services& services) {
fw::OrmDb* sqlite = services.sqlite.get();
fw::OrmDb* postgres = services.postgres.get();
fw::KvStore* kv = services.kv.get();
fw::Cache* cache = services.cache.get();
fw::Pubsub* pubsub = services.pubsub.get();
router.get("/orm/users", "orm-users", [sqlite, postgres](fw::Request req) {
fw::OrmDb* db = req.query_or("backend", "sqlite") == "postgres" ? postgres
: sqlite;
fw::OrmResult res = db->select_all("users");
std::string body = "{\"backend\":\"" + fw::backend_name(db->backend()) +
"\",\"healed\":" + (res.healed ? "true" : "false") +
",\"note\":\"" + fw::json_escape(res.healed_note) +
"\",\"rows\":" + rows_json(res.rows) + "}";
return fw::JsonResponse(body, 200);
});
router.post("/orm/users", "orm-users-post",
[sqlite, postgres](fw::Request req) {
fw::OrmDb* db = req.query_or("backend", "sqlite") == "postgres"
? postgres
: sqlite;
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
fw::OrmResult res = db->insert("users", input);
if (!res.ok)
return fw::JsonResponse("{\"error\":\"store full\"}", 500);
std::string body =
"{\"backend\":\"" + fw::backend_name(db->backend()) +
"\",\"healed\":" + (res.healed ? "true" : "false") +
",\"note\":\"" + fw::json_escape(res.healed_note) +
"\",\"rows\":" + rows_json(res.rows) + "}";
return fw::JsonResponse(body, 201);
});
router.get("/kv/items", "kv-get", [kv](fw::Request req) {
std::string key = req.query_or("key", "");
if (key.empty()) return fw::JsonResponse("{\"error\":\"key required\"}", 400);
std::string value;
if (!kv->get(key, value))
return fw::JsonResponse("{\"error\":\"not found\"}", 404);
return fw::JsonResponse("{\"key\":\"" + fw::json_escape(key) +
"\",\"value\":\"" + fw::json_escape(value) +
"\"}",
200);
});
router.post("/kv/items", "kv-set", [kv](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
if (!input.count("key") || !input.count("value"))
return fw::JsonResponse("{\"error\":\"key and value required\"}", 400);
if (!kv->set(input["key"], input["value"]))
return fw::JsonResponse("{\"error\":\"store full\"}", 500);
return fw::JsonResponse("{\"stored\":\"" + fw::json_escape(input["key"]) +
"\"}",
201);
});
router.get("/cache/lookup", "cache", [cache](fw::Request req) {
std::string key = req.query_or("key", "demo");
std::string value;
bool hit = cache->lookup(key, value, 1000);
if (!hit) {
value = "computed-for-" + key;
cache->put(key, value, 60, 1000);
return fw::JsonResponse(
"{\"key\":\"" + fw::json_escape(key) + "\",\"hit\":false,\"value\":\"" +
fw::json_escape(value) + "\"}",
200);
}
return fw::JsonResponse(
"{\"key\":\"" + fw::json_escape(key) + "\",\"hit\":true,\"value\":\"" +
fw::json_escape(value) + "\"}",
200);
});
router.post("/pubsub/publish", "pubsub", [pubsub](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string topic = input.count("topic") ? input["topic"] : "news";
std::string message = input.count("message") ? input["message"] : "hello";
std::size_t delivered = pubsub->publish(topic, message);
return fw::JsonResponse("{\"topic\":\"" + fw::json_escape(topic) +
"\",\"delivered\":" +
std::to_string(delivered) + "}",
200);
});
router.get("/pubsub/publish", "pubsub-history", [pubsub](fw::Request req) {
std::string topic = req.query_or("topic", "news");
auto hist = pubsub->history(topic);
std::string body = "{\"topic\":\"" + fw::json_escape(topic) +
"\",\"history\":[";
bool first = true;
for (const auto& m : hist) {
if (!first) body += ",";
first = false;
body += "\"" + fw::json_escape(m) + "\"";
}
return fw::JsonResponse(body + "]}", 200);
});
(void)pick_db;
}
} // namespace molo::example::app
+19
View File
@@ -0,0 +1,19 @@
#include "App.hpp"
namespace molo::example::app {
namespace {
// Byte-identical reproducible bundle. Production bundles are generated by
// the asset embedder CLI (09-cli-ops.md); this hand-written copy proves the
// serving path with sorted names and no timestamps.
} // namespace
void load_embedded(Services& services) {
services.embedded["/app.css"] =
"/* embedded bundle */\nbody{font-family:sans-serif}\n";
services.embedded["/hello.txt"] = "hello from embedded assets\n";
}
} // namespace molo::example::app
+131
View File
@@ -0,0 +1,131 @@
#include "App.hpp"
#include "../fw/Negotiate.hpp"
#include "../fw/Router.hpp"
#include "../fw/StaticFiles.hpp"
#include "../fw/Templates.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
namespace {
fw::Model contact_model() {
return fw::Model(
{{"name", fw::FieldType::String, true, 1, 80, 0, 0, false, ""},
{"email", fw::FieldType::Email, true, 3, 120, 0, 0, false, ""},
{"message", fw::FieldType::String, true, 1, 2000, 0, 0, false, ""}});
}
fw::Model user_model() {
fw::Field age{"age", fw::FieldType::Integer, true, 0, 0, 0, 150, true, ""};
return fw::Model(
{{"username", fw::FieldType::String, true, 3, 40, 0, 0, false, ""},
{"email", fw::FieldType::Email, true, 3, 120, 0, 0, false, ""},
age});
}
} // namespace
void register_formats_demo(fw::Router& router, Services& services) {
fw::Environment* env = services.templates.get();
std::map<std::string, std::string> embedded = services.embedded;
std::string static_root = services.static_root;
router.get("/templates/page", "template-page", [env](fw::Request req) {
(void)req;
fw::TemplateCtx ctx;
ctx["title"] = std::string("Templates");
ctx["heading"] = std::string("Template demo");
ctx["author"] = std::string("ada");
ctx["snippet"] = std::string("<b>bold</b>");
fw::TemplateList items;
items.push_back({{"name", "extends"}, {"kind", "inheritance"}});
items.push_back({{"name", "include"}, {"kind", "partial"}});
items.push_back({{"name", "for"}, {"kind", "loop"}});
ctx["items"] = items;
return fw::Response(200, env->render("page.html", ctx),
"text/html; charset=utf-8");
});
router.get("/formats/data", "formats", [](fw::Request req) {
std::vector<std::string> offers = {"application/json", "application/xml",
"text/html", "text/plain"};
std::string pick =
fw::negotiate(req.headers.get("Accept"), offers);
if (pick == "application/json")
return fw::Response(
200, "{\"format\":\"json\",\"value\":42}", "application/json");
if (pick == "application/xml")
return fw::Response(200, "<data><value>42</value></data>",
"application/xml");
if (pick == "text/html")
return fw::Response(200, "<p>value: 42</p>",
"text/html; charset=utf-8");
return fw::Response(200, "value: 42", "text/plain; charset=utf-8");
});
router.get("/forms/contact", "contact-get", [env](fw::Request req) {
(void)req;
fw::TemplateCtx ctx;
ctx["title"] = std::string("Contact");
ctx["posted"] = std::string("");
ctx["name"] = std::string("");
ctx["email"] = std::string("");
ctx["message"] = std::string("");
return fw::Response(200, env->render("contact.html", ctx),
"text/html; charset=utf-8");
});
router.post("/forms/contact", "contact-post", [env](fw::Request req) {
fw::Form form(contact_model());
fw::TemplateCtx ctx;
ctx["title"] = std::string("Contact");
try {
auto clean = form.bind(req);
ctx["posted"] = std::string("true");
ctx["name"] = clean["name"];
ctx["email"] = clean["email"];
ctx["message"] = clean["message"];
} catch (const fw::ValidationError& e) {
ctx["posted"] = std::string("");
auto input = fw::parse_form(req.body);
ctx["name"] = input.count("name") ? input["name"] : "";
ctx["email"] = input.count("email") ? input["email"] : "";
ctx["message"] = input.count("message") ? input["message"] : "";
ctx["error"] = e.to_json();
return fw::Response(422, env->render("contact.html", ctx),
"text/html; charset=utf-8");
}
return fw::Response(200, env->render("contact.html", ctx),
"text/html; charset=utf-8");
});
router.post("/validate/user", "validate-user", [](fw::Request req) {
fw::Model model = user_model();
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
try {
auto clean = model.validate(input);
return fw::JsonResponse(
"{\"ok\":true,\"username\":\"" +
fw::json_escape(clean["username"]) + "\"}",
200);
} catch (const fw::ValidationError& e) {
return fw::JsonResponse(e.to_json(), 422);
}
});
router.get("/static/{name}", "static", [static_root](fw::Request req) {
return fw::serve_disk_file(static_root, req.param_or("name", ""));
});
router.get("/embedded/{name}", "embedded", [embedded](fw::Request req) {
return fw::serve_embedded(embedded, req.param_or("name", ""));
});
router.get("/redirect/here", "redirect", [](fw::Request req) {
bool permanent = req.query_or("mode", "temp") == "perm";
return fw::Response(fw::RedirectResponse("/health", permanent));
});
}
} // namespace molo::example::app
+75
View File
@@ -0,0 +1,75 @@
#include "App.hpp"
#include "../fw/Http.hpp"
#include "../fw/Router.hpp"
#include "../fw/Templates.hpp"
namespace molo::example::app {
namespace {
const char* kFeatures[][2] = {
{"routing", "/routing/hello/world"},
{"views", "/views/greet"},
{"routers", "/routers/nested/deep"},
{"chaining", "/app1/app1/app1/whoami"},
{"orm-sqlite", "/orm/users?backend=sqlite"},
{"orm-postgres", "/orm/users?backend=postgres"},
{"auth", "/auth/me"},
{"sessions", "/sessions/counter"},
{"forms", "/forms/contact"},
{"validation", "/validate/user"},
{"templates", "/templates/page"},
{"formats", "/formats/data"},
{"static", "/static/app.css"},
{"embedded", "/embedded/hello.txt"},
{"streaming", "/streaming/feed"},
{"passthrough", "/streaming/passthrough"},
{"websocket", "/ws/chat"},
{"socketio", "/socketio/rooms"},
{"sse", "/sse/events"},
{"pubsub", "/pubsub/publish"},
{"events", "/events/fire"},
{"metrics", "/metrics/counters"},
{"telemetry", "/telemetry/trace"},
{"kv", "/kv/items"},
{"cache", "/cache/lookup"},
{"uploads", "/uploads/file"},
{"webdav", "/webdav/files/"},
{"replication", "/replication/state"},
{"tasks", "/supervisor/tasks"},
{"workers", "/supervisor/workers"},
{"restclient", "/restclient/self"},
{"openapi", "/openapi.json"},
{"docs", "/docs"},
{"ai", "/cli/ai"},
{"workflow", "/workflow/release"},
{"redirect", "/redirect/here"},
{"health", "/health"},
};
} // namespace
void register_index(fw::Router& router, Services& services) {
fw::Environment* env = services.templates.get();
router.get("/", "index", [env](fw::Request req) {
fw::TemplateCtx ctx;
ctx["title"] = std::string("MoloApp living example");
ctx["show_matrix"] = std::string("true");
fw::TemplateList rows;
for (const auto& [feature, route] : kFeatures) {
rows.push_back({{"feature", feature}, {"route", route}});
}
ctx["matrix"] = rows;
(void)req;
return fw::Response(200, env->render("index.html", ctx),
"text/html; charset=utf-8");
});
router.get("/health", "health", [](fw::Request req) {
(void)req;
return fw::JsonResponse(
"{\"status\":\"ok\",\"tls\":\"stub-no-wolfssl\"}", 200);
});
}
} // namespace molo::example::app
+224
View File
@@ -0,0 +1,224 @@
#include "App.hpp"
#include "../fw/Jobs.hpp"
#include "../fw/Net.hpp"
#include "../fw/Observ.hpp"
#include "../fw/Router.hpp"
#include "../fw/Templates.hpp"
#include "../fw/Validate.hpp"
#include "../fw/Workflow.hpp"
namespace molo::example::app {
void register_ops_demo(fw::Router& router, Services& services) {
fw::EventBus* events = services.events.get();
fw::Metrics* metrics = services.metrics.get();
fw::Telemetry* telemetry = services.telemetry.get();
fw::Supervisor* supervisor = services.supervisor.get();
fw::TaskQueue* tasks = services.tasks.get();
fw::ReplicationLog* repl = services.repl.get();
fw::OpenApi* openapi = services.openapi.get();
fw::Environment* env = services.templates.get();
router.post("/events/fire", "events-fire", [events](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string type = input.count("type") ? input["type"] : "demo.ping";
std::string payload =
input.count("payload") ? input["payload"] : "ping";
events->emit({type, payload, req.correlation_id});
return fw::JsonResponse(
"{\"fired\":\"" + fw::json_escape(type) + "\"}", 200);
});
router.get("/events/fire", "events-list", [events](fw::Request req) {
(void)req;
auto delivered = events->delivered();
std::string body = "{\"delivered\":[";
bool first = true;
for (const auto& e : delivered) {
if (!first) body += ",";
first = false;
body += "{\"type\":\"" + fw::json_escape(e.type) + "\",\"payload\":\"" +
fw::json_escape(e.payload) + "\"}";
}
return fw::JsonResponse(body + "]}", 200);
});
router.get("/metrics/counters", "metrics",
[metrics](fw::Request req) {
(void)req;
metrics->inc("example.page.views");
fw::Response res(200, metrics->render_prometheus(),
"text/plain; version=0.0.4");
return res;
});
router.get("/telemetry/trace", "telemetry",
[telemetry](fw::Request req) {
fw::Span span =
telemetry->start_span("demo", req.correlation_id);
telemetry->finish_span(span);
return fw::JsonResponse(
"{\"trace\":\"" + fw::json_escape(span.trace_id) +
"\",\"span\":\"" + fw::json_escape(span.span_id) +
"\",\"correlation\":\"" +
fw::json_escape(req.correlation_id) + "\"}",
200);
});
router.get("/replication/state", "repl", [repl](fw::Request req) {
unsigned long since = 0;
try {
since = (unsigned long)std::stoul(req.query_or("since", "0"));
} catch (...) {
since = 0;
}
auto entries = repl->since(since);
std::string body = "{\"latest\":" + std::to_string(repl->latest()) +
",\"entries\":[";
bool first = true;
for (const auto& e : entries) {
if (!first) body += ",";
first = false;
body += "{\"seq\":" + std::to_string(e.seq) + ",\"object\":\"" +
fw::json_escape(e.object) + "\",\"resolution\":\"" +
fw::json_escape(e.resolution) + "\"}";
}
return fw::JsonResponse(body + "]}", 200);
});
router.post("/replication/state", "repl-append", [repl](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string object = input.count("object") ? input["object"] : "doc-1";
std::string data = input.count("data") ? input["data"] : "{}";
fw::ReplEntry e = repl->append(object, data);
return fw::JsonResponse("{\"seq\":" + std::to_string(e.seq) +
",\"resolution\":\"" +
fw::json_escape(e.resolution) + "\"}",
201);
});
router.get("/supervisor/tasks", "tasks-list", [tasks](fw::Request req) {
(void)req;
std::string body = "{\"tasks\":[";
bool first = true;
for (const auto& t : tasks->list()) {
if (!first) body += ",";
first = false;
body += "{\"id\":\"" + fw::json_escape(t.id) + "\",\"state\":\"" +
fw::json_escape(t.state) + "\"}";
}
return fw::JsonResponse(body + "]}", 200);
});
router.post("/supervisor/tasks", "tasks-enqueue", [tasks](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string kind = input.count("kind") ? input["kind"] : "email";
std::string payload =
input.count("payload") ? input["payload"] : "{}";
std::string id = tasks->enqueue(kind, payload, 0);
if (id.empty()) return fw::JsonResponse("{\"error\":\"queue full\"}", 500);
return fw::JsonResponse("{\"id\":\"" + fw::json_escape(id) + "\"}", 201);
});
router.get("/supervisor/workers", "workers",
[supervisor](fw::Request req) {
(void)req;
std::string body = "{\"workers\":[";
bool first = true;
for (const auto& w : supervisor->status()) {
if (!first) body += ",";
first = false;
body += "{\"name\":\"" + fw::json_escape(w.name) +
"\",\"running\":" +
(w.running ? "true" : "false") + ",\"restarts\":" +
std::to_string(w.restarts) + "}";
}
return fw::JsonResponse(body + "]}", 200);
});
router.get("/restclient/self", "restclient", [](fw::Request req) {
(void)req;
fw::RestClient client([](fw::Request r) {
(void)r;
return fw::JsonResponse("{\"status\":\"ok\"}", 200);
});
fw::Response upstream = client.get("/health");
return fw::JsonResponse(
"{\"self_call\":" + std::to_string(upstream.status) + "}", 200);
});
openapi->add("/health", "get", "health probe");
openapi->add("/orm/users", "get", "list users");
openapi->add("/validate/user", "post", "validate user model");
router.get("/openapi.json", "openapi", [openapi](fw::Request req) {
(void)req;
return fw::Response(200, openapi->to_json(), "application/json");
});
router.get("/docs", "docs", [env, openapi](fw::Request req) {
(void)req;
(void)openapi;
fw::TemplateCtx ctx;
ctx["title"] = std::string("API docs");
fw::TemplateList rows;
rows.push_back({{"method", "GET"},
{"path", "/health"},
{"summary", "health probe"}});
rows.push_back({{"method", "GET"},
{"path", "/orm/users"},
{"summary", "list users"}});
rows.push_back({{"method", "POST"},
{"path", "/validate/user"},
{"summary", "validate user model"}});
ctx["routes"] = rows;
return fw::Response(200, env->render("docs.html", ctx),
"text/html; charset=utf-8");
});
router.get("/cli/ai", "ai", [](fw::Request req) {
std::string prompt = req.query_or("prompt", "add a route");
fw::AiSample sample = fw::ai_harness_sample(prompt);
std::string body = "{\"base_url\":\"" + sample.base_url +
"\",\"model\":\"" + sample.model +
"\",\"prompt\":\"" +
fw::json_escape(sample.redacted_prompt) +
"\",\"stream_events\":" +
std::to_string(sample.stream_chunks.size()) + "}";
return fw::JsonResponse(body, 200);
});
router.post("/workflow/release", "workflow", [](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string subjects = input.count("commits") ? input["commits"] : "";
std::vector<fw::CommitInfo> commits;
std::size_t start = 0;
while (start < subjects.size()) {
std::size_t bar = subjects.find('|', start);
std::string one =
subjects.substr(start, bar == std::string::npos ? bar : bar - start);
fw::CommitInfo info;
std::string error;
if (!fw::parse_commit(one, "", info, error))
return fw::JsonResponse(
"{\"error\":\"bad commit: " + fw::json_escape(error) + "\"}",
400);
commits.push_back(info);
if (bar == std::string::npos) break;
start = bar + 1;
}
fw::ReleasePlanner planner;
fw::ChangelogWriter writer;
fw::ReleaseVerifier verifier;
verifier.add_check("suite", true, "example suite green");
verifier.add_check("live", true, "health probe ok");
std::string version = planner.next_version("0.1.0", commits);
std::string body =
"{\"bump\":\"" + fw::bump_name(planner.decide(commits)) +
"\",\"version\":\"" + version + "\",\"green\":" +
(verifier.green() ? "true" : "false") + ",\"changelog\":\"" +
fw::json_escape(writer.entry(version, "2026-10-23", commits)) + "\"}";
return fw::JsonResponse(body, 200);
});
}
} // namespace molo::example::app
+93
View File
@@ -0,0 +1,93 @@
#include "App.hpp"
#include "../fw/Data.hpp"
#include "../fw/Router.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
// Realtime demos answer over plain HTTP in the skeleton: the WebSocket and
// Socket.IO endpoints describe the upgrade contract and echo posted frames,
// SSE streams real event text. Gap: real framing, namespaces, rooms, and
// long-polling fallback in 06-realtime.md plus matching clients.
void register_realtime_demo(fw::Router& router, Services& services) {
fw::WebdavStore* webdav = services.webdav.get();
router.get("/streaming/feed", "stream", [](fw::Request req) {
(void)req;
return fw::Response(
fw::StreamingResponse({"chunk-1\n", "chunk-2\n", "chunk-3\n"}));
});
router.get("/streaming/passthrough", "passthrough", [](fw::Request req) {
std::string target = req.query_or("target", "/health");
return fw::Response(fw::StreamingResponse(
{"passthrough from " + target + "\n", "{\"status\":\"ok\"}\n"}));
});
router.get("/ws/chat", "ws", [](fw::Request req) {
std::string upgrade = req.headers.get("Upgrade");
if (upgrade == "websocket")
return fw::JsonResponse(
"{\"upgraded\":false,\"note\":\"skeleton: echo over POST\"}", 200);
return fw::JsonResponse(
"{\"protocol\":\"websocket\",\"path\":\"/ws/chat\",\"upgrade\":"
"\"send Upgrade: websocket\"}",
200);
});
router.post("/ws/chat", "ws-echo", [](fw::Request req) {
return fw::JsonResponse(
"{\"echo\":\"" + fw::json_escape(req.body) + "\"}", 200);
});
router.get("/socketio/rooms", "socketio", [](fw::Request req) {
(void)req;
return fw::JsonResponse(
"{\"protocol\":\"socket.io\",\"namespaces\":[\"/\"],\"rooms\":["
"\"lobby\"],\"fallback\":\"long-polling\"}",
200);
});
router.post("/socketio/rooms", "socketio-emit", [](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string room = input.count("room") ? input["room"] : "lobby";
std::string event = input.count("event") ? input["event"] : "message";
return fw::JsonResponse("{\"emitted\":\"" + fw::json_escape(event) +
"\",\"room\":\"" + fw::json_escape(room) +
"\",\"ack\":true}",
200);
});
router.get("/sse/events", "sse", [](fw::Request req) {
(void)req;
return fw::Response(
fw::SseResponse({"hello", "tick", "goodbye"}));
});
router.any({fw::Method::Propfind}, "/webdav/files/", "webdav-propfind",
[webdav](fw::Request req) {
(void)req;
return fw::Response(207, webdav->propfind_xml("/files/"),
"application/xml");
});
router.any({fw::Method::Get}, "/webdav/files/{name}", "webdav-get",
[webdav](fw::Request req) -> fw::Response {
std::string content;
if (!webdav->get("/files/" + req.param_or("name", ""), content))
return fw::JsonResponse("{\"error\":\"not found\"}", 404);
return fw::TextResponse(content, 200);
});
router.any({fw::Method::Put}, "/webdav/files/{name}", "webdav-put",
[webdav](fw::Request req) {
webdav->put("/files/" + req.param_or("name", ""), req.body);
return fw::JsonResponse("{\"stored\":true}", 201);
});
router.any({fw::Method::Delete}, "/webdav/files/{name}", "webdav-delete",
[webdav](fw::Request req) {
if (!webdav->remove("/files/" + req.param_or("name", "")))
return fw::JsonResponse("{\"error\":\"not found\"}", 404);
return fw::JsonResponse("{\"deleted\":true}", 200);
});
}
} // namespace molo::example::app
+80
View File
@@ -0,0 +1,80 @@
#include "App.hpp"
#include "../fw/Router.hpp"
#include "../fw/View.hpp"
namespace molo::example::app {
namespace {
class GreetView : public fw::View {
public:
using fw::View::View;
fw::Response get() override {
return fw::JsonResponse(
"{\"view\":\"GreetView\",\"method\":\"GET\",\"name\":\"" +
fw::json_escape(req_.query_or("name", "stranger")) + "\"}",
200);
}
fw::Response post() override {
auto form = fw::parse_form(req_.body);
auto it = form.find("name");
std::string name = it == form.end() ? "stranger" : it->second;
return fw::JsonResponse(
"{\"view\":\"GreetView\",\"method\":\"POST\",\"name\":\"" +
fw::json_escape(name) + "\"}",
200);
}
};
} // namespace
void register_routing_demo(fw::Router& router, Services& services) {
(void)services;
router.get("/hello/{name}", "hello", [](fw::Request req) {
return fw::JsonResponse(
"{\"hello\":\"" + fw::json_escape(req.param_or("name", "")) + "\"}",
200);
});
fw::Router views;
views.get("/greet", "greet", [](fw::Request req) {
GreetView view(std::move(req));
return view.dispatch();
});
views.post("/greet", "greet-post", [](fw::Request req) {
GreetView view(std::move(req));
return view.dispatch();
});
router.include_router("/views", views, "views.");
fw::Router nested;
nested.get("/deep", "deep", [](fw::Request req) {
(void)req;
return fw::JsonResponse("{\"nested\":true}", 200);
});
fw::Router middle;
middle.include_router("/nested", nested, "nested.");
router.include_router("/routers", middle, "routers.");
}
void register_chain_demo(std::shared_ptr<fw::Application> app,
Services& services) {
(void)services;
auto leaf = std::make_shared<fw::Application>();
fw::Router r;
r.get("/whoami", "whoami", [](fw::Request req) {
(void)req;
return fw::JsonResponse("{\"depth\":3,\"path\":\"/app1/app1/app1\"}", 200);
});
leaf->include_router("", r);
auto mid = std::make_shared<fw::Application>();
mid->mount("/app1", leaf);
auto top = std::make_shared<fw::Application>();
top->mount("/app1", mid);
app->mount("/app1", top);
}
} // namespace molo::example::app
+93
View File
@@ -0,0 +1,93 @@
#include "App.hpp"
#include "../fw/Cookies.hpp"
#include "../fw/Data.hpp"
#include "../fw/Router.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
void register_security_demo(fw::Router& router, Services& services) {
fw::Auth* auth = services.auth.get();
fw::SessionStore* sessions = services.sessions.get();
fw::UploadStore* uploads = services.uploads.get();
std::string secret = services.cookie_secret;
router.get("/auth/me", "auth-me", [auth](fw::Request req) {
std::string user, password;
if (!fw::parse_basic_auth(req.headers.get("Authorization"), user,
password))
return fw::JsonResponse("{\"error\":\"basic auth required\"}", 401);
if (!auth->check(user, password))
return fw::JsonResponse("{\"error\":\"bad credentials\"}", 403);
return fw::JsonResponse(
"{\"user\":\"" + fw::json_escape(user) + "\"}", 200);
});
router.post("/auth/login", "auth-login", [auth](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
if (!input.count("username") || !input.count("password"))
return fw::JsonResponse("{\"error\":\"username and password required\"}",
400);
if (!auth->check(input["username"], input["password"]))
return fw::JsonResponse("{\"error\":\"bad credentials\"}", 403);
return fw::JsonResponse(
"{\"user\":\"" + fw::json_escape(input["username"]) + "\"}", 200);
});
router.get("/sessions/counter", "session-counter",
[sessions, secret](fw::Request req) {
std::string raw = req.cookie_or("session", "");
std::string id;
std::map<std::string, std::string> data;
bool fresh = false;
if (raw.empty() || !fw::cookie_verify(raw, secret, id) ||
!sessions->get(id, data)) {
id = sessions->create();
fresh = true;
data.clear();
}
long count = 0;
if (data.count("count")) {
try {
count = std::stol(data["count"]);
} catch (...) {
count = 0;
}
}
++count;
sessions->put(id, "count", std::to_string(count));
fw::Response res(200,
"{\"count\":" + std::to_string(count) +
",\"fresh\":" +
(fresh ? "true" : "false") + "}",
"application/json");
res.headers.set(
"Set-Cookie",
fw::make_set_cookie("session", fw::cookie_sign(id, secret),
"/", true, false, "Lax", 3600));
return res;
});
router.post("/uploads/file", "upload", [uploads](fw::Request req) {
std::string filename = req.query_or("filename", "upload.txt");
std::string content_type =
req.headers.get("Content-Type");
if (content_type.empty()) content_type = "text/plain";
fw::UploadInfo info;
std::string error;
if (!uploads->store(filename, content_type, req.body, info, error)) {
if (error == "file too large")
return fw::JsonResponse("{\"error\":\"" + error + "\"}", 413);
if (error == "content type not allowed")
return fw::JsonResponse("{\"error\":\"" + error + "\"}", 415);
return fw::JsonResponse("{\"error\":\"" + error + "\"}", 400);
}
return fw::JsonResponse("{\"file\":\"" + fw::json_escape(info.filename) +
"\",\"size\":" + std::to_string(info.size) +
"}",
201);
});
}
} // namespace molo::example::app
+14
View File
@@ -0,0 +1,14 @@
#include "App.hpp"
namespace molo::example::app {
void seed_services(Services& services) {
services.auth->add_user("ada", "correct-horse");
services.auth->add_user("grace", "compiler-rocks");
services.supervisor->add_worker("mailer");
services.supervisor->add_worker("indexer");
services.supervisor->start("mailer");
services.webdav->put("/files/welcome.txt", "hello from webdav\n");
}
} // namespace molo::example::app
+136
View File
@@ -0,0 +1,136 @@
#include "App.hpp"
#include "../fw/Templates.hpp"
namespace molo::example::app {
namespace {
const char kBase[] = R"BASE(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }}</title>
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
<header class="topbar">
<a class="brand" href="/">{{ site }}</a>
<nav class="nav-wide">
<a href="/">Index</a>
<a href="/templates/page">Templates</a>
<a href="/forms/contact">Forms</a>
<a href="/docs">Docs</a>
<a href="/health">Health</a>
</nav>
<details class="nav-narrow">
<summary>Menu</summary>
<nav>
<a href="/">Index</a>
<a href="/templates/page">Templates</a>
<a href="/forms/contact">Forms</a>
<a href="/docs">Docs</a>
<a href="/health">Health</a>
</nav>
</details>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer><p>{{ site }}: living example, {{ backend }}</p></footer>
</body>
</html>
)BASE";
const char kIndex[] = R"INDEX({% extends "base.html" %}
{% block content %}
<h1>Living example</h1>
<p>Every framework feature, one click away. Mobile-first: narrow the window
and the top nav collapses into a dropdown menu.</p>
{% if show_matrix %}
<table>
<thead><tr><th>Feature</th><th>Route</th></tr></thead>
<tbody>
{% for row in matrix %}
<tr><td>{{ row.feature }}</td><td><a href="{{ row.route }}">{{ row.route }}</a></td></tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>Matrix hidden.</p>
{% endif %}
{% include "nav_hint.html" %}
{% endblock %}
)INDEX";
const char kPage[] = R"PAGE({% extends "base.html" %}
{% block content %}
<h1>{{ heading }}</h1>
<p>Author: {{ author|upper }}</p>
<p>Raw (escaped): {{ snippet }}</p>
<p>Trusted (safe): {{ snippet|safe }}</p>
<ul>
{% for item in items %}
<li>{{ item.name }} ({{ item.kind }})</li>
{% endfor %}
</ul>
{% endblock %}
)PAGE";
const char kContact[] = R"CONTACT({% extends "base.html" %}
{% block content %}
<h1>Contact</h1>
{% if posted %}
<p class="ok">Thanks {{ name }}, message received.</p>
{% else %}
<form method="post" action="/forms/contact">
<label>Name <input name="name" value="{{ name }}"></label>
<label>Email <input name="email" value="{{ email }}"></label>
<label>Message <textarea name="message">{{ message }}</textarea></label>
<button type="submit">Send</button>
</form>
{% endif %}
{% if error %}
<p class="error">{{ error }}</p>
{% endif %}
{% endblock %}
)CONTACT";
const char kDocs[] = R"DOCS({% extends "base.html" %}
{% block content %}
<h1>API docs</h1>
<p>OpenAPI JSON: <a href="/openapi.json">/openapi.json</a></p>
<ul>
{% for row in routes %}
<li><code>{{ row.method }} {{ row.path }}</code> : {{ row.summary }}</li>
{% endfor %}
</ul>
{% endblock %}
)DOCS";
const char kError[] = R"ERROR({% extends "base.html" %}
{% block content %}
<h1>Error {{ status }}</h1>
<p>{{ message }}</p>
{% endblock %}
)ERROR";
const char kNavHint[] =
"<p class=\"hint\">Tip: this page works on a 360px phone.</p>\n";
} // namespace
void load_templates(Services& services) {
services.templates->add_template("base.html", kBase);
services.templates->add_template("index.html", kIndex);
services.templates->add_template("page.html", kPage);
services.templates->add_template("contact.html", kContact);
services.templates->add_template("docs.html", kDocs);
services.templates->add_template("error.html", kError);
services.templates->add_template("nav_hint.html", kNavHint);
services.templates->add_global("site", "MoloApp living example");
services.templates->add_global("backend", "skeleton");
}
} // namespace molo::example::app