Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import settingsRoutes from "./routes/settings";
import { statementsRoutes } from "./routes/statements";
import { paymentLinkRoutes } from "./routes/paymentLinkRoutes.js";
import providerStatusRouter from "./routes/providerStatus";
import { costAllocationRoutes } from "./routes/costAllocation";
import { startHeartbeatService, stopHeartbeatService } from "./services/heartbeatService";
import { startStellarExporter } from "./services/stellarExporter";

Expand Down Expand Up @@ -392,6 +393,7 @@ app.use("/api/developer", developerDashboardRoutes);
app.use("/api/admin", requireAuth, adminRoutes);
app.use("/api/admin/providers/status", requireAuth, providerStatusRouter);
app.use("/api/admin/kyc-upgrades", requireAuth, kycTierUpgradeRoutes);
app.use("/api/admin/cost-allocation", requireAuth, costAllocationRoutes);
app.use("/api/admin/auth", createAdminSep10Router());
app.use("/sep10", createSep10Router());
app.use("/sep31", sep31Router);
Expand Down
81 changes: 81 additions & 0 deletions src/routes/costAllocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Cost Allocation Metrics API — issue #261
*
* Exposes unit economics data (cost per transaction by provider and feature)
* as a JSON endpoint consumed by analytics dashboards and data pipelines.
*
* Routes:
* GET /api/admin/cost-allocation — unit cost analytics (JSON)
* GET /api/admin/cost-allocation/export — CSV export for data warehouse
*/

import { Router, Request, Response } from "express";
import { requireAuth } from "../middleware/auth";
import { costMetrics } from "../services/costAllocationMetrics";

const router = Router();

/**
* GET /api/admin/cost-allocation
* Returns cost-per-transaction analytics grouped by provider and feature.
* Identifies the most expensive features and enables capacity planning.
*/
router.get("/", requireAuth, (_req: Request, res: Response) => {
const records = costMetrics.getUnitCostAnalytics();

// Aggregate totals for the summary block
const summary = records.reduce(
(acc, r) => ({
total_api_calls: acc.total_api_calls + r.api_calls,
total_db_queries: acc.total_db_queries + r.db_queries,
total_storage_bytes: acc.total_storage_bytes + r.storage_bytes,
total_transactions: acc.total_transactions + r.total_transactions,
}),
{
total_api_calls: 0,
total_db_queries: 0,
total_storage_bytes: 0,
total_transactions: 0,
},
);

res.json({
generated_at: new Date().toISOString(),
summary,
records,
note: "Costs are estimated from configurable per-unit rates. Override via COST_PER_API_CALL_USD_CENTS, COST_PER_DB_QUERY_USD_CENTS, COST_PER_STORAGE_KB_USD_CENTS env vars.",
});
});

/**
* GET /api/admin/cost-allocation/export
* Returns cost analytics as a CSV for import into BigQuery / Redshift / Excel.
*/
router.get("/export", requireAuth, (_req: Request, res: Response) => {
const records = costMetrics.getUnitCostAnalytics();

const header =
"provider,feature,api_calls,db_queries,storage_bytes,total_transactions," +
"estimated_api_cost_usd_cents_per_tx,estimated_db_cost_usd_cents_per_tx," +
"estimated_total_cost_usd_cents_per_tx\n";

const rows = records
.map(
(r) =>
`${r.provider},${r.feature},${r.api_calls},${r.db_queries},` +
`${r.storage_bytes},${r.total_transactions},` +
`${r.estimated_api_cost_usd_cents_per_tx},` +
`${r.estimated_db_cost_usd_cents_per_tx},` +
`${r.estimated_total_cost_usd_cents_per_tx}`,
)
.join("\n");

res.setHeader("Content-Type", "text/csv");
res.setHeader(
"Content-Disposition",
`attachment; filename="cost-allocation-${new Date().toISOString().slice(0, 10)}.csv"`,
);
res.send(header + rows);
});

export { router as costAllocationRoutes };
Loading
Loading