From b306f3264ec6b187f4c4623e5f052e00beda8eb0 Mon Sep 17 00:00:00 2001 From: Saravana Achu Mac Date: Sat, 4 Apr 2026 18:56:20 -0700 Subject: [PATCH] refactor(backend): extract shared trading persistence types from SupabaseService Made-with: Cursor --- backend/src/services/SupabaseService.ts | 162 +++--------------- .../src/services/canonicalLifecycleService.ts | 2 +- .../reconciliationExitBackfillService.ts | 4 +- .../reconciliationSubTagRepairService.ts | 4 +- .../src/services/runtimeOrderRepository.ts | 2 +- .../src/services/tradingPersistenceTypes.ts | 143 ++++++++++++++++ 6 files changed, 171 insertions(+), 146 deletions(-) create mode 100644 backend/src/services/tradingPersistenceTypes.ts diff --git a/backend/src/services/SupabaseService.ts b/backend/src/services/SupabaseService.ts index b5297b4..32e555b 100644 --- a/backend/src/services/SupabaseService.ts +++ b/backend/src/services/SupabaseService.ts @@ -15,6 +15,29 @@ import { type AlpacaSubTagIntent } from '../utils/alpacaSubTag.js'; import { SymbolMapper } from '../utils/symbolMapper.js'; +import type { + FilledLifecycleOrderRow, + ReconciliationBackfillAuditInsert, + ReconciliationBackfillAuditQuery, + ReconciliationBackfillAuditRow, + ReconciliationBackfillBatchSummary, + ReconciliationBackfillOrderInsert, + ReconciliationSubTagRepairSummary, + StaleOrderScope, + VirtualOpenPosition +} from './tradingPersistenceTypes.js'; + +export type { + FilledLifecycleOrderRow, + ReconciliationBackfillAuditInsert, + ReconciliationBackfillAuditQuery, + ReconciliationBackfillAuditRow, + ReconciliationBackfillBatchSummary, + ReconciliationBackfillOrderInsert, + ReconciliationSubTagRepairSummary, + StaleOrderScope, + VirtualOpenPosition +} from './tradingPersistenceTypes.js'; export interface UserConfig { user_id: string; @@ -32,145 +55,6 @@ export interface UserConfig { market_poll_interval_in_seconds: number; } -export interface VirtualOpenPosition { - profileId: string; - symbol: string; - side: 'BUY' | 'SELL'; - qty: number; - entryPrice: number; - stopLoss: number; - takeProfit: number; - userId?: string; - tradeId: string; - tradeIds: string[]; -} - -export interface StaleOrderScope { - profileId?: string; - userId?: string; - includeOrphanUserOrders?: boolean; - profileNullOnly?: boolean; -} - -export interface FilledLifecycleOrderRow { - id?: string; - order_id?: string | null; - user_id?: string | null; - profile_id?: string | null; - symbol?: string | null; - trade_id?: string | null; - action?: string | null; - side?: string | null; - qty?: number | string | null; - quantity?: number | string | null; - price?: number | string | null; - status?: string | null; - source?: string | null; - sub_tag?: string | null; - stop_loss?: number | string | null; - take_profit?: number | string | null; - timestamp?: number | string | null; - created_at?: string | null; - filled_at?: string | null; - type?: string | null; -} - -export interface ReconciliationBackfillOrderInsert { - user_id: string; - profile_id: string; - order_id: string; - symbol: string; - type: string; - side: string; - qty: number; - quantity: number; - price: number; - status: string; - timestamp: number; - filled_at?: string; - trade_id: string; - action: 'EXIT'; - source: 'BOT'; - sub_tag?: string; -} - -export interface ReconciliationBackfillAuditInsert { - batch_id: string; - profile_id: string; - symbol: string; - trade_id: string; - exchange_order_id?: string | null; - exchange_client_order_id?: string | null; - backfill_order_id?: string | null; - filled_qty?: number | null; - filled_price?: number | null; - filled_at?: string | null; - dry_run: boolean; - decision: string; - reason?: string | null; - metadata?: Record | null; - applied_at?: string | null; - reverted_at?: string | null; -} - -export interface ReconciliationBackfillAuditQuery { - profileId?: string; - symbol?: string; - batchId?: string; - decisions?: string[]; - fromIso?: string; - toIso?: string; - limit?: number; - offset?: number; -} - -export interface ReconciliationBackfillAuditRow { - id: number; - batch_id: string; - profile_id: string; - symbol: string; - trade_id: string; - exchange_order_id?: string | null; - exchange_client_order_id?: string | null; - backfill_order_id?: string | null; - filled_qty?: number | null; - filled_price?: number | null; - filled_at?: string | null; - dry_run: boolean; - decision: string; - reason?: string | null; - metadata?: Record | null; - applied_at?: string | null; - reverted_at?: string | null; - created_at: string; -} - -export interface ReconciliationBackfillBatchSummary { - batchId: string; - firstSeenAt: string; - lastSeenAt: string; - profileIds: string[]; - symbols: string[]; - totalRows: number; - byDecision: Record; - dryRunRows: number; - appliedRows: number; - revertedRows: number; -} - -export interface ReconciliationSubTagRepairSummary { - attempted: boolean; - unsupported?: boolean; - scannedRows: number; - eligibleRows: number; - updatedRows: number; - skippedNoProfile: number; - skippedNoTrade: number; - skippedTagDisabled: number; - skippedAlreadyTagged: number; - dryRun: boolean; -} - class SupabaseService { private client: SupabaseClient | null = null; private tradeHistorySupportsSource: boolean | null = null; diff --git a/backend/src/services/canonicalLifecycleService.ts b/backend/src/services/canonicalLifecycleService.ts index ea03c67..6822091 100644 --- a/backend/src/services/canonicalLifecycleService.ts +++ b/backend/src/services/canonicalLifecycleService.ts @@ -1,4 +1,4 @@ -import type { FilledLifecycleOrderRow } from './SupabaseService.js'; +import type { FilledLifecycleOrderRow } from './tradingPersistenceTypes.js'; export type CanonicalLifecycleState = 'OPEN' | 'PARTIAL_EXIT' | 'CLOSED' | 'ORPHAN_EXIT'; export type CanonicalSide = 'BUY' | 'SELL'; diff --git a/backend/src/services/reconciliationExitBackfillService.ts b/backend/src/services/reconciliationExitBackfillService.ts index 683bf27..4c9c065 100644 --- a/backend/src/services/reconciliationExitBackfillService.ts +++ b/backend/src/services/reconciliationExitBackfillService.ts @@ -4,11 +4,11 @@ import logger from '../utils/logger.js'; import { normalizeOrderAction, normalizeOrderStatus, normalizeTradeSide } from '../domain/tradingEnums.js'; import { healthTracker } from './healthTracker.js'; import { observabilityService } from './observabilityService.js'; -import { +import type { FilledLifecycleOrderRow, ReconciliationBackfillAuditInsert, ReconciliationBackfillOrderInsert -} from './SupabaseService.js'; +} from './tradingPersistenceTypes.js'; import * as runtimeOrderRepository from './runtimeOrderRepository.js'; import type { TradeExecutor } from './TradeExecutor.js'; import { diff --git a/backend/src/services/reconciliationSubTagRepairService.ts b/backend/src/services/reconciliationSubTagRepairService.ts index eb233e4..bbfc4bf 100644 --- a/backend/src/services/reconciliationSubTagRepairService.ts +++ b/backend/src/services/reconciliationSubTagRepairService.ts @@ -1,9 +1,7 @@ import { config } from '../config/index.js'; import logger from '../utils/logger.js'; import { observabilityService } from './observabilityService.js'; -import { - type ReconciliationSubTagRepairSummary -} from './SupabaseService.js'; +import type { ReconciliationSubTagRepairSummary } from './tradingPersistenceTypes.js'; import { repairMissingSubTagsForProfile } from './runtimeOrderRepository.js'; export interface ReconciliationSubTagRepairContext { diff --git a/backend/src/services/runtimeOrderRepository.ts b/backend/src/services/runtimeOrderRepository.ts index 90d256e..8941951 100644 --- a/backend/src/services/runtimeOrderRepository.ts +++ b/backend/src/services/runtimeOrderRepository.ts @@ -25,7 +25,7 @@ import type { ReconciliationSubTagRepairSummary, StaleOrderScope, VirtualOpenPosition -} from './SupabaseService.js'; +} from './tradingPersistenceTypes.js'; import { ORDER_CONTAINER, RECONCILIATION_AUDIT_CONTAINER, diff --git a/backend/src/services/tradingPersistenceTypes.ts b/backend/src/services/tradingPersistenceTypes.ts new file mode 100644 index 0000000..5625823 --- /dev/null +++ b/backend/src/services/tradingPersistenceTypes.ts @@ -0,0 +1,143 @@ +/** + * Shared shapes for orders, reconciliation audit, and virtual positions. + * Used by Cosmos-first repositories and legacy SupabaseService persistence. + */ + +export interface VirtualOpenPosition { + profileId: string; + symbol: string; + side: 'BUY' | 'SELL'; + qty: number; + entryPrice: number; + stopLoss: number; + takeProfit: number; + userId?: string; + tradeId: string; + tradeIds: string[]; +} + +export interface StaleOrderScope { + profileId?: string; + userId?: string; + includeOrphanUserOrders?: boolean; + profileNullOnly?: boolean; +} + +export interface FilledLifecycleOrderRow { + id?: string; + order_id?: string | null; + user_id?: string | null; + profile_id?: string | null; + symbol?: string | null; + trade_id?: string | null; + action?: string | null; + side?: string | null; + qty?: number | string | null; + quantity?: number | string | null; + price?: number | string | null; + status?: string | null; + source?: string | null; + sub_tag?: string | null; + stop_loss?: number | string | null; + take_profit?: number | string | null; + timestamp?: number | string | null; + created_at?: string | null; + filled_at?: string | null; + type?: string | null; +} + +export interface ReconciliationBackfillOrderInsert { + user_id: string; + profile_id: string; + order_id: string; + symbol: string; + type: string; + side: string; + qty: number; + quantity: number; + price: number; + status: string; + timestamp: number; + filled_at?: string; + trade_id: string; + action: 'EXIT'; + source: 'BOT'; + sub_tag?: string; +} + +export interface ReconciliationBackfillAuditInsert { + batch_id: string; + profile_id: string; + symbol: string; + trade_id: string; + exchange_order_id?: string | null; + exchange_client_order_id?: string | null; + backfill_order_id?: string | null; + filled_qty?: number | null; + filled_price?: number | null; + filled_at?: string | null; + dry_run: boolean; + decision: string; + reason?: string | null; + metadata?: Record | null; + applied_at?: string | null; + reverted_at?: string | null; +} + +export interface ReconciliationBackfillAuditQuery { + profileId?: string; + symbol?: string; + batchId?: string; + decisions?: string[]; + fromIso?: string; + toIso?: string; + limit?: number; + offset?: number; +} + +export interface ReconciliationBackfillAuditRow { + id: number; + batch_id: string; + profile_id: string; + symbol: string; + trade_id: string; + exchange_order_id?: string | null; + exchange_client_order_id?: string | null; + backfill_order_id?: string | null; + filled_qty?: number | null; + filled_price?: number | null; + filled_at?: string | null; + dry_run: boolean; + decision: string; + reason?: string | null; + metadata?: Record | null; + applied_at?: string | null; + reverted_at?: string | null; + created_at: string; +} + +export interface ReconciliationBackfillBatchSummary { + batchId: string; + firstSeenAt: string; + lastSeenAt: string; + profileIds: string[]; + symbols: string[]; + totalRows: number; + byDecision: Record; + dryRunRows: number; + appliedRows: number; + revertedRows: number; +} + +export interface ReconciliationSubTagRepairSummary { + attempted: boolean; + unsupported?: boolean; + scannedRows: number; + eligibleRows: number; + updatedRows: number; + skippedNoProfile: number; + skippedNoTrade: number; + skippedTagDisabled: number; + skippedAlreadyTagged: number; + dryRun: boolean; +}