refactored monorepo for more projects
This commit is contained in:
parent
4632c174dc
commit
9492f1b15e
180 changed files with 1438 additions and 424 deletions
23
apps/stock/web-api/src/routes/create-routes.ts
Normal file
23
apps/stock/web-api/src/routes/create-routes.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Route factory for web API service
|
||||
* Creates routes with access to the service container
|
||||
*/
|
||||
|
||||
import { Hono } from 'hono';
|
||||
import type { IServiceContainer } from '@stock-bot/handlers';
|
||||
import { createHealthRoutes } from './health.routes';
|
||||
import { createExchangeRoutes } from './exchange.routes';
|
||||
|
||||
export function createRoutes(container: IServiceContainer): Hono {
|
||||
const app = new Hono();
|
||||
|
||||
// Create routes with container
|
||||
const healthRoutes = createHealthRoutes(container);
|
||||
const exchangeRoutes = createExchangeRoutes(container);
|
||||
|
||||
// Mount routes
|
||||
app.route('/health', healthRoutes);
|
||||
app.route('/api/exchanges', exchangeRoutes);
|
||||
|
||||
return app;
|
||||
}
|
||||
262
apps/stock/web-api/src/routes/exchange.routes.ts
Normal file
262
apps/stock/web-api/src/routes/exchange.routes.ts
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/**
|
||||
* Exchange management routes - Refactored
|
||||
*/
|
||||
import { Hono } from 'hono';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { IServiceContainer } from '@stock-bot/handlers';
|
||||
import { createExchangeService } from '../services/exchange.service';
|
||||
import { createSuccessResponse, handleError } from '../utils/error-handler';
|
||||
import {
|
||||
validateCreateExchange,
|
||||
validateCreateProviderMapping,
|
||||
validateUpdateExchange,
|
||||
validateUpdateProviderMapping,
|
||||
} from '../utils/validation';
|
||||
|
||||
const logger = getLogger('exchange-routes');
|
||||
|
||||
export function createExchangeRoutes(container: IServiceContainer) {
|
||||
const exchangeRoutes = new Hono();
|
||||
const exchangeService = createExchangeService(container);
|
||||
|
||||
// Get all exchanges with provider mapping counts and mappings
|
||||
exchangeRoutes.get('/', async c => {
|
||||
logger.debug('Getting all exchanges');
|
||||
try {
|
||||
const exchanges = await exchangeService.getAllExchanges();
|
||||
logger.info('Successfully retrieved exchanges', { count: exchanges.length });
|
||||
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get exchanges', { error });
|
||||
return handleError(c, error, 'to get exchanges');
|
||||
}
|
||||
});
|
||||
|
||||
// Get exchange by ID with detailed provider mappings
|
||||
exchangeRoutes.get('/:id', async c => {
|
||||
const exchangeId = c.req.param('id');
|
||||
logger.debug('Getting exchange by ID', { exchangeId });
|
||||
|
||||
try {
|
||||
const result = await exchangeService.getExchangeById(exchangeId);
|
||||
|
||||
if (!result) {
|
||||
logger.warn('Exchange not found', { exchangeId });
|
||||
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Successfully retrieved exchange details', {
|
||||
exchangeId,
|
||||
exchangeCode: result.exchange.code,
|
||||
mappingCount: result.provider_mappings.length,
|
||||
});
|
||||
return c.json(createSuccessResponse(result));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get exchange details', { error, exchangeId });
|
||||
return handleError(c, error, 'to get exchange details');
|
||||
}
|
||||
});
|
||||
|
||||
// Create new exchange
|
||||
exchangeRoutes.post('/', async c => {
|
||||
logger.debug('Creating new exchange');
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received exchange creation request', { requestBody: body });
|
||||
|
||||
const validatedData = validateCreateExchange(body);
|
||||
logger.debug('Exchange data validated successfully', { validatedData });
|
||||
|
||||
const exchange = await exchangeService.createExchange(validatedData);
|
||||
logger.info('Exchange created successfully', {
|
||||
exchangeId: exchange.id,
|
||||
code: exchange.code,
|
||||
name: exchange.name,
|
||||
});
|
||||
|
||||
return c.json(createSuccessResponse(exchange, 'Exchange created successfully'), 201);
|
||||
} catch (error) {
|
||||
logger.error('Failed to create exchange', { error });
|
||||
return handleError(c, error, 'to create exchange');
|
||||
}
|
||||
});
|
||||
|
||||
// Update exchange (activate/deactivate, rename, etc.)
|
||||
exchangeRoutes.patch('/:id', async c => {
|
||||
const exchangeId = c.req.param('id');
|
||||
logger.debug('Updating exchange', { exchangeId });
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received exchange update request', { exchangeId, updates: body });
|
||||
|
||||
const validatedUpdates = validateUpdateExchange(body);
|
||||
logger.debug('Exchange update data validated', { exchangeId, validatedUpdates });
|
||||
|
||||
const exchange = await exchangeService.updateExchange(exchangeId, validatedUpdates);
|
||||
|
||||
if (!exchange) {
|
||||
logger.warn('Exchange not found for update', { exchangeId });
|
||||
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Exchange updated successfully', {
|
||||
exchangeId,
|
||||
code: exchange.code,
|
||||
updates: validatedUpdates,
|
||||
});
|
||||
|
||||
// Log special actions
|
||||
if (validatedUpdates.visible === false) {
|
||||
logger.warn('Exchange marked as hidden - provider mappings will be deleted', {
|
||||
exchangeId,
|
||||
code: exchange.code,
|
||||
});
|
||||
}
|
||||
|
||||
return c.json(createSuccessResponse(exchange, 'Exchange updated successfully'));
|
||||
} catch (error) {
|
||||
logger.error('Failed to update exchange', { error, exchangeId });
|
||||
return handleError(c, error, 'to update exchange');
|
||||
}
|
||||
});
|
||||
|
||||
// Get all provider mappings
|
||||
exchangeRoutes.get('/provider-mappings/all', async c => {
|
||||
logger.debug('Getting all provider mappings');
|
||||
|
||||
try {
|
||||
const mappings = await exchangeService.getAllProviderMappings();
|
||||
logger.info('Successfully retrieved all provider mappings', { count: mappings.length });
|
||||
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get provider mappings', { error });
|
||||
return handleError(c, error, 'to get provider mappings');
|
||||
}
|
||||
});
|
||||
|
||||
// Get provider mappings by provider
|
||||
exchangeRoutes.get('/provider-mappings/:provider', async c => {
|
||||
const provider = c.req.param('provider');
|
||||
logger.debug('Getting provider mappings by provider', { provider });
|
||||
|
||||
try {
|
||||
const mappings = await exchangeService.getProviderMappingsByProvider(provider);
|
||||
logger.info('Successfully retrieved provider mappings', { provider, count: mappings.length });
|
||||
|
||||
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get provider mappings', { error, provider });
|
||||
return handleError(c, error, 'to get provider mappings');
|
||||
}
|
||||
});
|
||||
|
||||
// Update provider mapping (activate/deactivate, verify, change confidence)
|
||||
exchangeRoutes.patch('/provider-mappings/:id', async c => {
|
||||
const mappingId = c.req.param('id');
|
||||
logger.debug('Updating provider mapping', { mappingId });
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received provider mapping update request', { mappingId, updates: body });
|
||||
|
||||
const validatedUpdates = validateUpdateProviderMapping(body);
|
||||
logger.debug('Provider mapping update data validated', { mappingId, validatedUpdates });
|
||||
|
||||
const mapping = await exchangeService.updateProviderMapping(mappingId, validatedUpdates);
|
||||
|
||||
if (!mapping) {
|
||||
logger.warn('Provider mapping not found for update', { mappingId });
|
||||
return c.json(createSuccessResponse(null, 'Provider mapping not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Provider mapping updated successfully', {
|
||||
mappingId,
|
||||
provider: mapping.provider,
|
||||
providerExchangeCode: mapping.provider_exchange_code,
|
||||
updates: validatedUpdates,
|
||||
});
|
||||
|
||||
return c.json(createSuccessResponse(mapping, 'Provider mapping updated successfully'));
|
||||
} catch (error) {
|
||||
logger.error('Failed to update provider mapping', { error, mappingId });
|
||||
return handleError(c, error, 'to update provider mapping');
|
||||
}
|
||||
});
|
||||
|
||||
// Create new provider mapping
|
||||
exchangeRoutes.post('/provider-mappings', async c => {
|
||||
logger.debug('Creating new provider mapping');
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received provider mapping creation request', { requestBody: body });
|
||||
|
||||
const validatedData = validateCreateProviderMapping(body);
|
||||
logger.debug('Provider mapping data validated successfully', { validatedData });
|
||||
|
||||
const mapping = await exchangeService.createProviderMapping(validatedData);
|
||||
logger.info('Provider mapping created successfully', {
|
||||
mappingId: mapping.id,
|
||||
provider: mapping.provider,
|
||||
providerExchangeCode: mapping.provider_exchange_code,
|
||||
masterExchangeId: mapping.master_exchange_id,
|
||||
});
|
||||
|
||||
return c.json(createSuccessResponse(mapping, 'Provider mapping created successfully'), 201);
|
||||
} catch (error) {
|
||||
logger.error('Failed to create provider mapping', { error });
|
||||
return handleError(c, error, 'to create provider mapping');
|
||||
}
|
||||
});
|
||||
|
||||
// Get all available providers
|
||||
exchangeRoutes.get('/providers/list', async c => {
|
||||
logger.debug('Getting providers list');
|
||||
|
||||
try {
|
||||
const providers = await exchangeService.getProviders();
|
||||
logger.info('Successfully retrieved providers list', { count: providers.length, providers });
|
||||
return c.json(createSuccessResponse(providers));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get providers list', { error });
|
||||
return handleError(c, error, 'to get providers list');
|
||||
}
|
||||
});
|
||||
|
||||
// Get unmapped provider exchanges by provider
|
||||
exchangeRoutes.get('/provider-exchanges/unmapped/:provider', async c => {
|
||||
const provider = c.req.param('provider');
|
||||
logger.debug('Getting unmapped provider exchanges', { provider });
|
||||
|
||||
try {
|
||||
const exchanges = await exchangeService.getUnmappedProviderExchanges(provider);
|
||||
logger.info('Successfully retrieved unmapped provider exchanges', {
|
||||
provider,
|
||||
count: exchanges.length,
|
||||
});
|
||||
|
||||
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get unmapped provider exchanges', { error, provider });
|
||||
return handleError(c, error, 'to get unmapped provider exchanges');
|
||||
}
|
||||
});
|
||||
|
||||
// Get exchange statistics
|
||||
exchangeRoutes.get('/stats/summary', async c => {
|
||||
logger.debug('Getting exchange statistics');
|
||||
|
||||
try {
|
||||
const stats = await exchangeService.getExchangeStats();
|
||||
logger.info('Successfully retrieved exchange statistics', { stats });
|
||||
return c.json(createSuccessResponse(stats));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get exchange statistics', { error });
|
||||
return handleError(c, error, 'to get exchange statistics');
|
||||
}
|
||||
});
|
||||
|
||||
return exchangeRoutes;
|
||||
}
|
||||
111
apps/stock/web-api/src/routes/health.routes.ts
Normal file
111
apps/stock/web-api/src/routes/health.routes.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* Health check routes factory
|
||||
*/
|
||||
import { Hono } from 'hono';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { IServiceContainer } from '@stock-bot/handlers';
|
||||
|
||||
const logger = getLogger('health-routes');
|
||||
|
||||
export function createHealthRoutes(container: IServiceContainer) {
|
||||
const healthRoutes = new Hono();
|
||||
|
||||
// Basic health check
|
||||
healthRoutes.get('/', c => {
|
||||
logger.debug('Basic health check requested');
|
||||
|
||||
const response = {
|
||||
status: 'healthy',
|
||||
service: 'web-api',
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
logger.info('Basic health check successful', { status: response.status });
|
||||
return c.json(response);
|
||||
});
|
||||
|
||||
// Detailed health check with database connectivity
|
||||
healthRoutes.get('/detailed', async c => {
|
||||
logger.debug('Detailed health check requested');
|
||||
|
||||
const health = {
|
||||
status: 'healthy',
|
||||
service: 'web-api',
|
||||
timestamp: new Date().toISOString(),
|
||||
checks: {
|
||||
mongodb: { status: 'unknown', message: '' },
|
||||
postgresql: { status: 'unknown', message: '' },
|
||||
},
|
||||
};
|
||||
|
||||
// Check MongoDB
|
||||
logger.debug('Checking MongoDB connectivity');
|
||||
try {
|
||||
const mongoClient = container.mongodb;
|
||||
if (mongoClient && mongoClient.connected) {
|
||||
// Try a simple operation
|
||||
const db = mongoClient.getDatabase();
|
||||
await db.admin().ping();
|
||||
health.checks.mongodb = { status: 'healthy', message: 'Connected and responsive' };
|
||||
logger.debug('MongoDB health check passed');
|
||||
} else {
|
||||
health.checks.mongodb = { status: 'unhealthy', message: 'Not connected' };
|
||||
logger.warn('MongoDB health check failed - not connected');
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
health.checks.mongodb = {
|
||||
status: 'unhealthy',
|
||||
message: errorMessage,
|
||||
};
|
||||
logger.error('MongoDB health check failed', { error: errorMessage });
|
||||
}
|
||||
|
||||
// Check PostgreSQL
|
||||
logger.debug('Checking PostgreSQL connectivity');
|
||||
try {
|
||||
const postgresClient = container.postgres;
|
||||
if (postgresClient) {
|
||||
await postgresClient.query('SELECT 1');
|
||||
health.checks.postgresql = { status: 'healthy', message: 'Connected and responsive' };
|
||||
logger.debug('PostgreSQL health check passed');
|
||||
} else {
|
||||
health.checks.postgresql = { status: 'unhealthy', message: 'PostgreSQL client not available' };
|
||||
logger.warn('PostgreSQL health check failed - client not available');
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
health.checks.postgresql = {
|
||||
status: 'unhealthy',
|
||||
message: errorMessage,
|
||||
};
|
||||
logger.error('PostgreSQL health check failed', { error: errorMessage });
|
||||
}
|
||||
|
||||
// Overall status
|
||||
const allHealthy = Object.values(health.checks).every(check => check.status === 'healthy');
|
||||
health.status = allHealthy ? 'healthy' : 'unhealthy';
|
||||
|
||||
const statusCode = allHealthy ? 200 : 503;
|
||||
|
||||
if (allHealthy) {
|
||||
logger.info('Detailed health check successful - all systems healthy', {
|
||||
mongodb: health.checks.mongodb.status,
|
||||
postgresql: health.checks.postgresql.status,
|
||||
});
|
||||
} else {
|
||||
logger.warn('Detailed health check failed - some systems unhealthy', {
|
||||
mongodb: health.checks.mongodb.status,
|
||||
postgresql: health.checks.postgresql.status,
|
||||
overallStatus: health.status,
|
||||
});
|
||||
}
|
||||
|
||||
return c.json(health, statusCode);
|
||||
});
|
||||
|
||||
return healthRoutes;
|
||||
}
|
||||
|
||||
// Export legacy routes for backward compatibility during migration
|
||||
export const healthRoutes = createHealthRoutes({} as IServiceContainer);
|
||||
5
apps/stock/web-api/src/routes/index.ts
Normal file
5
apps/stock/web-api/src/routes/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
* Routes index - exports all route modules
|
||||
*/
|
||||
export { createExchangeRoutes } from './exchange.routes';
|
||||
export { healthRoutes } from './health.routes';
|
||||
Loading…
Add table
Add a link
Reference in a new issue