feat: standardize request ids across operator flows
This commit is contained in:
parent
ffa60fcfb7
commit
d99cb94d19
@ -98,7 +98,7 @@ pnpm lint
|
||||
|
||||
## Request Tracing
|
||||
|
||||
- the main web and mobile API paths now attach `x-request-id`
|
||||
- the main web and mobile API paths, operator actions, and lifecycle fetches now attach `x-request-id`
|
||||
- backend HTTP responses echo `x-request-id` so browser/app logs can be correlated with backend logs
|
||||
- during incident review, treat `x-request-id` as the primary request correlation key across client and backend traces
|
||||
|
||||
@ -228,6 +228,6 @@ Manual mobile release smoke is still required before broad rollout:
|
||||
- web now uses platform-session handling end to end; the remaining auth cleanup is removing dormant compatibility stubs and aligning profile bootstrap contracts fully with backend-owned product APIs
|
||||
- root `pnpm verify` is green again after aligning the web Vitest harness with platform-session storage and current API contracts
|
||||
- mobile does not yet include push notification infrastructure
|
||||
- feature-flag ownership and correlation-ID propagation are not fully standardized yet
|
||||
- feature-flag ownership and exchange/order-level correlation-ID propagation are not fully standardized yet
|
||||
|
||||
These are follow-up items, not hidden defects. They should remain tracked in `docs/ROADMAP.md`.
|
||||
|
||||
@ -40,7 +40,7 @@ It assumes:
|
||||
- [x] Backend risk and PnL aggregate reads now flow through repository abstractions instead of direct legacy service calls
|
||||
- [x] Web history, profile, marketplace, config, and manual-entry flows now run through backend APIs instead of browser-side table access
|
||||
- [x] Release smoke coverage now exists for web auth and product accessibility flows, with a tracked mobile release smoke checklist in operations
|
||||
- [x] Request ID propagation is now standardized across the main web/mobile API paths and echoed by backend HTTP responses
|
||||
- [x] Request ID propagation is now standardized across the main web/mobile API paths, operator actions, lifecycle fetches, and backend HTTP responses
|
||||
- [x] Backtest feature access now reads from an explicit backend feature-flags contract instead of scraping generic runtime config
|
||||
- [x] Trading user profiles and marketplace presets now have Cosmos-backed authority paths
|
||||
- [x] Runtime order, trade-history, manual-entry, order-activity, and reconciliation-audit repositories now use Cosmos-backed trading-record storage instead of the legacy service layer
|
||||
|
||||
@ -5,6 +5,7 @@ import { mobileRuntime } from '@/lib/runtime';
|
||||
import { mobileTelemetry, trackMobileError } from '@/lib/telemetry';
|
||||
import { useMobileAuth } from '@/providers/MobileAuthProvider';
|
||||
import { buildTradingSocketOptions, isUnauthorizedSocketError } from '../../shared/realtime.js';
|
||||
import { createRequestId } from '../../shared/request-id.js';
|
||||
|
||||
type HealthSnapshot = {
|
||||
tradingControl?: {
|
||||
@ -165,6 +166,7 @@ export function TradingDataProvider({ children }: { children: ReactNode }) {
|
||||
const response = await fetch(`${mobileRuntime.tradingApiUrl}/state`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('mobile-state'),
|
||||
},
|
||||
});
|
||||
|
||||
@ -335,6 +337,7 @@ export function TradingDataProvider({ children }: { children: ReactNode }) {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('mobile-control'),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
reason: reason || 'Requested from mobile trading surface',
|
||||
|
||||
@ -2,6 +2,7 @@ import { useState, useRef, useEffect, useMemo } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
import {
|
||||
Send, X, Bot, User,
|
||||
Check, Loader2,
|
||||
@ -204,7 +205,8 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-chat')
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: msg,
|
||||
|
||||
@ -4,6 +4,7 @@ import { useAuth } from '../components/AuthContext';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
import { createManualEntry, updateManualEntry } from '../lib/manualEntriesApi';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
|
||||
interface EntryFormProps {
|
||||
onSuccess: () => void;
|
||||
@ -129,7 +130,8 @@ export function EntryForm({ onSuccess, initialData }: EntryFormProps) {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-entry')
|
||||
},
|
||||
body: JSON.stringify(apiPayload)
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { tradingRuntime } from './runtime';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
|
||||
export type CanonicalLifecycleState = 'OPEN' | 'PARTIAL_EXIT' | 'CLOSED' | 'ORPHAN_EXIT';
|
||||
export type CanonicalSide = 'BUY' | 'SELL';
|
||||
@ -145,7 +146,8 @@ export const fetchCanonicalLifecycleSnapshot = async (args: {
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
Authorization: `Bearer ${token}`,
|
||||
'x-request-id': createRequestId('web-lifecycle')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import { useAuth } from '../components/AuthContext';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
import { fetchDynamicConfigItems, upsertDynamicConfigItems } from '../lib/dynamicConfigApi';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
|
||||
interface AdminTabProps {
|
||||
botState: BotState;
|
||||
@ -158,7 +159,8 @@ export const AdminTab = ({ botState }: AdminTabProps) => {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'x-request-id': createRequestId('web-admin')
|
||||
},
|
||||
body: JSON.stringify({ reason: 'Admin pause from dashboard' })
|
||||
});
|
||||
@ -183,7 +185,8 @@ export const AdminTab = ({ botState }: AdminTabProps) => {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'x-request-id': createRequestId('web-admin')
|
||||
},
|
||||
body: JSON.stringify({ reason: 'Admin resume from dashboard' })
|
||||
});
|
||||
@ -208,7 +211,8 @@ export const AdminTab = ({ botState }: AdminTabProps) => {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'x-request-id': createRequestId('web-admin')
|
||||
}
|
||||
});
|
||||
if (!res.ok) {
|
||||
@ -230,7 +234,8 @@ export const AdminTab = ({ botState }: AdminTabProps) => {
|
||||
if (!accessToken) return;
|
||||
const res = await fetch(`${apiUrl}/api/config`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-admin')
|
||||
}
|
||||
});
|
||||
if (res.ok) {
|
||||
|
||||
@ -3,6 +3,7 @@ import type { BotState } from '../hooks/useWebSocket';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
import { useAuth } from '../components/AuthContext';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
import { Layers, ListFilter, Link2, GitBranch, AlertTriangle, Lock, RefreshCw, CheckCircle, XCircle } from 'lucide-react';
|
||||
import { useCanonicalLifecycle } from '../hooks/useCanonicalLifecycle';
|
||||
import { fetchPositionsBootstrap } from '../lib/positionsApi';
|
||||
@ -1370,9 +1371,10 @@ export const PositionsTab = ({ botState }: PositionsTabProps) => {
|
||||
const response = await fetch(`${tradingRuntime.tradingApiUrl}/api/close`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
},
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-close')
|
||||
},
|
||||
body: JSON.stringify({
|
||||
profile_id: pos.profileId,
|
||||
symbol: pos.symbol
|
||||
|
||||
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { AlertTriangle, Clock3, RefreshCcw, Search, ShieldCheck, Undo2 } from 'lucide-react';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
|
||||
interface ReconciliationBackfillAuditRow {
|
||||
id: number;
|
||||
@ -167,13 +168,22 @@ export const ReconciliationAuditPanel = () => {
|
||||
|
||||
const [auditResponse, batchResponse, manualReviewResponse] = await Promise.all([
|
||||
fetch(`${apiUrl}/api/reconciliation/backfill/audit?${auditParams.toString()}`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` }
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-recon')
|
||||
}
|
||||
}),
|
||||
fetch(`${apiUrl}/api/reconciliation/backfill/batches?${batchParams.toString()}`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` }
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-recon')
|
||||
}
|
||||
}),
|
||||
fetch(`${apiUrl}/api/reconciliation/backfill/audit?${manualReviewParams.toString()}`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` }
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-recon')
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
@ -266,7 +276,8 @@ export const ReconciliationAuditPanel = () => {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-request-id': createRequestId('web-recon')
|
||||
},
|
||||
body: JSON.stringify({ batchId })
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user