This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/portal/myBusinesses.cfm
John Mizerek dc9db32b58 Add API performance profiling, caching, and query optimizations
- Add queryTimed() wrapper and logPerf() for per-endpoint timing metrics
- Add api_perf_log table flush mechanism with background thread batching
- Add application-scope cache (appCacheGet/Put/Invalidate) with TTL
- Cache businesses/get (5m), addresses/states (24h), menu/items (2m)
- Fix N+1 queries in orders/history, orders/listForKDS (batch fetch)
- Fix correlated subquery in orders/getDetail (LEFT JOIN)
- Combine 4 queries into 1 in portal/stats (subselects)
- Optimize getForBuilder tree building with pre-indexed parent lookup
- Add cache invalidation in update, saveBrandColor, updateHours, saveFromBuilder
- New admin/perf.cfm dashboard (localhost-protected)
- Instrument top 10 endpoints with queryTimed + logPerf

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:41:27 -08:00

76 lines
1.9 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfheader name="Cache-Control" value="no-store">
<cfscript>
/**
* Get Businesses for User
* Returns list of businesses the authenticated user has access to
*
* POST: { UserID: int }
* Headers: X-User-Token (optional - will use session if not provided)
*/
response = { "OK": false };
try {
// Get UserID from request or session
userID = 0;
// Check token auth first
if (structKeyExists(request, "UserID") && isNumeric(request.UserID)) {
userID = int(request.UserID);
}
// Also check request body
if (userID == 0) {
requestBody = toString(getHttpRequestData().content);
if (len(requestBody)) {
requestData = deserializeJSON(requestBody);
if (structKeyExists(requestData, "UserID")) {
userID = val(requestData.UserID);
}
}
}
if (userID == 0) {
response["ERROR"] = "not_logged_in";
response["MESSAGE"] = "User not authenticated";
writeOutput(serializeJSON(response));
abort;
}
// Get businesses for this user
// Users are linked to businesses via BusinessUserID field (owner)
q = queryTimed("
SELECT
b.BusinessID,
b.BusinessName
FROM Businesses b
WHERE b.BusinessUserID = :userID
ORDER BY b.BusinessName
", { userID: userID }, { datasource: "payfrit" });
businesses = [];
for (row in q) {
arrayAppend(businesses, {
"BusinessID": row.BusinessID,
"BusinessName": row.BusinessName
});
}
response["OK"] = true;
response["BUSINESSES"] = businesses;
response["COUNT"] = arrayLen(businesses);
} catch (any e) {
response["ERROR"] = "server_error";
response["MESSAGE"] = e.message;
}
logPerf();
writeOutput(serializeJSON(response));
</cfscript>