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>;
|
bySeverity: Record<EventSeverity, number>;
|
||||||
criticalEvents: 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;
|
iat: number;
|
||||||
exp: 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[]> {
|
async getCategories(): Promise<Category[]> {
|
||||||
const result = await db.query<Record<string, unknown>>(
|
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) => ({
|
return result.rows.map((row) => ({
|
||||||
id: row.id as string,
|
id: row.id as string,
|
||||||
name: row.name as string,
|
name: row.name as string,
|
||||||
slug: row.slug as string,
|
slug: row.slug as string,
|
||||||
description: row.description as string | undefined,
|
description: row.description as string | undefined,
|
||||||
icon: row.icon as string | undefined,
|
|
||||||
parentId: row.parent_id 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),
|
createdAt: new Date(row.created_at as string),
|
||||||
updatedAt: new Date(row.updated_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,
|
name: row.name as string,
|
||||||
slug: row.slug as string,
|
slug: row.slug as string,
|
||||||
description: row.description as string | undefined,
|
description: row.description as string | undefined,
|
||||||
icon: row.icon as string | undefined,
|
|
||||||
parentId: row.parent_id 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),
|
createdAt: new Date(row.created_at as string),
|
||||||
updatedAt: new Date(row.updated_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> {
|
async createCategory(input: CreateCategoryInput): Promise<Category> {
|
||||||
const slug = input.slug || generateSlug(input.name);
|
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>>(
|
const result = await db.query<Record<string, unknown>>(
|
||||||
`INSERT INTO education.categories (name, slug, description, icon, parent_id, sort_order)
|
`INSERT INTO education.categories (name, slug, description, icon_url, color, parent_id, display_order, is_active)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
RETURNING *`,
|
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];
|
const row = result.rows[0];
|
||||||
return {
|
return {
|
||||||
@ -151,11 +166,16 @@ class CourseService {
|
|||||||
name: row.name as string,
|
name: row.name as string,
|
||||||
slug: row.slug as string,
|
slug: row.slug as string,
|
||||||
description: row.description as string | undefined,
|
description: row.description as string | undefined,
|
||||||
icon: row.icon as string | undefined,
|
|
||||||
parentId: row.parent_id 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),
|
createdAt: new Date(row.created_at as string),
|
||||||
updatedAt: new Date(row.updated_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 {
|
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 {
|
return {
|
||||||
id: row.id as string,
|
id: row.id as string,
|
||||||
userId: row.user_id as string,
|
userId: row.user_id as string,
|
||||||
enrollmentId: row.enrollment_id as string,
|
|
||||||
lessonId: row.lesson_id as string,
|
lessonId: row.lesson_id as string,
|
||||||
isCompleted: (row.is_completed || row.video_completed) as boolean || false,
|
enrollmentId: row.enrollment_id as string,
|
||||||
videoProgressSeconds: row.video_progress_seconds as number | undefined,
|
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,
|
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),
|
createdAt: new Date(row.created_at as string),
|
||||||
updatedAt: new Date(row.updated_at as string),
|
updatedAt: new Date(row.updated_at as string),
|
||||||
videoWatchedSeconds: row.video_watched_seconds as number,
|
// Backward-compatible aliases
|
||||||
videoCompleted: (row.is_completed || row.video_completed) as boolean || false,
|
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 {
|
export interface Category {
|
||||||
@ -88,22 +88,54 @@ export interface Category {
|
|||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
icon?: string;
|
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
sortOrder: number;
|
displayOrder: number;
|
||||||
|
iconUrl?: string;
|
||||||
|
color?: string;
|
||||||
|
isActive: boolean;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: 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 {
|
export interface CreateCategoryInput {
|
||||||
name: string;
|
name: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
icon?: string;
|
iconUrl?: string;
|
||||||
|
color?: string;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
|
displayOrder?: number;
|
||||||
|
isActive?: boolean;
|
||||||
|
// Backward-compatible aliases
|
||||||
|
/** @deprecated Use iconUrl instead */
|
||||||
|
icon?: string;
|
||||||
|
/** @deprecated Use displayOrder instead */
|
||||||
sortOrder?: number;
|
sortOrder?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdateCategoryInput extends Partial<CreateCategoryInput> {}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Course (Aligned with education.courses DDL)
|
// Course (Aligned with education.courses DDL)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -402,27 +434,61 @@ export interface CreateEnrollmentInput {
|
|||||||
export interface LessonProgress {
|
export interface LessonProgress {
|
||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
enrollmentId: string;
|
|
||||||
lessonId: string;
|
lessonId: string;
|
||||||
|
enrollmentId: string;
|
||||||
isCompleted: boolean;
|
isCompleted: boolean;
|
||||||
videoProgressSeconds?: number;
|
lastPositionSeconds: number;
|
||||||
|
totalWatchTimeSeconds: number;
|
||||||
|
watchPercentage: number;
|
||||||
|
firstViewedAt?: Date;
|
||||||
|
lastViewedAt?: Date;
|
||||||
completedAt?: Date;
|
completedAt?: Date;
|
||||||
startedAt?: Date;
|
|
||||||
xpEarned: number;
|
|
||||||
notes?: string;
|
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
// Backward-compatible aliases
|
// Backward-compatible aliases
|
||||||
/** @deprecated Use videoProgressSeconds instead */
|
/** @deprecated Use lastPositionSeconds instead */
|
||||||
|
videoProgressSeconds?: number;
|
||||||
|
/** @deprecated Use lastPositionSeconds instead */
|
||||||
videoWatchedSeconds?: number;
|
videoWatchedSeconds?: number;
|
||||||
/** @deprecated Use isCompleted instead */
|
/** @deprecated Use isCompleted instead */
|
||||||
videoCompleted?: boolean;
|
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 {
|
export interface UpdateLessonProgressInput {
|
||||||
|
lastPositionSeconds?: number;
|
||||||
|
totalWatchTimeSeconds?: number;
|
||||||
|
watchPercentage?: number;
|
||||||
|
isCompleted?: boolean;
|
||||||
|
completedAt?: Date;
|
||||||
|
/** @deprecated Use lastPositionSeconds instead */
|
||||||
videoWatchedSeconds?: number;
|
videoWatchedSeconds?: number;
|
||||||
|
/** @deprecated Use isCompleted instead */
|
||||||
videoCompleted?: boolean;
|
videoCompleted?: boolean;
|
||||||
|
/** @deprecated Not in DDL */
|
||||||
userNotes?: string;
|
userNotes?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,6 +682,179 @@ export interface CreateActivityLogInput {
|
|||||||
userAgent?: string;
|
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)
|
// Attachments (for lesson attachments JSONB field)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@ -19,10 +19,29 @@ export interface CourseReview {
|
|||||||
helpfulVotes: number;
|
helpfulVotes: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
// Computed/joined fields (not in DDL)
|
||||||
userName?: string;
|
userName?: string;
|
||||||
userAvatar?: 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 {
|
export interface CourseReviewWithUser extends CourseReview {
|
||||||
user: {
|
user: {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -69,6 +69,32 @@ export enum TransactionStatusEnum {
|
|||||||
CANCELLED = 'cancelled',
|
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
|
// Interfaces
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -148,3 +174,109 @@ export interface WithdrawalDestinationDetails {
|
|||||||
crypto_network?: string;
|
crypto_network?: string;
|
||||||
payment_method: 'bank_transfer' | 'crypto' | 'other';
|
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 {
|
export interface UserPreferences {
|
||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
communicationTone: CommunicationTone;
|
|
||||||
verbosityLevel: VerbosityLevel;
|
// Communication preferences
|
||||||
alertFrequency: AlertFrequency;
|
language: string;
|
||||||
preferredLanguage: string;
|
tone: CommunicationTone;
|
||||||
|
verbosity: VerbosityLevel;
|
||||||
|
|
||||||
|
// Trading preferences
|
||||||
preferredSymbols: string[];
|
preferredSymbols: string[];
|
||||||
preferredTimeframes: string[];
|
preferredTimeframe: string;
|
||||||
tradingExperience: string;
|
|
||||||
riskTolerance: 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;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
@ -99,9 +127,27 @@ export interface UserMemory {
|
|||||||
memoryType: MemoryType;
|
memoryType: MemoryType;
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
confidence: number;
|
|
||||||
|
// Importance
|
||||||
|
importanceScore: number;
|
||||||
|
|
||||||
|
// Source
|
||||||
sourceConversationId?: string;
|
sourceConversationId?: string;
|
||||||
|
extractedFrom?: string;
|
||||||
|
extractionMethod: string;
|
||||||
|
|
||||||
|
// Validity
|
||||||
|
isActive: boolean;
|
||||||
expiresAt?: Date;
|
expiresAt?: Date;
|
||||||
|
|
||||||
|
// Confirmation
|
||||||
|
requiresConfirmation: boolean;
|
||||||
|
confirmedByUser: boolean;
|
||||||
|
confirmedAt?: Date;
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
@ -112,14 +158,48 @@ export interface UserMemory {
|
|||||||
|
|
||||||
export interface Embedding {
|
export interface Embedding {
|
||||||
id: string;
|
id: string;
|
||||||
sourceType: string;
|
|
||||||
sourceId: string;
|
// Content type and reference
|
||||||
|
contentType: string;
|
||||||
|
contentId?: string;
|
||||||
|
|
||||||
|
// Content
|
||||||
content: string;
|
content: string;
|
||||||
|
contentHash?: string;
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
// Vector embedding
|
||||||
embedding: number[];
|
embedding: number[];
|
||||||
modelName: string;
|
embeddingModel: string;
|
||||||
dimensions: number;
|
|
||||||
metadata?: Record<string, unknown>;
|
// 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;
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -166,3 +246,123 @@ export interface MessageRow {
|
|||||||
metadata: Record<string, unknown> | null;
|
metadata: Record<string, unknown> | null;
|
||||||
created_at: Date;
|
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
|
* Market Data Module Types
|
||||||
* OHLCV data types for the market data module
|
* 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 Timeframe = '5m' | '15m' | '1h' | '4h' | '1d';
|
||||||
|
|
||||||
|
export type AssetType = 'forex' | 'crypto' | 'commodity' | 'stock' | 'index';
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// API/Business Types
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
export interface OHLCV {
|
export interface OHLCV {
|
||||||
timestamp: Date;
|
timestamp: Date;
|
||||||
open: number;
|
open: number;
|
||||||
@ -31,7 +42,34 @@ export interface HistoricalDataOptions {
|
|||||||
to: Date;
|
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;
|
id: string;
|
||||||
ticker_id: number;
|
ticker_id: number;
|
||||||
timestamp: Date;
|
timestamp: Date;
|
||||||
@ -41,16 +79,49 @@ export interface OhlcvDataRow {
|
|||||||
close: string;
|
close: string;
|
||||||
volume: string;
|
volume: string;
|
||||||
vwap: string | null;
|
vwap: string | null;
|
||||||
|
ts_epoch: string | null;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TickerRow {
|
/**
|
||||||
id: number;
|
* OHLCV 15-minute candle - maps to market_data.ohlcv_15m table
|
||||||
symbol: string;
|
* DDL: apps/database/ddl/schemas/market_data/tables/03-ohlcv_15m.sql
|
||||||
name: string;
|
*/
|
||||||
asset_type: string;
|
export interface Ohlcv15mRow {
|
||||||
exchange: string | null;
|
id: string;
|
||||||
base_currency: string;
|
ticker_id: number;
|
||||||
quote_currency: string;
|
timestamp: Date;
|
||||||
is_active: boolean;
|
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;
|
created_at: Date;
|
||||||
updated_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