learning_ai_invt_trdg/docs/BACKEND_AUDIT_SCHEMA.md
Saravana Achu Mac d955d00c00 feat(contracts): shared socket namespaces, tab flags, cutover docs, README
- shared/realtime.ts: add SOCKET_NAMESPACES constants (/trading, /admin, root)
- shared/feature-flags.ts: add tabs.marketplace and tabs.membership to
  TradingFeatureFlagsResponse; add FEATURE_FLAG_KEYS constants
- .env.example: remove /api suffix from VITE/NEXT_PUBLIC trading URL vars
  (web appends /api itself); add tab visibility flag vars with comments
- web: add useTabFeatureFlags hook + DOM test; wire tab visibility into App.tsx
- web/vite.config.ts: finalize build config
- mobile/providers/TradingDataProvider.tsx: deriveSocketParams for proxy-safe
  socket origin/path resolution (already landed upstream, conflict resolved)
- docs: add CUTOVER_WEB.md, CUTOVER_MOBILE.md checklists; update OPERATIONS.md
  with Docker commands and resolved gap log; update ROADMAP.md to Done;
  add BACKEND_AUDIT_SCHEMA.md, BACKEND_API_DEPRECATION.md, CONVENTIONS.md;
  add audit-events container entry to AZURE_INFRASTRUCTURE.md
- README.md: full rewrite with workspace table, arch summary, env var reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 19:35:53 -04:00

5.2 KiB

Backend Admin Audit Schema

Purpose

This document defines the TradeAuditEvent schema used by the trading backend to log all admin-facing, operator-facing, and safety-critical state changes. Every audit event is written to the structured logger via logger.info('[AUDIT] {...}') with a UTC timestamp prepended.

Audit events are not yet persisted to Cosmos — they are log-only. Downstream log aggregation (e.g., Azure Monitor, Log Analytics) is the durable store for audit history.


TradeAuditEvent Schema

interface TradeAuditEvent {
  event: string;            // Required. Identifies the audit event type (see catalogue below).
  userId?: string;          // Auth user ID performing or triggering the action.
  profileId?: string;       // Trading profile ID relevant to the action (if applicable).
  symbol?: string;          // Asset symbol relevant to the action (if applicable).
  outcome?: 'accepted'      // Action was applied.
           | 'rejected'     // Action was blocked by a rule or safety guard.
           | 'error';       // Action failed due to a runtime error.
  reason?: string;          // Human-readable explanation for the outcome.
  details?: Record<string, unknown>; // Structured metadata specific to the event type.
}

Log line format (written via logger.info):

{
  "ts": "2026-04-07T10:00:00.000Z",
  "event": "manual_order_created",
  "userId": "user-abc",
  "profileId": "profile-xyz",
  "symbol": "BTC/USDT",
  "outcome": "accepted",
  "reason": "within risk limits",
  "details": { "side": "BUY", "qty": 0.01, "allocatedCapital": 1000 }
}

Event Catalogue

All events are emitted via auditTradeEvent() in backend/src/services/apiServer.ts.

Event Trigger Key details fields
manual_order_created POST /api/orders/manual — order submitted side, qty, symbol, profileId
manual_order_rejected Manual order blocked by risk/capital guard reason, guard name
manual_order_error Manual order failed at execution error message
profile_control_create Chat AI creates a new trading profile profileName, allocatedCapital
profile_control_update Chat AI updates an existing profile profileId, updatedFields
profile_control_error Chat AI profile action fails error message
chat_profile_control Generic chat-initiated profile action action type, profileId
trading_paused POST /internal/trading/pause — admin pauses trading pausedBy, reason
trading_resumed POST /internal/trading/resume — admin resumes trading resumedBy
backfill_reverted POST /internal/trading/revert-backfill — admin reverts exit backfill symbol, profileId
reconciliation_audit GET /api/reconciliation/backfill/audit — admin reads reconciliation audit
position_closed_manual Admin/operator manually closes a position symbol, profileId, tradeId
order_failure Order execution failure recorded side, qty, reason, tradeId

Not all events use every field. Absent fields are omitted from the log payload.


Audit Middleware

The auditTradeEvent() private method in ApiServer writes directly to the logger:

private auditTradeEvent(evt: TradeAuditEvent): void {
    const payload = { ts: new Date().toISOString(), ...evt };
    logger.info(`[AUDIT] ${JSON.stringify(payload)}`);
}

All audit calls are synchronous and never throw — audit failure must not block the primary operation.


Admin-Scoped Endpoints

Routes that require requireAdmin middleware are the primary sources of audit events:

  • POST /internal/trading/pause
  • POST /internal/trading/resume
  • POST /internal/trading/revert-backfill
  • GET /api/reconciliation/backfill/audit
  • POST /api/admin/dynamic-config

All admin actions must produce an audit event with userId set from authUserId on the authenticated request.


Persistence

Audit events are written to two sinks simultaneously:

  1. Structured log — always, via logger.info('[AUDIT] ...'). Zero runtime dependency.
  2. Cosmos audit-events container — best-effort, via persistAuditEvent() in auditRepository.ts. Silently skipped if Cosmos is not configured or the write fails.

Activating Cosmos Persistence

Create the container in your Cosmos database:

Setting Value
Container name audit-events
Partition key /productId
TTL (Time To Live) 7776000 seconds (90 days)
Throughput Shared or dedicated — start with 400 RU/s

Once the container exists and COSMOS_ENDPOINT / COSMOS_KEY are configured, all auditTradeEvent() calls will persist records automatically.

Admin Audit Endpoint

GET /api/admin/audit (admin-only) queries the audit-events container:

GET /api/admin/audit?userId=user-123&event=manual_order_created&since=1712500000000&limit=50

Query parameters (all optional):

Parameter Type Description
userId string Filter by user ID
event string Filter by event name (exact match)
since number Unix epoch ms — return events newer than this timestamp
limit number Max records to return (default 100, max 500)

Response: { records: AuditEventDocument[], count: number }