fix: operator approval workflow — add approval toggle, lockout CRUD, and PBT tests

- Add GET/PUT /api/admin/trading/approval-config endpoints
- Add POST/DELETE /api/admin/trading/lockouts endpoints
- Add useApprovalConfig, useUpdateApprovalConfig, useCreateLockout, useDeleteLockout hooks
- Add Paper Order Approval toggle card with confirmation dialog
- Add lockout creation form and delete button to Active Lockouts card
- Add MSW handlers for all new endpoints
- Add property-based tests for bug condition exploration and preservation
This commit is contained in:
Celes Renata
2026-04-17 06:14:46 +00:00
parent 3b7ded37cc
commit b149f70507
9 changed files with 1035 additions and 5 deletions
+10
View File
@@ -92,8 +92,18 @@ export const handlers = [
http.get('/api/orders/:id', () => HttpResponse.json({ ...mockOrders[0], idempotency_key: null, decision_trace: null, events: [], audit_trail: [] })),
http.get('/api/positions', () => HttpResponse.json(mockPositions)),
http.get('/api/admin/trading/config', () => HttpResponse.json({ trading_mode: 'paper', config: {} })),
http.get('/api/admin/trading/approval-config', () => HttpResponse.json({ auto_approve_paper: true, require_approval_for_live: true, approval_timeout_minutes: 5 })),
http.put('/api/admin/trading/approval-config', async ({ request }) => {
const body = await request.json() as Record<string, unknown>;
return HttpResponse.json({ auto_approve_paper: true, require_approval_for_live: true, approval_timeout_minutes: 5, ...body });
}),
http.get('/api/admin/trading/approvals', () => HttpResponse.json([])),
http.get('/api/admin/trading/lockouts', () => HttpResponse.json([])),
http.post('/api/admin/trading/lockouts', async ({ request }) => {
const body = await request.json() as Record<string, unknown>;
return HttpResponse.json({ id: 'lockout-new', ticker: body.ticker, reason: body.reason, lockout_type: body.lockout_type ?? 'manual', expires_at: new Date(Date.now() + ((body.duration_minutes as number) ?? 60) * 60000).toISOString(), created_at: new Date().toISOString() }, { status: 201 });
}),
http.delete('/api/admin/trading/lockouts/:id', () => HttpResponse.json({ status: 'deleted' })),
http.get('/api/ops/pipeline/health', () => HttpResponse.json({ hours: 24, document_stages: [{ status: 'extracted', doc_count: 5 }], parsing: {}, extraction: {}, aggregation: {} })),
http.get('/api/ops/ingestion/summary', () => HttpResponse.json({ total_runs: 10, completed: 8, failed: 2, total_items_fetched: 50, total_items_new: 12, by_source_type: [] })),
http.get('/api/ops/ingestion/throughput', () => HttpResponse.json([])),