trading-platform-backend-v2/src/modules/risk/controllers/risk.controller.ts
Adrian Flores Cortes 58a7b44673 feat(proxy): Add Express proxy gateway for Python services (ARCH-001)
- Add proxy module with types, service, controller, and routes
- Configure llmAgent and dataService in config
- Register proxy routes in main Express app
- All Python service access now goes through authenticated Express gateway

ARCH-001: Centralized proxy with auth, logging, and error handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:43:41 -06:00

267 lines
5.5 KiB
TypeScript

/**
* Risk Assessment Controller
* Handles HTTP endpoints for risk questionnaire and assessments
*/
import { Request, Response, NextFunction } from 'express';
import { riskService } from '../services/risk.service';
// ============================================================================
// Types
// ============================================================================
type AuthRequest = Request;
// ============================================================================
// Controllers
// ============================================================================
/**
* GET /api/v1/risk/questions
* Get all risk questionnaire questions
*/
export async function getQuestions(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const questions = riskService.getQuestions();
res.json({
success: true,
data: questions,
});
} catch (error) {
next(error);
}
}
/**
* GET /api/v1/risk/assessment
* Get current user's risk assessment
*/
export async function getCurrentUserAssessment(
req: AuthRequest,
res: Response,
next: NextFunction
): Promise<void> {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
});
return;
}
const assessment = await riskService.getUserAssessment(req.user.id);
if (!assessment) {
res.status(404).json({
success: false,
error: {
message: 'No risk assessment found',
code: 'NOT_FOUND',
},
});
return;
}
res.json({
success: true,
data: assessment,
});
} catch (error) {
next(error);
}
}
/**
* GET /api/v1/risk/assessment/valid
* Check if current user has a valid (non-expired) assessment
*/
export async function checkValidAssessment(
req: AuthRequest,
res: Response,
next: NextFunction
): Promise<void> {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
});
return;
}
const isValid = await riskService.isAssessmentValid(req.user.id);
const assessment = isValid
? await riskService.getValidAssessment(req.user.id)
: null;
res.json({
success: true,
data: {
isValid,
assessment,
},
});
} catch (error) {
next(error);
}
}
/**
* POST /api/v1/risk/assessment
* Submit risk questionnaire responses
* Body: { responses: [{ questionId, answer }] }
*/
export async function submitAssessment(
req: AuthRequest,
res: Response,
next: NextFunction
): Promise<void> {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
});
return;
}
const { responses, completionTimeSeconds } = req.body;
if (!responses || !Array.isArray(responses)) {
res.status(400).json({
success: false,
error: {
message: 'Invalid request: responses array is required',
code: 'INVALID_REQUEST',
},
});
return;
}
const assessment = await riskService.submitAssessment({
userId: req.user.id,
responses,
ipAddress: req.ip,
userAgent: req.get('user-agent'),
completionTimeSeconds,
});
res.status(201).json({
success: true,
data: assessment,
message: `Risk assessment completed. Your profile: ${assessment.riskProfile}`,
});
} catch (error) {
next(error);
}
}
/**
* GET /api/v1/risk/assessment/:userId
* Get risk assessment for specific user (admin only)
*/
export async function getUserAssessment(
req: AuthRequest,
res: Response,
next: NextFunction
): Promise<void> {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
});
return;
}
const { userId } = req.params;
if (!userId) {
res.status(400).json({
success: false,
error: {
message: 'User ID is required',
code: 'INVALID_REQUEST',
},
});
return;
}
const assessment = await riskService.getUserAssessment(userId);
if (!assessment) {
res.status(404).json({
success: false,
error: {
message: 'No risk assessment found for this user',
code: 'NOT_FOUND',
},
});
return;
}
res.json({
success: true,
data: assessment,
});
} catch (error) {
next(error);
}
}
/**
* GET /api/v1/risk/assessment/history
* Get assessment history for current user
*/
export async function getAssessmentHistory(
req: AuthRequest,
res: Response,
next: NextFunction
): Promise<void> {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
});
return;
}
const history = await riskService.getAssessmentHistory(req.user.id);
res.json({
success: true,
data: history,
});
} catch (error) {
next(error);
}
}
/**
* GET /api/v1/risk/statistics
* Get risk profile statistics (admin only)
*/
export async function getStatistics(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const statistics = await riskService.getProfileStatistics();
res.json({
success: true,
data: statistics,
});
} catch (error) {
next(error);
}
}