feat: Update TypeScript types across modules
Updated types: - audit.types.ts: Enhanced audit trail types - auth.types.ts: Session and token types - education.types.ts, reviews.types.ts: Course and enrollment types - investment.types.ts: Portfolio types - llm.types.ts: LLM integration types - market-data.types.ts: Market data types - financial.types.ts: Payment processing types New: - trading/entity.types.ts: Trading entity definitions Services: - Update course and enrollment services Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
58a7b44673
commit
c91b8e5419
@ -237,3 +237,286 @@ export interface AuditStats {
|
||||
bySeverity: Record<EventSeverity, number>;
|
||||
criticalEvents: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// System Events Types (from 03-system_events.sql)
|
||||
// ============================================================================
|
||||
|
||||
export type SystemEventType =
|
||||
| 'startup'
|
||||
| 'shutdown'
|
||||
| 'job_start'
|
||||
| 'job_complete'
|
||||
| 'job_failed'
|
||||
| 'health_check'
|
||||
| 'config_reload'
|
||||
| 'error'
|
||||
| 'warning'
|
||||
| 'maintenance';
|
||||
|
||||
export type SystemEnvironment =
|
||||
| 'development'
|
||||
| 'staging'
|
||||
| 'production';
|
||||
|
||||
export interface SystemEvent {
|
||||
id: string;
|
||||
eventType: string;
|
||||
severity: EventSeverity;
|
||||
serviceName: string;
|
||||
component: string | null;
|
||||
environment: SystemEnvironment;
|
||||
hostname: string | null;
|
||||
eventName: string;
|
||||
message: string;
|
||||
stackTrace: string | null;
|
||||
correlationId: string | null;
|
||||
jobId: string | null;
|
||||
durationMs: number | null;
|
||||
metadata: Record<string, unknown>;
|
||||
tags: string[] | null;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateSystemEventInput {
|
||||
eventType: string;
|
||||
severity?: EventSeverity;
|
||||
serviceName: string;
|
||||
component?: string;
|
||||
environment?: SystemEnvironment;
|
||||
hostname?: string;
|
||||
eventName: string;
|
||||
message: string;
|
||||
stackTrace?: string;
|
||||
correlationId?: string;
|
||||
jobId?: string;
|
||||
durationMs?: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface SystemEventFilters {
|
||||
eventType?: string;
|
||||
severity?: EventSeverity;
|
||||
serviceName?: string;
|
||||
environment?: SystemEnvironment;
|
||||
jobId?: string;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Trading Audit Types (from 04-trading_audit.sql)
|
||||
// ============================================================================
|
||||
|
||||
export type TradingAction =
|
||||
| 'order_placed'
|
||||
| 'order_filled'
|
||||
| 'order_cancelled'
|
||||
| 'position_opened'
|
||||
| 'position_closed'
|
||||
| 'position_modified'
|
||||
| 'stop_loss_triggered'
|
||||
| 'take_profit_triggered';
|
||||
|
||||
export type TradingSide = 'buy' | 'sell';
|
||||
|
||||
export type OrderType =
|
||||
| 'market'
|
||||
| 'limit'
|
||||
| 'stop'
|
||||
| 'stop_limit'
|
||||
| 'trailing_stop';
|
||||
|
||||
export interface TradingAudit {
|
||||
id: string;
|
||||
userId: string;
|
||||
botId: string | null;
|
||||
action: string;
|
||||
actionStatus: EventStatus;
|
||||
orderId: string | null;
|
||||
positionId: string | null;
|
||||
symbol: string;
|
||||
side: TradingSide;
|
||||
orderType: OrderType | null;
|
||||
quantity: string;
|
||||
price: string | null;
|
||||
executedPrice: string | null;
|
||||
pnl: string | null;
|
||||
fees: string | null;
|
||||
strategyId: string | null;
|
||||
signalId: string | null;
|
||||
isPaperTrading: boolean;
|
||||
executionTimeMs: number | null;
|
||||
brokerResponse: Record<string, unknown> | null;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateTradingAuditInput {
|
||||
userId: string;
|
||||
botId?: string;
|
||||
action: string;
|
||||
actionStatus: EventStatus;
|
||||
orderId?: string;
|
||||
positionId?: string;
|
||||
symbol: string;
|
||||
side: TradingSide;
|
||||
orderType?: OrderType;
|
||||
quantity: string;
|
||||
price?: string;
|
||||
executedPrice?: string;
|
||||
pnl?: string;
|
||||
fees?: string;
|
||||
strategyId?: string;
|
||||
signalId?: string;
|
||||
isPaperTrading?: boolean;
|
||||
executionTimeMs?: number;
|
||||
brokerResponse?: Record<string, unknown>;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface TradingAuditFilters {
|
||||
userId?: string;
|
||||
botId?: string;
|
||||
symbol?: string;
|
||||
action?: string;
|
||||
side?: TradingSide;
|
||||
isPaperTrading?: boolean;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// API Request Logs Types (from 05-api_request_logs.sql)
|
||||
// ============================================================================
|
||||
|
||||
export type HttpMethod =
|
||||
| 'GET'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'PATCH'
|
||||
| 'DELETE'
|
||||
| 'OPTIONS'
|
||||
| 'HEAD';
|
||||
|
||||
export interface ApiRequestLog {
|
||||
id: string;
|
||||
requestId: string;
|
||||
method: HttpMethod;
|
||||
path: string;
|
||||
queryParams: Record<string, unknown> | null;
|
||||
headers: Record<string, unknown> | null;
|
||||
bodySize: number | null;
|
||||
userId: string | null;
|
||||
apiKeyId: string | null;
|
||||
ipAddress: string;
|
||||
userAgent: string | null;
|
||||
statusCode: number;
|
||||
responseSize: number | null;
|
||||
responseTimeMs: number;
|
||||
serviceName: string | null;
|
||||
version: string | null;
|
||||
errorCode: string | null;
|
||||
errorMessage: string | null;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateApiRequestLogInput {
|
||||
requestId: string;
|
||||
method: HttpMethod;
|
||||
path: string;
|
||||
queryParams?: Record<string, unknown>;
|
||||
headers?: Record<string, unknown>;
|
||||
bodySize?: number;
|
||||
userId?: string;
|
||||
apiKeyId?: string;
|
||||
ipAddress: string;
|
||||
userAgent?: string;
|
||||
statusCode: number;
|
||||
responseSize?: number;
|
||||
responseTimeMs: number;
|
||||
serviceName?: string;
|
||||
version?: string;
|
||||
errorCode?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
export interface ApiRequestLogFilters {
|
||||
userId?: string;
|
||||
method?: HttpMethod;
|
||||
path?: string;
|
||||
statusCode?: number;
|
||||
minResponseTime?: number;
|
||||
ipAddress?: string;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Data Access Logs Types (from 06-data_access_logs.sql)
|
||||
// ============================================================================
|
||||
|
||||
export type DataCategory =
|
||||
| 'pii'
|
||||
| 'financial'
|
||||
| 'health'
|
||||
| 'credentials';
|
||||
|
||||
export type DataAccessType =
|
||||
| 'view'
|
||||
| 'export'
|
||||
| 'modify'
|
||||
| 'delete';
|
||||
|
||||
export interface DataAccessLog {
|
||||
id: string;
|
||||
accessorUserId: string;
|
||||
accessorRole: string;
|
||||
targetUserId: string | null;
|
||||
dataCategory: DataCategory;
|
||||
dataFields: string[] | null;
|
||||
accessType: DataAccessType;
|
||||
accessReason: string | null;
|
||||
requestId: string | null;
|
||||
ipAddress: string | null;
|
||||
userAgent: string | null;
|
||||
consentVerified: boolean;
|
||||
legalBasis: string | null;
|
||||
retentionDays: number | null;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateDataAccessLogInput {
|
||||
accessorUserId: string;
|
||||
accessorRole: string;
|
||||
targetUserId?: string;
|
||||
dataCategory: DataCategory;
|
||||
dataFields?: string[];
|
||||
accessType: DataAccessType;
|
||||
accessReason?: string;
|
||||
requestId?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
consentVerified?: boolean;
|
||||
legalBasis?: string;
|
||||
retentionDays?: number;
|
||||
}
|
||||
|
||||
export interface DataAccessLogFilters {
|
||||
accessorUserId?: string;
|
||||
targetUserId?: string;
|
||||
dataCategory?: DataCategory;
|
||||
accessType?: DataAccessType;
|
||||
consentVerified?: boolean;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
@ -218,3 +218,311 @@ export interface JWTRefreshPayload {
|
||||
iat: number;
|
||||
exp: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phone Channel Type (DDL: auth.phone_channel)
|
||||
// ============================================================================
|
||||
export type PhoneChannel = 'sms' | 'whatsapp';
|
||||
|
||||
// ============================================================================
|
||||
// Auth Event Type (DDL: auth.auth_event_type)
|
||||
// ============================================================================
|
||||
export type AuthEventType =
|
||||
| 'login'
|
||||
| 'logout'
|
||||
| 'register'
|
||||
| 'password_change'
|
||||
| 'password_reset_request'
|
||||
| 'password_reset_complete'
|
||||
| 'email_verification'
|
||||
| 'phone_verification'
|
||||
| 'mfa_enabled'
|
||||
| 'mfa_disabled'
|
||||
| 'session_expired'
|
||||
| 'account_suspended'
|
||||
| 'account_reactivated'
|
||||
| 'failed_login'
|
||||
| 'oauth_linked'
|
||||
| 'oauth_unlinked';
|
||||
|
||||
// ============================================================================
|
||||
// Rate Limit Scope Type
|
||||
// ============================================================================
|
||||
export type RateLimitScope = 'ip' | 'user' | 'email' | 'global';
|
||||
|
||||
// ============================================================================
|
||||
// Notification Types
|
||||
// ============================================================================
|
||||
export type NotificationType =
|
||||
| 'alert_triggered'
|
||||
| 'trade_executed'
|
||||
| 'deposit_confirmed'
|
||||
| 'withdrawal_completed'
|
||||
| 'distribution_received'
|
||||
| 'system_announcement'
|
||||
| 'security_alert'
|
||||
| 'account_update';
|
||||
|
||||
export type NotificationPriority = 'low' | 'normal' | 'high' | 'urgent';
|
||||
export type NotificationIconType = 'success' | 'warning' | 'error' | 'info';
|
||||
export type PushPlatform = 'web' | 'ios' | 'android';
|
||||
|
||||
// ============================================================================
|
||||
// Email Verification (DDL: auth.email_verifications)
|
||||
// ============================================================================
|
||||
export interface EmailVerification {
|
||||
id: string;
|
||||
userId: string;
|
||||
email: string;
|
||||
token: string;
|
||||
expiresAt: Date;
|
||||
verifiedAt?: Date;
|
||||
isVerified: boolean;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.email_verifications */
|
||||
export interface EmailVerificationRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
email: string;
|
||||
token: string;
|
||||
expires_at: Date;
|
||||
verified_at: Date | null;
|
||||
is_verified: boolean;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phone Verification (DDL: auth.phone_verifications)
|
||||
// ============================================================================
|
||||
export interface PhoneVerification {
|
||||
id: string;
|
||||
userId: string;
|
||||
phoneNumber: string;
|
||||
verificationCode: string;
|
||||
channel: PhoneChannel;
|
||||
expiresAt: Date;
|
||||
verifiedAt?: Date;
|
||||
isVerified: boolean;
|
||||
sendAttempts: number;
|
||||
verificationAttempts: number;
|
||||
maxAttempts: number;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.phone_verifications */
|
||||
export interface PhoneVerificationRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
phone_number: string;
|
||||
verification_code: string;
|
||||
channel: PhoneChannel;
|
||||
expires_at: Date;
|
||||
verified_at: Date | null;
|
||||
is_verified: boolean;
|
||||
send_attempts: number;
|
||||
verification_attempts: number;
|
||||
max_attempts: number;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Password Reset Token (DDL: auth.password_reset_tokens)
|
||||
// ============================================================================
|
||||
export interface PasswordResetToken {
|
||||
id: string;
|
||||
userId: string;
|
||||
email: string;
|
||||
token: string;
|
||||
expiresAt: Date;
|
||||
usedAt?: Date;
|
||||
isUsed: boolean;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.password_reset_tokens */
|
||||
export interface PasswordResetTokenRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
email: string;
|
||||
token: string;
|
||||
expires_at: Date;
|
||||
used_at: Date | null;
|
||||
is_used: boolean;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Auth Log (DDL: auth.auth_logs)
|
||||
// ============================================================================
|
||||
export interface AuthLog {
|
||||
id: string;
|
||||
eventType: AuthEventType;
|
||||
userId?: string;
|
||||
email?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
sessionId?: string;
|
||||
success: boolean;
|
||||
failureReason?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.auth_logs */
|
||||
export interface AuthLogRow {
|
||||
id: string;
|
||||
event_type: AuthEventType;
|
||||
user_id: string | null;
|
||||
email: string | null;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
session_id: string | null;
|
||||
success: boolean;
|
||||
failure_reason: string | null;
|
||||
metadata: Record<string, unknown> | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Login Attempt (DDL: auth.login_attempts)
|
||||
// ============================================================================
|
||||
export interface LoginAttempt {
|
||||
id: string;
|
||||
email?: string;
|
||||
userId?: string;
|
||||
ipAddress: string;
|
||||
userAgent?: string;
|
||||
success: boolean;
|
||||
failureReason?: string;
|
||||
attemptedAt: Date;
|
||||
metadata?: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.login_attempts */
|
||||
export interface LoginAttemptRow {
|
||||
id: string;
|
||||
email: string | null;
|
||||
user_id: string | null;
|
||||
ip_address: string;
|
||||
user_agent: string | null;
|
||||
success: boolean;
|
||||
failure_reason: string | null;
|
||||
attempted_at: Date;
|
||||
metadata: Record<string, unknown> | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Rate Limiting Config (DDL: auth.rate_limiting_config)
|
||||
// ============================================================================
|
||||
export interface RateLimitingConfig {
|
||||
id: string;
|
||||
endpoint: string;
|
||||
description?: string;
|
||||
maxRequests: number;
|
||||
windowSeconds: number;
|
||||
blockDurationSeconds?: number;
|
||||
scope: RateLimitScope;
|
||||
isActive: boolean;
|
||||
metadata?: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdById?: string;
|
||||
updatedById?: string;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.rate_limiting_config */
|
||||
export interface RateLimitingConfigRow {
|
||||
id: string;
|
||||
endpoint: string;
|
||||
description: string | null;
|
||||
max_requests: number;
|
||||
window_seconds: number;
|
||||
block_duration_seconds: number | null;
|
||||
scope: RateLimitScope;
|
||||
is_active: boolean;
|
||||
metadata: Record<string, unknown> | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
created_by_id: string | null;
|
||||
updated_by_id: string | null;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Notification (DDL: auth.notifications)
|
||||
// ============================================================================
|
||||
export interface Notification {
|
||||
id: string;
|
||||
userId: string;
|
||||
type: NotificationType;
|
||||
title: string;
|
||||
message: string;
|
||||
priority: NotificationPriority;
|
||||
data?: Record<string, unknown>;
|
||||
actionUrl?: string;
|
||||
iconType: NotificationIconType;
|
||||
channels: string[];
|
||||
isRead: boolean;
|
||||
readAt?: Date;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.notifications */
|
||||
export interface NotificationRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
type: NotificationType;
|
||||
title: string;
|
||||
message: string;
|
||||
priority: NotificationPriority;
|
||||
data: Record<string, unknown> | null;
|
||||
action_url: string | null;
|
||||
icon_type: NotificationIconType;
|
||||
channels: string[];
|
||||
is_read: boolean;
|
||||
read_at: Date | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// User Push Token (DDL: auth.user_push_tokens)
|
||||
// ============================================================================
|
||||
export interface UserPushToken {
|
||||
id: string;
|
||||
userId: string;
|
||||
token: string;
|
||||
platform: PushPlatform;
|
||||
deviceInfo?: Record<string, unknown>;
|
||||
isActive: boolean;
|
||||
lastUsedAt?: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/** Database row type (snake_case) for auth.user_push_tokens */
|
||||
export interface UserPushTokenRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
token: string;
|
||||
platform: PushPlatform;
|
||||
device_info: Record<string, unknown> | null;
|
||||
is_active: boolean;
|
||||
last_used_at: Date | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
@ -102,18 +102,23 @@ class CourseService {
|
||||
|
||||
async getCategories(): Promise<Category[]> {
|
||||
const result = await db.query<Record<string, unknown>>(
|
||||
`SELECT * FROM education.categories ORDER BY sort_order, name`
|
||||
`SELECT * FROM education.categories ORDER BY display_order, name`
|
||||
);
|
||||
return result.rows.map((row) => ({
|
||||
id: row.id as string,
|
||||
name: row.name as string,
|
||||
slug: row.slug as string,
|
||||
description: row.description as string | undefined,
|
||||
icon: row.icon as string | undefined,
|
||||
parentId: row.parent_id as string | undefined,
|
||||
sortOrder: row.sort_order as number,
|
||||
displayOrder: (row.display_order as number) || 0,
|
||||
iconUrl: row.icon_url as string | undefined,
|
||||
color: row.color as string | undefined,
|
||||
isActive: (row.is_active as boolean) ?? true,
|
||||
createdAt: new Date(row.created_at as string),
|
||||
updatedAt: new Date(row.updated_at as string),
|
||||
// Backward-compatible aliases
|
||||
sortOrder: (row.display_order as number) || 0,
|
||||
icon: row.icon_url as string | undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
@ -129,21 +134,31 @@ class CourseService {
|
||||
name: row.name as string,
|
||||
slug: row.slug as string,
|
||||
description: row.description as string | undefined,
|
||||
icon: row.icon as string | undefined,
|
||||
parentId: row.parent_id as string | undefined,
|
||||
sortOrder: row.sort_order as number,
|
||||
displayOrder: (row.display_order as number) || 0,
|
||||
iconUrl: row.icon_url as string | undefined,
|
||||
color: row.color as string | undefined,
|
||||
isActive: (row.is_active as boolean) ?? true,
|
||||
createdAt: new Date(row.created_at as string),
|
||||
updatedAt: new Date(row.updated_at as string),
|
||||
// Backward-compatible aliases
|
||||
sortOrder: (row.display_order as number) || 0,
|
||||
icon: row.icon_url as string | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
async createCategory(input: CreateCategoryInput): Promise<Category> {
|
||||
const slug = input.slug || generateSlug(input.name);
|
||||
// Support both new and deprecated field names
|
||||
const iconUrl = input.iconUrl || input.icon;
|
||||
const displayOrder = input.displayOrder ?? input.sortOrder ?? 0;
|
||||
const isActive = input.isActive ?? true;
|
||||
|
||||
const result = await db.query<Record<string, unknown>>(
|
||||
`INSERT INTO education.categories (name, slug, description, icon, parent_id, sort_order)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`INSERT INTO education.categories (name, slug, description, icon_url, color, parent_id, display_order, is_active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *`,
|
||||
[input.name, slug, input.description, input.icon, input.parentId, input.sortOrder || 0]
|
||||
[input.name, slug, input.description, iconUrl, input.color, input.parentId, displayOrder, isActive]
|
||||
);
|
||||
const row = result.rows[0];
|
||||
return {
|
||||
@ -151,11 +166,16 @@ class CourseService {
|
||||
name: row.name as string,
|
||||
slug: row.slug as string,
|
||||
description: row.description as string | undefined,
|
||||
icon: row.icon as string | undefined,
|
||||
parentId: row.parent_id as string | undefined,
|
||||
sortOrder: row.sort_order as number,
|
||||
displayOrder: (row.display_order as number) || 0,
|
||||
iconUrl: row.icon_url as string | undefined,
|
||||
color: row.color as string | undefined,
|
||||
isActive: (row.is_active as boolean) ?? true,
|
||||
createdAt: new Date(row.created_at as string),
|
||||
updatedAt: new Date(row.updated_at as string),
|
||||
// Backward-compatible aliases
|
||||
sortOrder: (row.display_order as number) || 0,
|
||||
icon: row.icon_url as string | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -40,20 +40,32 @@ function transformEnrollment(row: Record<string, unknown>): Enrollment {
|
||||
}
|
||||
|
||||
function transformLessonProgress(row: Record<string, unknown>): LessonProgress {
|
||||
const isCompleted = (row.is_completed || row.video_completed) as boolean || false;
|
||||
const lastPosition = (row.last_position_seconds || row.video_progress_seconds || row.video_watched_seconds || 0) as number;
|
||||
const totalWatch = (row.total_watch_time_seconds || row.video_watched_seconds || 0) as number;
|
||||
const watchPct = parseFloat(row.watch_percentage as string) || 0;
|
||||
|
||||
return {
|
||||
id: row.id as string,
|
||||
userId: row.user_id as string,
|
||||
enrollmentId: row.enrollment_id as string,
|
||||
lessonId: row.lesson_id as string,
|
||||
isCompleted: (row.is_completed || row.video_completed) as boolean || false,
|
||||
videoProgressSeconds: row.video_progress_seconds as number | undefined,
|
||||
enrollmentId: row.enrollment_id as string,
|
||||
isCompleted,
|
||||
lastPositionSeconds: lastPosition,
|
||||
totalWatchTimeSeconds: totalWatch,
|
||||
watchPercentage: watchPct,
|
||||
firstViewedAt: row.first_viewed_at ? new Date(row.first_viewed_at as string) : undefined,
|
||||
lastViewedAt: row.last_viewed_at ? new Date(row.last_viewed_at as string) : undefined,
|
||||
completedAt: row.completed_at ? new Date(row.completed_at as string) : undefined,
|
||||
xpEarned: (row.xp_earned as number) || 0,
|
||||
notes: row.notes as string | undefined,
|
||||
createdAt: new Date(row.created_at as string),
|
||||
updatedAt: new Date(row.updated_at as string),
|
||||
videoWatchedSeconds: row.video_watched_seconds as number,
|
||||
videoCompleted: (row.is_completed || row.video_completed) as boolean || false,
|
||||
// Backward-compatible aliases
|
||||
videoProgressSeconds: lastPosition,
|
||||
videoWatchedSeconds: totalWatch,
|
||||
videoCompleted: isCompleted,
|
||||
startedAt: row.first_viewed_at ? new Date(row.first_viewed_at as string) : undefined,
|
||||
xpEarned: (row.xp_earned as number) || 0,
|
||||
notes: row.notes as string | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ export enum AchievementTypeEnum {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Category
|
||||
// Category (Aligned with education.categories DDL)
|
||||
// ============================================================================
|
||||
|
||||
export interface Category {
|
||||
@ -88,22 +88,54 @@ export interface Category {
|
||||
name: string;
|
||||
slug: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
parentId?: string;
|
||||
sortOrder: number;
|
||||
displayOrder: number;
|
||||
iconUrl?: string;
|
||||
color?: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
// Backward-compatible aliases
|
||||
/** @deprecated Use displayOrder instead */
|
||||
sortOrder?: number;
|
||||
/** @deprecated Use iconUrl instead */
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
/** Row type for DB mapping (snake_case) - education.categories */
|
||||
export interface CategoryRow {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string | null;
|
||||
parent_id: string | null;
|
||||
display_order: number;
|
||||
icon_url: string | null;
|
||||
color: string | null;
|
||||
is_active: boolean;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface CreateCategoryInput {
|
||||
name: string;
|
||||
slug?: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
iconUrl?: string;
|
||||
color?: string;
|
||||
parentId?: string;
|
||||
displayOrder?: number;
|
||||
isActive?: boolean;
|
||||
// Backward-compatible aliases
|
||||
/** @deprecated Use iconUrl instead */
|
||||
icon?: string;
|
||||
/** @deprecated Use displayOrder instead */
|
||||
sortOrder?: number;
|
||||
}
|
||||
|
||||
export interface UpdateCategoryInput extends Partial<CreateCategoryInput> {}
|
||||
|
||||
// ============================================================================
|
||||
// Course (Aligned with education.courses DDL)
|
||||
// ============================================================================
|
||||
@ -402,27 +434,61 @@ export interface CreateEnrollmentInput {
|
||||
export interface LessonProgress {
|
||||
id: string;
|
||||
userId: string;
|
||||
enrollmentId: string;
|
||||
lessonId: string;
|
||||
enrollmentId: string;
|
||||
isCompleted: boolean;
|
||||
videoProgressSeconds?: number;
|
||||
lastPositionSeconds: number;
|
||||
totalWatchTimeSeconds: number;
|
||||
watchPercentage: number;
|
||||
firstViewedAt?: Date;
|
||||
lastViewedAt?: Date;
|
||||
completedAt?: Date;
|
||||
startedAt?: Date;
|
||||
xpEarned: number;
|
||||
notes?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
// Backward-compatible aliases
|
||||
/** @deprecated Use videoProgressSeconds instead */
|
||||
/** @deprecated Use lastPositionSeconds instead */
|
||||
videoProgressSeconds?: number;
|
||||
/** @deprecated Use lastPositionSeconds instead */
|
||||
videoWatchedSeconds?: number;
|
||||
/** @deprecated Use isCompleted instead */
|
||||
videoCompleted?: boolean;
|
||||
/** @deprecated Use firstViewedAt instead */
|
||||
startedAt?: Date;
|
||||
/** @deprecated Not in DDL - use generic metadata if needed */
|
||||
xpEarned?: number;
|
||||
/** @deprecated Not in DDL - use generic metadata if needed */
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
/** Row type for DB mapping (snake_case) - education.progress */
|
||||
export interface LessonProgressRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
lesson_id: string;
|
||||
enrollment_id: string;
|
||||
is_completed: boolean;
|
||||
last_position_seconds: number;
|
||||
total_watch_time_seconds: number;
|
||||
watch_percentage: string; // DECIMAL comes as string from PG
|
||||
first_viewed_at: Date | null;
|
||||
last_viewed_at: Date | null;
|
||||
completed_at: Date | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface UpdateLessonProgressInput {
|
||||
lastPositionSeconds?: number;
|
||||
totalWatchTimeSeconds?: number;
|
||||
watchPercentage?: number;
|
||||
isCompleted?: boolean;
|
||||
completedAt?: Date;
|
||||
/** @deprecated Use lastPositionSeconds instead */
|
||||
videoWatchedSeconds?: number;
|
||||
/** @deprecated Use isCompleted instead */
|
||||
videoCompleted?: boolean;
|
||||
/** @deprecated Not in DDL */
|
||||
userNotes?: string;
|
||||
}
|
||||
|
||||
@ -616,6 +682,179 @@ export interface CreateActivityLogInput {
|
||||
userAgent?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Video (Aligned with education.videos DDL)
|
||||
// ============================================================================
|
||||
|
||||
export type VideoStatus = 'uploading' | 'uploaded' | 'processing' | 'ready' | 'error' | 'deleted';
|
||||
export type VideoStorageProvider = 's3' | 'r2' | 'cloudflare_stream';
|
||||
|
||||
export interface VideoTranscodedVersion {
|
||||
resolution: string; // e.g., '1080p', '720p', '480p'
|
||||
storageKey: string;
|
||||
cdnUrl: string;
|
||||
fileSizeBytes: number;
|
||||
}
|
||||
|
||||
export interface VideoCaption {
|
||||
language: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface VideoMetadata {
|
||||
tags?: string[];
|
||||
language?: string;
|
||||
difficulty?: DifficultyLevel;
|
||||
captions?: VideoCaption[];
|
||||
transcript?: string;
|
||||
videoCodec?: string;
|
||||
audioCodec?: string;
|
||||
bitrateKbps?: number;
|
||||
fps?: number;
|
||||
resolution?: string; // e.g., '1920x1080'
|
||||
}
|
||||
|
||||
export interface Video {
|
||||
id: string;
|
||||
courseId: string;
|
||||
lessonId?: string;
|
||||
uploadedBy: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
originalFilename: string;
|
||||
storageProvider: VideoStorageProvider;
|
||||
storageBucket: string;
|
||||
storageKey: string;
|
||||
storageRegion?: string;
|
||||
fileSizeBytes: number;
|
||||
mimeType: string;
|
||||
durationSeconds?: number;
|
||||
status: VideoStatus;
|
||||
processingStartedAt?: Date;
|
||||
processingCompletedAt?: Date;
|
||||
processingError?: string;
|
||||
cdnUrl?: string;
|
||||
thumbnailUrl?: string;
|
||||
transcodedVersions?: VideoTranscodedVersion[];
|
||||
metadata: VideoMetadata;
|
||||
uploadId?: string;
|
||||
uploadPartsCompleted: number;
|
||||
uploadPartsTotal?: number;
|
||||
uploadProgressPercent: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
uploadedAt?: Date;
|
||||
deletedAt?: Date;
|
||||
}
|
||||
|
||||
/** Row type for DB mapping (snake_case) - education.videos */
|
||||
export interface VideoRow {
|
||||
id: string;
|
||||
course_id: string;
|
||||
lesson_id: string | null;
|
||||
uploaded_by: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
original_filename: string;
|
||||
storage_provider: string;
|
||||
storage_bucket: string;
|
||||
storage_key: string;
|
||||
storage_region: string | null;
|
||||
file_size_bytes: string; // BIGINT comes as string from PG
|
||||
mime_type: string;
|
||||
duration_seconds: number | null;
|
||||
status: string;
|
||||
processing_started_at: Date | null;
|
||||
processing_completed_at: Date | null;
|
||||
processing_error: string | null;
|
||||
cdn_url: string | null;
|
||||
thumbnail_url: string | null;
|
||||
transcoded_versions: unknown; // JSONB
|
||||
metadata: unknown; // JSONB
|
||||
upload_id: string | null;
|
||||
upload_parts_completed: number;
|
||||
upload_parts_total: number | null;
|
||||
upload_progress_percent: number;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
uploaded_at: Date | null;
|
||||
deleted_at: Date | null;
|
||||
}
|
||||
|
||||
export interface CreateVideoInput {
|
||||
courseId: string;
|
||||
lessonId?: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
originalFilename: string;
|
||||
storageBucket: string;
|
||||
storageKey: string;
|
||||
storageProvider?: VideoStorageProvider;
|
||||
storageRegion?: string;
|
||||
fileSizeBytes: number;
|
||||
mimeType?: string;
|
||||
metadata?: VideoMetadata;
|
||||
uploadPartsTotal?: number;
|
||||
}
|
||||
|
||||
export interface UpdateVideoInput {
|
||||
title?: string;
|
||||
description?: string;
|
||||
lessonId?: string;
|
||||
status?: VideoStatus;
|
||||
durationSeconds?: number;
|
||||
cdnUrl?: string;
|
||||
thumbnailUrl?: string;
|
||||
transcodedVersions?: VideoTranscodedVersion[];
|
||||
metadata?: VideoMetadata;
|
||||
processingStartedAt?: Date;
|
||||
processingCompletedAt?: Date;
|
||||
processingError?: string;
|
||||
uploadPartsCompleted?: number;
|
||||
uploadProgressPercent?: number;
|
||||
uploadedAt?: Date;
|
||||
}
|
||||
|
||||
export interface InitiateMultipartUploadInput {
|
||||
courseId: string;
|
||||
lessonId?: string;
|
||||
title: string;
|
||||
originalFilename: string;
|
||||
fileSizeBytes: number;
|
||||
mimeType: string;
|
||||
partsTotal: number;
|
||||
}
|
||||
|
||||
export interface CompleteMultipartUploadInput {
|
||||
videoId: string;
|
||||
uploadId: string;
|
||||
parts: { partNumber: number; eTag: string }[];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Review Helpful Votes (Aligned with education.review_helpful_votes DDL)
|
||||
// ============================================================================
|
||||
|
||||
export interface ReviewHelpfulVote {
|
||||
id: string;
|
||||
userId: string;
|
||||
reviewId: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
/** Row type for DB mapping (snake_case) - education.review_helpful_votes */
|
||||
export interface ReviewHelpfulVoteRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
review_id: string;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface CreateReviewHelpfulVoteInput {
|
||||
userId: string;
|
||||
reviewId: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Attachments (for lesson attachments JSONB field)
|
||||
// ============================================================================
|
||||
|
||||
@ -19,10 +19,29 @@ export interface CourseReview {
|
||||
helpfulVotes: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
// Computed/joined fields (not in DDL)
|
||||
userName?: string;
|
||||
userAvatar?: string;
|
||||
}
|
||||
|
||||
/** Row type for DB mapping (snake_case) - education.course_reviews */
|
||||
export interface CourseReviewRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
course_id: string;
|
||||
enrollment_id: string;
|
||||
rating: number;
|
||||
title: string | null;
|
||||
content: string | null;
|
||||
is_approved: boolean;
|
||||
is_featured: boolean;
|
||||
approved_by: string | null;
|
||||
approved_at: Date | null;
|
||||
helpful_votes: number;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface CourseReviewWithUser extends CourseReview {
|
||||
user: {
|
||||
id: string;
|
||||
|
||||
@ -69,6 +69,32 @@ export enum TransactionStatusEnum {
|
||||
CANCELLED = 'cancelled',
|
||||
}
|
||||
|
||||
// Alineado con investment.withdrawal_status (DDL 06-withdrawal_requests.sql)
|
||||
export type WithdrawalStatus =
|
||||
| 'pending'
|
||||
| 'under_review'
|
||||
| 'approved'
|
||||
| 'processing'
|
||||
| 'completed'
|
||||
| 'rejected'
|
||||
| 'cancelled';
|
||||
|
||||
export enum WithdrawalStatusEnum {
|
||||
PENDING = 'pending',
|
||||
UNDER_REVIEW = 'under_review',
|
||||
APPROVED = 'approved',
|
||||
PROCESSING = 'processing',
|
||||
COMPLETED = 'completed',
|
||||
REJECTED = 'rejected',
|
||||
CANCELLED = 'cancelled',
|
||||
}
|
||||
|
||||
// Tipo de destino de retiro
|
||||
export type WithdrawalDestinationType = 'wallet' | 'bank' | 'crypto';
|
||||
|
||||
// Fuente del snapshot de rendimiento
|
||||
export type SnapshotSource = 'cron' | 'manual' | 'system';
|
||||
|
||||
// ============================================================================
|
||||
// Interfaces
|
||||
// ============================================================================
|
||||
@ -148,3 +174,109 @@ export interface WithdrawalDestinationDetails {
|
||||
crypto_network?: string;
|
||||
payment_method: 'bank_transfer' | 'crypto' | 'other';
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Entity Interfaces (Alineado con DDL tables)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* investment.risk_questionnaire (DDL 02-risk_questionnaire.sql)
|
||||
* Risk assessment questionnaire responses (valid for 1 year)
|
||||
*/
|
||||
export interface RiskQuestionnaire {
|
||||
id: string;
|
||||
user_id: string;
|
||||
responses: RiskQuestionnaireResponse[];
|
||||
total_score: number;
|
||||
calculated_profile: RiskProfile;
|
||||
recommended_agent: TradingAgent | null;
|
||||
completed_at: Date;
|
||||
expires_at: Date;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
completion_time_seconds: number | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* investment.withdrawal_requests (DDL 06-withdrawal_requests.sql)
|
||||
* Withdrawal requests from PAMM accounts
|
||||
*/
|
||||
export interface WithdrawalRequest {
|
||||
id: string;
|
||||
account_id: string;
|
||||
user_id: string;
|
||||
request_number: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
status: WithdrawalStatus;
|
||||
destination_type: WithdrawalDestinationType;
|
||||
destination_details: WithdrawalDestinationDetails;
|
||||
fee_amount: number;
|
||||
fee_percentage: number;
|
||||
net_amount: number; // Generated column
|
||||
requires_approval: boolean;
|
||||
reviewed_by: string | null;
|
||||
reviewed_at: Date | null;
|
||||
review_notes: string | null;
|
||||
processed_at: Date | null;
|
||||
completed_at: Date | null;
|
||||
transaction_reference: string | null;
|
||||
rejection_reason: string | null;
|
||||
cancelled_at: Date | null;
|
||||
cancellation_reason: string | null;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* investment.daily_performance (DDL 07-daily_performance.sql)
|
||||
* Daily performance snapshots for PAMM accounts
|
||||
*/
|
||||
export interface DailyPerformance {
|
||||
id: string;
|
||||
account_id: string;
|
||||
product_id: string;
|
||||
snapshot_date: Date;
|
||||
opening_balance: number;
|
||||
closing_balance: number;
|
||||
daily_pnl: number;
|
||||
daily_return_percentage: number;
|
||||
cumulative_pnl: number;
|
||||
cumulative_return_percentage: number;
|
||||
deposits: number;
|
||||
withdrawals: number;
|
||||
distributions_received: number;
|
||||
trades_executed: number;
|
||||
winning_trades: number;
|
||||
losing_trades: number;
|
||||
win_rate: number | null;
|
||||
max_drawdown: number | null;
|
||||
sharpe_ratio: number | null;
|
||||
volatility: number | null;
|
||||
high_water_mark: number | null;
|
||||
lowest_point: number | null;
|
||||
snapshot_source: SnapshotSource;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* investment.distribution_history (DDL 08-distribution_history.sql)
|
||||
* Daily distribution records per investment account
|
||||
*/
|
||||
export interface DistributionHistory {
|
||||
id: string;
|
||||
account_id: string;
|
||||
product_id: string;
|
||||
distribution_date: Date;
|
||||
gross_amount: number;
|
||||
fee_amount: number;
|
||||
net_amount: number;
|
||||
balance_before: number;
|
||||
balance_after: number;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
@ -77,14 +77,42 @@ export interface ToolCall {
|
||||
export interface UserPreferences {
|
||||
id: string;
|
||||
userId: string;
|
||||
communicationTone: CommunicationTone;
|
||||
verbosityLevel: VerbosityLevel;
|
||||
alertFrequency: AlertFrequency;
|
||||
preferredLanguage: string;
|
||||
|
||||
// Communication preferences
|
||||
language: string;
|
||||
tone: CommunicationTone;
|
||||
verbosity: VerbosityLevel;
|
||||
|
||||
// Trading preferences
|
||||
preferredSymbols: string[];
|
||||
preferredTimeframes: string[];
|
||||
tradingExperience: string;
|
||||
preferredTimeframe: string;
|
||||
riskTolerance: string;
|
||||
|
||||
// Notification preferences
|
||||
proactiveAlerts: boolean;
|
||||
alertFrequency: AlertFrequency;
|
||||
notificationHoursStart: string;
|
||||
notificationHoursEnd: string;
|
||||
timezone: string;
|
||||
|
||||
// Interests
|
||||
topicsOfInterest: string[];
|
||||
|
||||
// Experience level
|
||||
tradingExperienceLevel: string;
|
||||
|
||||
// Analysis preferences
|
||||
preferredAnalysisTypes: string[];
|
||||
|
||||
// Response format
|
||||
includeCharts: boolean;
|
||||
includeDataTables: boolean;
|
||||
includeExplanations: boolean;
|
||||
|
||||
// Onboarding
|
||||
onboardingCompleted: boolean;
|
||||
onboardingCompletedAt?: Date;
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@ -99,9 +127,27 @@ export interface UserMemory {
|
||||
memoryType: MemoryType;
|
||||
key: string;
|
||||
value: string;
|
||||
confidence: number;
|
||||
|
||||
// Importance
|
||||
importanceScore: number;
|
||||
|
||||
// Source
|
||||
sourceConversationId?: string;
|
||||
extractedFrom?: string;
|
||||
extractionMethod: string;
|
||||
|
||||
// Validity
|
||||
isActive: boolean;
|
||||
expiresAt?: Date;
|
||||
|
||||
// Confirmation
|
||||
requiresConfirmation: boolean;
|
||||
confirmedByUser: boolean;
|
||||
confirmedAt?: Date;
|
||||
|
||||
// Metadata
|
||||
metadata?: Record<string, unknown>;
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@ -112,14 +158,48 @@ export interface UserMemory {
|
||||
|
||||
export interface Embedding {
|
||||
id: string;
|
||||
sourceType: string;
|
||||
sourceId: string;
|
||||
|
||||
// Content type and reference
|
||||
contentType: string;
|
||||
contentId?: string;
|
||||
|
||||
// Content
|
||||
content: string;
|
||||
contentHash?: string;
|
||||
|
||||
// Metadata
|
||||
title?: string;
|
||||
description?: string;
|
||||
|
||||
// Vector embedding
|
||||
embedding: number[];
|
||||
modelName: string;
|
||||
dimensions: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
embeddingModel: string;
|
||||
|
||||
// Access control
|
||||
userId?: string;
|
||||
isPublic: boolean;
|
||||
|
||||
// Categorization
|
||||
category?: string;
|
||||
subcategory?: string;
|
||||
tags: string[];
|
||||
|
||||
// Relevance
|
||||
importanceScore: number;
|
||||
|
||||
// Context
|
||||
contextMetadata?: Record<string, unknown>;
|
||||
|
||||
// Source
|
||||
sourceUrl?: string;
|
||||
sourceType?: string;
|
||||
|
||||
// Validity
|
||||
isActive: boolean;
|
||||
expiresAt?: Date;
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -166,3 +246,123 @@ export interface MessageRow {
|
||||
metadata: Record<string, unknown> | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface UserPreferencesRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
|
||||
// Communication preferences
|
||||
language: string;
|
||||
tone: string;
|
||||
verbosity: string;
|
||||
|
||||
// Trading preferences
|
||||
preferred_symbols: string[];
|
||||
preferred_timeframe: string;
|
||||
risk_tolerance: string;
|
||||
|
||||
// Notification preferences
|
||||
proactive_alerts: boolean;
|
||||
alert_frequency: string;
|
||||
notification_hours_start: string;
|
||||
notification_hours_end: string;
|
||||
timezone: string;
|
||||
|
||||
// Interests
|
||||
topics_of_interest: string[];
|
||||
|
||||
// Experience level
|
||||
trading_experience_level: string;
|
||||
|
||||
// Analysis preferences
|
||||
preferred_analysis_types: string[];
|
||||
|
||||
// Response format
|
||||
include_charts: boolean;
|
||||
include_data_tables: boolean;
|
||||
include_explanations: boolean;
|
||||
|
||||
// Onboarding
|
||||
onboarding_completed: boolean;
|
||||
onboarding_completed_at: Date | null;
|
||||
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface UserMemoryRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
memory_type: string;
|
||||
key: string;
|
||||
value: string;
|
||||
|
||||
// Importance
|
||||
importance_score: number;
|
||||
|
||||
// Source
|
||||
source_conversation_id: string | null;
|
||||
extracted_from: string | null;
|
||||
extraction_method: string;
|
||||
|
||||
// Validity
|
||||
is_active: boolean;
|
||||
expires_at: Date | null;
|
||||
|
||||
// Confirmation
|
||||
requires_confirmation: boolean;
|
||||
confirmed_by_user: boolean;
|
||||
confirmed_at: Date | null;
|
||||
|
||||
// Metadata
|
||||
metadata: Record<string, unknown> | null;
|
||||
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface EmbeddingRow {
|
||||
id: string;
|
||||
|
||||
// Content type and reference
|
||||
content_type: string;
|
||||
content_id: string | null;
|
||||
|
||||
// Content
|
||||
content: string;
|
||||
content_hash: string | null;
|
||||
|
||||
// Metadata
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
|
||||
// Vector embedding
|
||||
embedding: number[];
|
||||
embedding_model: string;
|
||||
|
||||
// Access control
|
||||
user_id: string | null;
|
||||
is_public: boolean;
|
||||
|
||||
// Categorization
|
||||
category: string | null;
|
||||
subcategory: string | null;
|
||||
tags: string[];
|
||||
|
||||
// Relevance
|
||||
importance_score: number;
|
||||
|
||||
// Context
|
||||
context_metadata: Record<string, unknown> | null;
|
||||
|
||||
// Source
|
||||
source_url: string | null;
|
||||
source_type: string | null;
|
||||
|
||||
// Validity
|
||||
is_active: boolean;
|
||||
expires_at: Date | null;
|
||||
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
/**
|
||||
* Market Data Module Types
|
||||
* OHLCV data types for the market data module
|
||||
* Aligned with DDL: apps/database/ddl/schemas/market_data/tables/
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// Enums and Constants
|
||||
// =============================================================================
|
||||
|
||||
export type Timeframe = '5m' | '15m' | '1h' | '4h' | '1d';
|
||||
|
||||
export type AssetType = 'forex' | 'crypto' | 'commodity' | 'stock' | 'index';
|
||||
|
||||
// =============================================================================
|
||||
// API/Business Types
|
||||
// =============================================================================
|
||||
|
||||
export interface OHLCV {
|
||||
timestamp: Date;
|
||||
open: number;
|
||||
@ -31,7 +42,34 @@ export interface HistoricalDataOptions {
|
||||
to: Date;
|
||||
}
|
||||
|
||||
export interface OhlcvDataRow {
|
||||
// =============================================================================
|
||||
// Database Row Types - Aligned with market_data schema DDL
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Ticker entity - maps to market_data.tickers table
|
||||
* DDL: apps/database/ddl/schemas/market_data/tables/01-tickers.sql
|
||||
*/
|
||||
export interface TickerRow {
|
||||
id: number;
|
||||
symbol: string;
|
||||
name: string;
|
||||
asset_type: AssetType;
|
||||
base_currency: string;
|
||||
quote_currency: string;
|
||||
is_ml_enabled: boolean;
|
||||
supported_timeframes: string[];
|
||||
polygon_ticker: string | null;
|
||||
is_active: boolean;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* OHLCV 5-minute candle - maps to market_data.ohlcv_5m table
|
||||
* DDL: apps/database/ddl/schemas/market_data/tables/02-ohlcv_5m.sql
|
||||
*/
|
||||
export interface Ohlcv5mRow {
|
||||
id: string;
|
||||
ticker_id: number;
|
||||
timestamp: Date;
|
||||
@ -41,16 +79,49 @@ export interface OhlcvDataRow {
|
||||
close: string;
|
||||
volume: string;
|
||||
vwap: string | null;
|
||||
ts_epoch: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface TickerRow {
|
||||
id: number;
|
||||
symbol: string;
|
||||
name: string;
|
||||
asset_type: string;
|
||||
exchange: string | null;
|
||||
base_currency: string;
|
||||
quote_currency: string;
|
||||
is_active: boolean;
|
||||
/**
|
||||
* OHLCV 15-minute candle - maps to market_data.ohlcv_15m table
|
||||
* DDL: apps/database/ddl/schemas/market_data/tables/03-ohlcv_15m.sql
|
||||
*/
|
||||
export interface Ohlcv15mRow {
|
||||
id: string;
|
||||
ticker_id: number;
|
||||
timestamp: Date;
|
||||
open: string;
|
||||
high: string;
|
||||
low: string;
|
||||
close: string;
|
||||
volume: string;
|
||||
vwap: string | null;
|
||||
candle_count: number;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Staging row for bulk imports - maps to market_data.ohlcv_5m_staging table
|
||||
* DDL: apps/database/ddl/schemas/market_data/tables/04-staging.sql
|
||||
*/
|
||||
export interface OhlcvStagingRow {
|
||||
ticker_id: number | null;
|
||||
timestamp: Date | null;
|
||||
open: string | null;
|
||||
high: string | null;
|
||||
low: string | null;
|
||||
close: string | null;
|
||||
volume: string | null;
|
||||
vwap: string | null;
|
||||
ts_epoch: string | null;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Backwards Compatibility Alias
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @deprecated Use Ohlcv5mRow instead
|
||||
*/
|
||||
export type OhlcvDataRow = Ohlcv5mRow;
|
||||
|
||||
@ -171,3 +171,387 @@ export interface WalletTransactionRow {
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Invoice (from financial.invoices)
|
||||
// ============================================================================
|
||||
|
||||
export interface InvoiceLineItem {
|
||||
description: string;
|
||||
quantity: number;
|
||||
unitPrice: number;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export interface BillingAddress {
|
||||
line1?: string;
|
||||
line2?: string;
|
||||
city?: string;
|
||||
state?: string;
|
||||
postalCode?: string;
|
||||
country?: string;
|
||||
}
|
||||
|
||||
export interface Invoice {
|
||||
id: string;
|
||||
userId: string;
|
||||
subscriptionId?: string;
|
||||
stripeInvoiceId?: string;
|
||||
stripeCustomerId?: string;
|
||||
invoiceNumber?: string;
|
||||
invoiceType: InvoiceType;
|
||||
status: InvoiceStatus;
|
||||
subtotal: number;
|
||||
tax: number;
|
||||
total: number;
|
||||
amountPaid: number;
|
||||
amountDue: number;
|
||||
currency: CurrencyCode;
|
||||
invoiceDate: Date;
|
||||
dueDate?: Date;
|
||||
periodStart?: Date;
|
||||
periodEnd?: Date;
|
||||
paid: boolean;
|
||||
paidAt?: Date;
|
||||
attempted: boolean;
|
||||
attemptCount: number;
|
||||
nextPaymentAttempt?: Date;
|
||||
hostedInvoiceUrl?: string;
|
||||
invoicePdfUrl?: string;
|
||||
billingEmail?: string;
|
||||
billingName?: string;
|
||||
billingAddress?: BillingAddress;
|
||||
lineItems: InvoiceLineItem[];
|
||||
description?: string;
|
||||
notes?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
finalizedAt?: Date;
|
||||
voidedAt?: Date;
|
||||
}
|
||||
|
||||
export interface InvoiceRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
subscription_id: string | null;
|
||||
stripe_invoice_id: string | null;
|
||||
stripe_customer_id: string | null;
|
||||
invoice_number: string | null;
|
||||
invoice_type: string;
|
||||
status: string;
|
||||
subtotal: string;
|
||||
tax: string;
|
||||
total: string;
|
||||
amount_paid: string;
|
||||
amount_due: string;
|
||||
currency: string;
|
||||
invoice_date: Date;
|
||||
due_date: Date | null;
|
||||
period_start: Date | null;
|
||||
period_end: Date | null;
|
||||
paid: boolean;
|
||||
paid_at: Date | null;
|
||||
attempted: boolean;
|
||||
attempt_count: number;
|
||||
next_payment_attempt: Date | null;
|
||||
hosted_invoice_url: string | null;
|
||||
invoice_pdf_url: string | null;
|
||||
billing_email: string | null;
|
||||
billing_name: string | null;
|
||||
billing_address: Record<string, unknown> | null;
|
||||
line_items: unknown[];
|
||||
description: string | null;
|
||||
notes: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
finalized_at: Date | null;
|
||||
voided_at: Date | null;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Wallet Audit Log (from financial.wallet_audit_log)
|
||||
// ============================================================================
|
||||
|
||||
export type ActorType = 'user' | 'system' | 'admin' | 'api';
|
||||
|
||||
export interface WalletAuditLog {
|
||||
id: string;
|
||||
walletId: string;
|
||||
action: WalletAuditAction;
|
||||
actorId?: string;
|
||||
actorType: ActorType;
|
||||
oldValues?: Record<string, unknown>;
|
||||
newValues?: Record<string, unknown>;
|
||||
balanceBefore?: number;
|
||||
balanceAfter?: number;
|
||||
transactionId?: string;
|
||||
reason?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface WalletAuditLogRow {
|
||||
id: string;
|
||||
wallet_id: string;
|
||||
action: string;
|
||||
actor_id: string | null;
|
||||
actor_type: string;
|
||||
old_values: Record<string, unknown> | null;
|
||||
new_values: Record<string, unknown> | null;
|
||||
balance_before: string | null;
|
||||
balance_after: string | null;
|
||||
transaction_id: string | null;
|
||||
reason: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
ip_address: string | null;
|
||||
user_agent: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Currency Exchange Rates (from financial.currency_exchange_rates)
|
||||
// ============================================================================
|
||||
|
||||
export type ExchangeRateSource = 'manual' | 'api' | 'stripe' | 'coinbase';
|
||||
|
||||
export interface CurrencyExchangeRate {
|
||||
id: string;
|
||||
fromCurrency: CurrencyCode;
|
||||
toCurrency: CurrencyCode;
|
||||
rate: number;
|
||||
source: ExchangeRateSource;
|
||||
provider?: string;
|
||||
validFrom: Date;
|
||||
validTo?: Date;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface CurrencyExchangeRateRow {
|
||||
id: string;
|
||||
from_currency: string;
|
||||
to_currency: string;
|
||||
rate: string;
|
||||
source: string;
|
||||
provider: string | null;
|
||||
valid_from: Date;
|
||||
valid_to: Date | null;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Wallet Limits (from financial.wallet_limits)
|
||||
// ============================================================================
|
||||
|
||||
export interface WalletLimit {
|
||||
id: string;
|
||||
walletId?: string;
|
||||
walletType?: WalletType;
|
||||
subscriptionPlan?: SubscriptionPlan;
|
||||
minDeposit?: number;
|
||||
maxDeposit?: number;
|
||||
minWithdrawal?: number;
|
||||
maxWithdrawal?: number;
|
||||
minTransfer?: number;
|
||||
maxTransfer?: number;
|
||||
dailyDepositLimit?: number;
|
||||
dailyWithdrawalLimit?: number;
|
||||
dailyTransferLimit?: number;
|
||||
weeklyDepositLimit?: number;
|
||||
weeklyWithdrawalLimit?: number;
|
||||
weeklyTransferLimit?: number;
|
||||
monthlyDepositLimit?: number;
|
||||
monthlyWithdrawalLimit?: number;
|
||||
monthlyTransferLimit?: number;
|
||||
maxPendingTransactions?: number;
|
||||
maxDailyTransactionCount?: number;
|
||||
minBalance: number;
|
||||
maxBalance?: number;
|
||||
currency: CurrencyCode;
|
||||
priority: number;
|
||||
active: boolean;
|
||||
validFrom: Date;
|
||||
validTo?: Date;
|
||||
description?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface WalletLimitRow {
|
||||
id: string;
|
||||
wallet_id: string | null;
|
||||
wallet_type: string | null;
|
||||
subscription_plan: string | null;
|
||||
min_deposit: string | null;
|
||||
max_deposit: string | null;
|
||||
min_withdrawal: string | null;
|
||||
max_withdrawal: string | null;
|
||||
min_transfer: string | null;
|
||||
max_transfer: string | null;
|
||||
daily_deposit_limit: string | null;
|
||||
daily_withdrawal_limit: string | null;
|
||||
daily_transfer_limit: string | null;
|
||||
weekly_deposit_limit: string | null;
|
||||
weekly_withdrawal_limit: string | null;
|
||||
weekly_transfer_limit: string | null;
|
||||
monthly_deposit_limit: string | null;
|
||||
monthly_withdrawal_limit: string | null;
|
||||
monthly_transfer_limit: string | null;
|
||||
max_pending_transactions: number | null;
|
||||
max_daily_transaction_count: number | null;
|
||||
min_balance: string;
|
||||
max_balance: string | null;
|
||||
currency: string;
|
||||
priority: number;
|
||||
active: boolean;
|
||||
valid_from: Date;
|
||||
valid_to: Date | null;
|
||||
description: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Customer (from financial.customers)
|
||||
// ============================================================================
|
||||
|
||||
export interface Customer {
|
||||
id: string;
|
||||
userId: string;
|
||||
stripeCustomerId?: string;
|
||||
stripeDefaultPaymentMethodId?: string;
|
||||
billingName?: string;
|
||||
billingEmail?: string;
|
||||
billingPhone?: string;
|
||||
billingAddressLine1?: string;
|
||||
billingAddressLine2?: string;
|
||||
billingCity?: string;
|
||||
billingState?: string;
|
||||
billingPostalCode?: string;
|
||||
billingCountry?: string;
|
||||
taxId?: string;
|
||||
taxIdType: string;
|
||||
legalName?: string;
|
||||
currency: CurrencyCode;
|
||||
locale: string;
|
||||
isActive: boolean;
|
||||
delinquent: boolean;
|
||||
delinquentSince?: Date;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface CustomerRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
stripe_customer_id: string | null;
|
||||
stripe_default_payment_method_id: string | null;
|
||||
billing_name: string | null;
|
||||
billing_email: string | null;
|
||||
billing_phone: string | null;
|
||||
billing_address_line1: string | null;
|
||||
billing_address_line2: string | null;
|
||||
billing_city: string | null;
|
||||
billing_state: string | null;
|
||||
billing_postal_code: string | null;
|
||||
billing_country: string | null;
|
||||
tax_id: string | null;
|
||||
tax_id_type: string;
|
||||
legal_name: string | null;
|
||||
currency: string;
|
||||
locale: string;
|
||||
is_active: boolean;
|
||||
delinquent: boolean;
|
||||
delinquent_since: Date | null;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Payment Method (from financial.payment_methods)
|
||||
// ============================================================================
|
||||
|
||||
export type SavedPaymentType = 'card' | 'bank_account' | 'sepa_debit' | 'crypto_wallet';
|
||||
export type PaymentMethodStatus = 'pending_verification' | 'active' | 'expired' | 'failed' | 'removed';
|
||||
export type CardBrand = 'visa' | 'mastercard' | 'amex' | 'discover' | 'diners' | 'jcb' | 'unionpay';
|
||||
export type CardFunding = 'credit' | 'debit' | 'prepaid' | 'unknown';
|
||||
export type BankAccountType = 'checking' | 'savings';
|
||||
export type CryptoNetwork = 'ethereum' | 'bitcoin' | 'polygon' | 'solana' | 'binance';
|
||||
|
||||
export interface PaymentMethodDisplayInfo {
|
||||
last4?: string;
|
||||
brand?: string;
|
||||
bankName?: string;
|
||||
network?: string;
|
||||
}
|
||||
|
||||
export interface SavedPaymentMethod {
|
||||
id: string;
|
||||
userId: string;
|
||||
customerId?: string;
|
||||
stripePaymentMethodId?: string;
|
||||
stripeFingerprint?: string;
|
||||
paymentType: SavedPaymentType;
|
||||
status: PaymentMethodStatus;
|
||||
displayInfo: PaymentMethodDisplayInfo;
|
||||
isDefault: boolean;
|
||||
cardBrand?: CardBrand;
|
||||
cardLast4?: string;
|
||||
cardExpMonth?: number;
|
||||
cardExpYear?: number;
|
||||
cardFunding?: CardFunding;
|
||||
bankName?: string;
|
||||
bankLast4?: string;
|
||||
bankAccountType?: BankAccountType;
|
||||
cryptoNetwork?: CryptoNetwork;
|
||||
cryptoAddressLast8?: string;
|
||||
verifiedAt?: Date;
|
||||
verificationMethod?: string;
|
||||
billingAddress: BillingAddress;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
expiresAt?: Date;
|
||||
removedAt?: Date;
|
||||
}
|
||||
|
||||
export interface PaymentMethodRow {
|
||||
id: string;
|
||||
user_id: string;
|
||||
customer_id: string | null;
|
||||
stripe_payment_method_id: string | null;
|
||||
stripe_fingerprint: string | null;
|
||||
payment_type: string;
|
||||
status: string;
|
||||
display_info: Record<string, unknown>;
|
||||
is_default: boolean;
|
||||
card_brand: string | null;
|
||||
card_last4: string | null;
|
||||
card_exp_month: number | null;
|
||||
card_exp_year: number | null;
|
||||
card_funding: string | null;
|
||||
bank_name: string | null;
|
||||
bank_last4: string | null;
|
||||
bank_account_type: string | null;
|
||||
crypto_network: string | null;
|
||||
crypto_address_last8: string | null;
|
||||
verified_at: Date | null;
|
||||
verification_method: string | null;
|
||||
billing_address: Record<string, unknown>;
|
||||
metadata: Record<string, unknown>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
expires_at: Date | null;
|
||||
removed_at: Date | null;
|
||||
}
|
||||
|
||||
483
src/modules/trading/types/entity.types.ts
Normal file
483
src/modules/trading/types/entity.types.ts
Normal file
@ -0,0 +1,483 @@
|
||||
/**
|
||||
* Entity Types for Trading Schema
|
||||
* ================================
|
||||
* TypeScript interfaces aligned with trading.* DDL tables
|
||||
*
|
||||
* Tables covered:
|
||||
* - trading.symbols (01-symbols.sql)
|
||||
* - trading.bots (04-bots.sql)
|
||||
* - trading.signals (08-signals.sql)
|
||||
* - trading.trading_metrics (09-trading_metrics.sql)
|
||||
* - trading.paper_balances (10-paper_balances.sql)
|
||||
*/
|
||||
|
||||
import {
|
||||
BotType,
|
||||
BotStatus,
|
||||
Timeframe,
|
||||
SignalType,
|
||||
ConfidenceLevel,
|
||||
TradingBotStrategyConfig,
|
||||
} from './order.types';
|
||||
|
||||
// ============================================================================
|
||||
// Symbol Entity (trading.symbols)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Symbol - Catálogo de instrumentos financieros operables
|
||||
* Aligned with: trading.symbols (01-symbols.sql)
|
||||
*/
|
||||
export interface Symbol {
|
||||
id: string; // UUID
|
||||
symbol: string; // e.g., BTC/USDT, EUR/USD
|
||||
name: string;
|
||||
baseAsset: string; // e.g., BTC, EUR
|
||||
quoteAsset: string; // e.g., USDT, USD
|
||||
|
||||
// Tipo
|
||||
assetClass: AssetClass;
|
||||
exchange?: string; // binance, coinbase
|
||||
|
||||
// Precisión
|
||||
pricePrecision: number;
|
||||
quantityPrecision: number;
|
||||
|
||||
// Límites
|
||||
minQuantity?: number;
|
||||
maxQuantity?: number;
|
||||
minNotional?: number;
|
||||
|
||||
// Estado
|
||||
isActive: boolean;
|
||||
isTradeable: boolean;
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export type AssetClass = 'crypto' | 'forex' | 'stocks' | 'commodities';
|
||||
|
||||
export interface CreateSymbolDto {
|
||||
symbol: string;
|
||||
name: string;
|
||||
baseAsset: string;
|
||||
quoteAsset: string;
|
||||
assetClass: AssetClass;
|
||||
exchange?: string;
|
||||
pricePrecision?: number;
|
||||
quantityPrecision?: number;
|
||||
minQuantity?: number;
|
||||
maxQuantity?: number;
|
||||
minNotional?: number;
|
||||
isActive?: boolean;
|
||||
isTradeable?: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateSymbolDto {
|
||||
name?: string;
|
||||
exchange?: string;
|
||||
pricePrecision?: number;
|
||||
quantityPrecision?: number;
|
||||
minQuantity?: number;
|
||||
maxQuantity?: number;
|
||||
minNotional?: number;
|
||||
isActive?: boolean;
|
||||
isTradeable?: boolean;
|
||||
}
|
||||
|
||||
export interface SymbolFilters {
|
||||
assetClass?: AssetClass;
|
||||
exchange?: string;
|
||||
isActive?: boolean;
|
||||
isTradeable?: boolean;
|
||||
search?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TradingBot Entity (trading.bots)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* TradingBot - Trading bots configurados por usuarios
|
||||
* Aligned with: trading.bots (04-bots.sql)
|
||||
*/
|
||||
export interface TradingBot {
|
||||
id: string; // UUID
|
||||
userId: string; // UUID
|
||||
|
||||
// Configuración básica
|
||||
name: string;
|
||||
botType: BotType;
|
||||
status: BotStatus;
|
||||
|
||||
// Símbolos a operar
|
||||
symbols: string[];
|
||||
timeframe: Timeframe;
|
||||
|
||||
// Capital
|
||||
initialCapital: number;
|
||||
currentCapital: number;
|
||||
|
||||
// Risk management
|
||||
maxPositionSizePct: number; // % del capital
|
||||
maxDailyLossPct: number;
|
||||
maxDrawdownPct: number;
|
||||
|
||||
// Estrategia
|
||||
strategyType?: StrategyType;
|
||||
strategyConfig: TradingBotStrategyConfig;
|
||||
|
||||
// Estadísticas
|
||||
totalTrades: number;
|
||||
winningTrades: number;
|
||||
totalProfitLoss: number;
|
||||
winRate: number;
|
||||
|
||||
// Metadata
|
||||
startedAt?: Date;
|
||||
stoppedAt?: Date;
|
||||
lastTradeAt?: Date;
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export type StrategyType = 'atlas' | 'orion' | 'nova' | 'custom';
|
||||
|
||||
export interface CreateTradingBotDto {
|
||||
name: string;
|
||||
botType?: BotType;
|
||||
symbols: string[];
|
||||
timeframe?: Timeframe;
|
||||
initialCapital: number;
|
||||
maxPositionSizePct?: number;
|
||||
maxDailyLossPct?: number;
|
||||
maxDrawdownPct?: number;
|
||||
strategyType?: StrategyType;
|
||||
strategyConfig?: TradingBotStrategyConfig;
|
||||
}
|
||||
|
||||
export interface UpdateTradingBotDto {
|
||||
name?: string;
|
||||
status?: BotStatus;
|
||||
symbols?: string[];
|
||||
timeframe?: Timeframe;
|
||||
maxPositionSizePct?: number;
|
||||
maxDailyLossPct?: number;
|
||||
maxDrawdownPct?: number;
|
||||
strategyType?: StrategyType;
|
||||
strategyConfig?: TradingBotStrategyConfig;
|
||||
}
|
||||
|
||||
export interface TradingBotFilters {
|
||||
userId?: string;
|
||||
botType?: BotType;
|
||||
status?: BotStatus;
|
||||
strategyType?: StrategyType;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TradingSignal Entity (trading.signals)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* TradingSignal - Señales de trading generadas por modelos ML
|
||||
* Aligned with: trading.signals (08-signals.sql)
|
||||
*
|
||||
* INTERFAZ entre Trading y ML:
|
||||
* ML escribe señales aquí, Trading las consume
|
||||
*/
|
||||
export interface TradingSignal {
|
||||
id: string; // UUID
|
||||
|
||||
// Origen de la señal
|
||||
source: SignalSource;
|
||||
modelVersion?: string;
|
||||
|
||||
// Target
|
||||
symbol: string;
|
||||
timeframe: Timeframe;
|
||||
|
||||
// Señal
|
||||
signalType: SignalType;
|
||||
confidence: ConfidenceLevel;
|
||||
confidenceScore?: number; // 0.0000 to 1.0000
|
||||
|
||||
// Precios objetivo
|
||||
entryPrice?: number;
|
||||
targetPrice?: number;
|
||||
stopLoss?: number;
|
||||
|
||||
// Predicciones
|
||||
predictedDeltaHigh?: number; // % esperado de subida
|
||||
predictedDeltaLow?: number; // % esperado de bajada
|
||||
|
||||
// Resultado (se actualiza después)
|
||||
actualOutcome?: SignalOutcome;
|
||||
actualDelta?: number;
|
||||
outcomeAt?: Date;
|
||||
|
||||
// Validez
|
||||
validFrom: Date;
|
||||
validUntil: Date;
|
||||
isActive: boolean;
|
||||
|
||||
// Metadata
|
||||
metadata: Record<string, unknown>;
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export type SignalSource = 'ml_atlas' | 'ml_orion' | 'ml_nova' | 'manual';
|
||||
export type SignalOutcome = 'hit_target' | 'hit_stop' | 'expired' | 'cancelled';
|
||||
|
||||
export interface CreateTradingSignalDto {
|
||||
source: SignalSource;
|
||||
modelVersion?: string;
|
||||
symbol: string;
|
||||
timeframe: Timeframe;
|
||||
signalType: SignalType;
|
||||
confidence: ConfidenceLevel;
|
||||
confidenceScore?: number;
|
||||
entryPrice?: number;
|
||||
targetPrice?: number;
|
||||
stopLoss?: number;
|
||||
predictedDeltaHigh?: number;
|
||||
predictedDeltaLow?: number;
|
||||
validUntil: Date;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface UpdateTradingSignalDto {
|
||||
actualOutcome?: SignalOutcome;
|
||||
actualDelta?: number;
|
||||
outcomeAt?: Date;
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
export interface TradingSignalFilters {
|
||||
symbol?: string;
|
||||
timeframe?: Timeframe;
|
||||
source?: SignalSource;
|
||||
signalType?: SignalType;
|
||||
confidence?: ConfidenceLevel;
|
||||
isActive?: boolean;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TradingMetrics Entity (trading.trading_metrics)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* TradingMetrics - Métricas diarias de performance por bot
|
||||
* Aligned with: trading.trading_metrics (09-trading_metrics.sql)
|
||||
*/
|
||||
export interface TradingMetrics {
|
||||
id: string; // UUID
|
||||
botId: string; // UUID
|
||||
|
||||
// Período
|
||||
metricDate: Date;
|
||||
|
||||
// Capital
|
||||
startingCapital: number;
|
||||
endingCapital: number;
|
||||
peakCapital: number;
|
||||
|
||||
// Trading
|
||||
totalTrades: number;
|
||||
winningTrades: number;
|
||||
losingTrades: number;
|
||||
|
||||
// PnL
|
||||
grossProfit: number;
|
||||
grossLoss: number;
|
||||
netProfit: number;
|
||||
|
||||
// Ratios
|
||||
winRate: number;
|
||||
profitFactor: number; // gross_profit / gross_loss (>1 es rentable)
|
||||
sharpeRatio?: number;
|
||||
maxDrawdown: number; // Máximo drawdown del día (%)
|
||||
|
||||
// Trades
|
||||
avgWin: number;
|
||||
avgLoss: number;
|
||||
largestWin: number;
|
||||
largestLoss: number;
|
||||
|
||||
// Tiempos promedio
|
||||
avgTradeDurationMinutes?: number;
|
||||
|
||||
// Metadata
|
||||
metadata: Record<string, unknown>;
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateTradingMetricsDto {
|
||||
botId: string;
|
||||
metricDate: Date;
|
||||
startingCapital: number;
|
||||
endingCapital: number;
|
||||
peakCapital: number;
|
||||
totalTrades?: number;
|
||||
winningTrades?: number;
|
||||
losingTrades?: number;
|
||||
grossProfit?: number;
|
||||
grossLoss?: number;
|
||||
netProfit?: number;
|
||||
winRate?: number;
|
||||
profitFactor?: number;
|
||||
sharpeRatio?: number;
|
||||
maxDrawdown?: number;
|
||||
avgWin?: number;
|
||||
avgLoss?: number;
|
||||
largestWin?: number;
|
||||
largestLoss?: number;
|
||||
avgTradeDurationMinutes?: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface UpdateTradingMetricsDto {
|
||||
endingCapital?: number;
|
||||
peakCapital?: number;
|
||||
totalTrades?: number;
|
||||
winningTrades?: number;
|
||||
losingTrades?: number;
|
||||
grossProfit?: number;
|
||||
grossLoss?: number;
|
||||
netProfit?: number;
|
||||
winRate?: number;
|
||||
profitFactor?: number;
|
||||
sharpeRatio?: number;
|
||||
maxDrawdown?: number;
|
||||
avgWin?: number;
|
||||
avgLoss?: number;
|
||||
largestWin?: number;
|
||||
largestLoss?: number;
|
||||
avgTradeDurationMinutes?: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface TradingMetricsFilters {
|
||||
botId?: string;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PaperBalance Entity (trading.paper_balances)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* PaperBalance - Balances virtuales para paper trading
|
||||
* Aligned with: trading.paper_balances (10-paper_balances.sql)
|
||||
*
|
||||
* Permite a usuarios practicar sin riesgo real
|
||||
*/
|
||||
export interface PaperBalance {
|
||||
id: string; // UUID
|
||||
userId: string; // UUID
|
||||
|
||||
// Asset y balance
|
||||
asset: string; // e.g., USDT
|
||||
total: number;
|
||||
available: number;
|
||||
locked: number;
|
||||
|
||||
// Tracking
|
||||
initialBalance: number;
|
||||
totalDeposits: number;
|
||||
totalWithdrawals: number;
|
||||
totalPnl: number;
|
||||
|
||||
// Reset tracking
|
||||
lastResetAt?: Date;
|
||||
resetCount: number;
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface CreatePaperBalanceDto {
|
||||
userId: string;
|
||||
asset?: string; // defaults to USDT
|
||||
initialBalance?: number; // defaults to 10000.00
|
||||
}
|
||||
|
||||
export interface UpdatePaperBalanceDto {
|
||||
total?: number;
|
||||
available?: number;
|
||||
locked?: number;
|
||||
totalDeposits?: number;
|
||||
totalWithdrawals?: number;
|
||||
totalPnl?: number;
|
||||
}
|
||||
|
||||
export interface ResetPaperBalanceDto {
|
||||
initialBalance?: number; // defaults to 10000.00
|
||||
}
|
||||
|
||||
export interface PaperBalanceFilters {
|
||||
userId?: string;
|
||||
asset?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Result Types
|
||||
// ============================================================================
|
||||
|
||||
export interface SymbolListResult {
|
||||
symbols: Symbol[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface TradingBotListResult {
|
||||
bots: TradingBot[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface TradingSignalListResult {
|
||||
signals: TradingSignal[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface TradingMetricsListResult {
|
||||
metrics: TradingMetrics[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface PaperBalanceListResult {
|
||||
balances: PaperBalance[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user