feat: add go-live readiness metric for pilot launch gating

This commit is contained in:
MOHAN 2026-03-29 18:05:29 +05:30
parent 7fe725b00e
commit 1ac6899898
6 changed files with 155 additions and 2 deletions

View File

@ -0,0 +1,26 @@
# 11 Going Live Audit
Source checked: Uber Eats "Going Live" section shared by you.
## Implemented Now
- Go-live readiness metric endpoint for pilot gating:
- `GET /api/v1/metrics/go-live-readiness`
- computes 3-day injection success and evaluates against configurable threshold (default 98%)
- Existing production readiness controls already present:
- webhook security (signature + optional basic auth)
- OAuth domain pairing checks
- injection success monitoring endpoint
## Existing Before
- Menu upload and POS integration activation APIs
- Provisioning and de-provisioning flow endpoints
- Webhook ingestion and order action APIs
## Pending (Operational / Process)
- Scheduling formal joint verification run with Uber support team
- Production app creation and scope whitelisting workflow in dashboard
- Pilot launch operational communication workflow outside API service

View File

@ -7,3 +7,13 @@ Go-live readiness:
- Alerting and log monitoring enabled - Alerting and log monitoring enabled
- Token refresh and failure runbooks ready - Token refresh and failure runbooks ready
- Injection success rate monitoring enabled (`target >= 99%`) - Injection success rate monitoring enabled (`target >= 99%`)
- Pilot launch metric check enabled (`>= 98%` over 3 days):
- `GET /api/v1/metrics/go-live-readiness`
Pilot launch workflow:
1. Provision pilot store to production app.
2. Upload menu (`PUT /api/v1/uber/menu/replace`).
3. Enable POS integration (`PATCH /api/v1/uber/stores/{storeId}/pos-data` with `integration_enabled=true`).
4. Monitor injection success and order response SLA.
5. Continue launches after pilot stability target is met.

View File

@ -246,6 +246,37 @@
} }
} }
}, },
"/api/v1/metrics/go-live-readiness": {
"get": {
"summary": "Check pilot go-live readiness based on 3-day injection success threshold",
"tags": [
"Metrics"
],
"parameters": [
{
"in": "query",
"name": "merchantId",
"required": false,
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "thresholdPercent",
"required": false,
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": "Go-live readiness status"
}
}
}
},
"/api/v1/uber/request": { "/api/v1/uber/request": {
"post": { "post": {
"summary": "Generic Uber passthrough for any Uber endpoint", "summary": "Generic Uber passthrough for any Uber endpoint",

View File

@ -549,6 +549,36 @@
} }
} }
}, },
{
"name": "Go Live Readiness Metric",
"request": {
"method": "GET",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/v1/metrics/go-live-readiness?merchantId={{merchantId}}",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"metrics",
"go-live-readiness"
],
"query": [
{
"key": "merchantId",
"value": "{{merchantId}}"
}
]
}
}
},
{ {
"name": "Fetch Reporting CSV", "name": "Fetch Reporting CSV",
"request": { "request": {

View File

@ -63,7 +63,38 @@ async function getOrderResponseSla(req, res) {
}); });
} }
async function getGoLiveReadiness(req, res) {
const schema = z.object({
merchantId: z.string().optional(),
thresholdPercent: z.coerce.number().optional()
});
const query = schema.parse(req.query);
const sinceIso = toSinceIso("3");
const stats = apiLogRepository.getInjectionSuccessStats({
merchantId: query.merchantId,
sinceIso
});
const threshold = query.thresholdPercent ?? 98;
const hasData = stats.total > 0;
const eligible = hasData && stats.successRate >= threshold;
return res.json({
success: true,
data: {
metric: "go_live_readiness",
merchantId: query.merchantId || "all",
pilotWindowDays: 3,
requiredInjectionSuccessPercent: threshold,
hasData,
eligible,
...stats
}
});
}
module.exports = { module.exports = {
getInjectionSuccess, getInjectionSuccess,
getOrderResponseSla getOrderResponseSla,
getGoLiveReadiness
}; };

View File

@ -2,7 +2,8 @@ const express = require("express");
const asyncHandler = require("../middleware/asyncHandler"); const asyncHandler = require("../middleware/asyncHandler");
const { const {
getInjectionSuccess, getInjectionSuccess,
getOrderResponseSla getOrderResponseSla,
getGoLiveReadiness
} = require("../modules/metrics/metrics.controller"); } = require("../modules/metrics/metrics.controller");
const router = express.Router(); const router = express.Router();
@ -55,4 +56,28 @@ router.get("/metrics/injection-success", asyncHandler(getInjectionSuccess));
*/ */
router.get("/metrics/order-response-sla", asyncHandler(getOrderResponseSla)); router.get("/metrics/order-response-sla", asyncHandler(getOrderResponseSla));
/**
* @openapi
* /api/v1/metrics/go-live-readiness:
* get:
* summary: Check pilot go-live readiness based on 3-day injection success threshold
* tags:
* - Metrics
* parameters:
* - in: query
* name: merchantId
* required: false
* schema:
* type: string
* - in: query
* name: thresholdPercent
* required: false
* schema:
* type: number
* responses:
* 200:
* description: Go-live readiness status
*/
router.get("/metrics/go-live-readiness", asyncHandler(getGoLiveReadiness));
module.exports = router; module.exports = router;