/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // The public financials aggregates. // // The page at /financials shows running totals only. Sales and shop donations // fold out of the order ledger on every request (Orders.cpp); the bank-side // donations and the expenses come from the aggregates file this unit reads — // written by the owner's own tooling, off this box, and re-read per request so // updating the file is all it takes to update the page. // // This unit once also held the bunq mutation callback that moved those numbers // live (parser, default-deny classifier, dedup ledger, signature check). That // integration was retired 2026-08-17 — the webhook is deregistered and the // endpoint is gone — and the file is in git history if a bank feed ever comes // back. What survives is the privacy property the page still promises: the // only bank-derived state on this box is category totals with an as-of date; // no transaction, counterparty or timestamp ever reaches disk here. module; module Catcrafts.Server; import std; import Catcrafts.Shared; namespace Catcrafts::Server { namespace { std::mutex gFinMutex; FinancialsConfig gFinCfg; std::string ReadStateFile(const std::filesystem::path& p) { if (p.empty()) return {}; std::ifstream in(p, std::ios::binary); if (!in) return {}; std::ostringstream buf; buf << in.rdbuf(); return buf.str(); } } // namespace void ConfigureFinancials(FinancialsConfig config) { std::lock_guard lock(gFinMutex); gFinCfg = std::move(config); } Financials CurrentFinancials() { std::lock_guard lock(gFinMutex); return LoadFinancials(ReadStateFile(gFinCfg.publicPath)); } } // namespace Catcrafts::Server