feat: align getting-started guidance with menu PUT replace and sandbox setup

This commit is contained in:
MOHAN 2026-03-29 17:36:08 +05:30
parent 156f7cdd58
commit 522f46fd1e
9 changed files with 136 additions and 6 deletions

View File

@ -7,10 +7,12 @@ UBER_CLIENT_SECRET=your_client_secret
UBER_REDIRECT_URI=http://localhost:8080/api/v1/auth/uber/callback
UBER_OAUTH_BASE_URL=https://login.uber.com
UBER_API_BASE_URL=https://api.uber.com
# Sandbox values when testing:
# UBER_OAUTH_BASE_URL=https://sandbox-auth.uber.com
# UBER_API_BASE_URL=https://test-api.uber.com
# SQLite database path
SQLITE_PATH=./data/uber_wrapper.db
# Shared API key for wrapper clients (optional but recommended)
WRAPPER_API_KEY=change-me

View File

@ -0,0 +1,31 @@
# 01 Getting Started Audit
Source checked: Uber Eats "Getting Started" section shared by you.
## Implemented Now
- OAuth-based authentication foundation is present.
- Store/menu/order/webhook modules exist.
- Multi-merchant model is implemented.
- Sandbox guidance updated with official sandbox domains.
- Full menu replacement support added via `PUT /api/v1/uber/menu/replace`.
## Partly Implemented
- Store management:
Hours update exists, but typed online/offline and settings endpoints are pending.
- Order processing:
Core actions exist, but full BYOC and advanced workflows are pending.
## Not Yet Implemented
- Written-approval and scope entitlement checks (operational process outside API code).
- Formal quality gate automation for all production standards.
- Full typed coverage for promotions/reporting APIs.
## Current Safe Fallback
For any endpoint not yet typed, use:
- `POST /api/v1/uber/request`

View File

@ -2,8 +2,11 @@
Menu sync between POS and Uber Eats:
- Upload/replace menu
- Full menu replacement via PUT
- Fetch menu from Uber
- Item and modifier mapping strategy
- Validation and publish error handling
Current wrapper route for full replacement:
- `PUT /api/v1/uber/menu/replace`

View File

@ -2,9 +2,20 @@
Checklist:
- Create a dedicated TESTING app in Uber Developer Dashboard
- Use sandbox domains in `.env`:
- `UBER_OAUTH_BASE_URL=https://sandbox-auth.uber.com`
- `UBER_API_BASE_URL=https://test-api.uber.com`
- Test OAuth connect flow
- Test menu upload/get
- Test order lifecycle actions
- Test webhook receipt and persistence
- Validate retry and duplicate event handling
Validation sequence:
1. Authentication token generation and authorized call test
2. Store status/hours API smoke tests
3. Full menu replacement test via PUT
4. Order webhook receipt and lifecycle action tests
5. Error and retry behavior checks

View File

@ -202,6 +202,19 @@
}
}
},
"/api/v1/uber/menu/replace": {
"put": {
"summary": "Replace store menu (full upload)",
"tags": [
"Uber Menu"
],
"responses": {
"200": {
"description": "Menu replaced"
}
}
}
},
"/api/v1/uber/menu": {
"get": {
"summary": "Fetch store menu",

View File

@ -83,6 +83,39 @@
}
}
},
{
"name": "Replace Menu (PUT)",
"request": {
"method": "PUT",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"storeId\": \"{{storeId}}\",\n \"menu\": {\n \"categories\": []\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/menu/replace",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"menu",
"replace"
]
}
}
},
{
"name": "Generic Uber Request",
"request": {
@ -135,4 +168,3 @@
}
]
}

View File

@ -40,6 +40,21 @@ async function getMenu(req, res) {
return res.json({ success: true, data });
}
async function replaceMenu(req, res) {
const schema = z.object({
merchantId: z.string().min(1),
storeId: z.string().min(1),
menu: z.any()
});
const payload = schema.parse(req.body);
const data = await proxyService.menuReplace({
merchantId: payload.merchantId,
storeId: payload.storeId,
payload: payload.menu
});
return res.json({ success: true, data });
}
async function listOrders(req, res) {
const schema = z.object({
merchantId: z.string().min(1),
@ -89,9 +104,9 @@ async function updateHours(req, res) {
module.exports = {
genericProxy,
upsertMenu,
replaceMenu,
getMenu,
listOrders,
orderAction,
updateHours
};

View File

@ -94,6 +94,17 @@ async function menuUpsert({ merchantId, storeId, payload }) {
});
}
async function menuReplace({ merchantId, storeId, payload }) {
const uberPath = interpolatePath(uberEndpoints.menu.upsert, { storeId });
return callUberApi({
merchantId,
method: "PUT",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/menu/replace"
});
}
async function menuGet({ merchantId, storeId }) {
const uberPath = interpolatePath(uberEndpoints.menu.get, { storeId });
return callUberApi({
@ -153,9 +164,9 @@ async function updateStoreHours({ merchantId, storeId, payload }) {
module.exports = {
genericProxy,
menuUpsert,
menuReplace,
menuGet,
ordersList,
orderAction,
updateStoreHours
};

View File

@ -30,6 +30,19 @@ router.post("/uber/request", asyncHandler(controller.genericProxy));
*/
router.post("/uber/menu/upsert", asyncHandler(controller.upsertMenu));
/**
* @openapi
* /api/v1/uber/menu/replace:
* put:
* summary: Replace store menu (full upload)
* tags:
* - Uber Menu
* responses:
* 200:
* description: Menu replaced
*/
router.put("/uber/menu/replace", asyncHandler(controller.replaceMenu));
/**
* @openapi
* /api/v1/uber/menu:
@ -89,4 +102,3 @@ router.post("/uber/orders/:orderId/action", asyncHandler(controller.orderAction)
router.put("/uber/stores/hours", asyncHandler(controller.updateHours));
module.exports = router;