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:
Adrian Flores Cortes 2026-01-30 12:24:45 -06:00
parent 58a7b44673
commit c91b8e5419
11 changed files with 2200 additions and 49 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,
}; };
} }

View File

@ -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,
}; };
} }

View File

@ -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)
// ============================================================================ // ============================================================================

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View 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;
}