diff --git a/apps/data-sync-service/src/index.ts b/apps/data-sync-service/src/index.ts index f6638c0..2d2dcf6 100644 --- a/apps/data-sync-service/src/index.ts +++ b/apps/data-sync-service/src/index.ts @@ -1,16 +1,23 @@ /** * Data Sync Service - Sync raw MongoDB data to PostgreSQL master records */ + +// Framework imports import { Hono } from 'hono'; import { cors } from 'hono/cors'; + +// Library imports import { initializeServiceConfig } from '@stock-bot/config-new'; import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger'; import { createAndConnectMongoDBClient, MongoDBClient } from '@stock-bot/mongodb-client'; import { createAndConnectPostgreSQLClient, PostgreSQLClient } from '@stock-bot/postgres-client'; import { Shutdown } from '@stock-bot/shutdown'; + +// Local imports import { enhancedSyncManager } from './services/enhanced-sync-manager'; import { syncManager } from './services/sync-manager'; import { setMongoDBClient, setPostgreSQLClient } from './clients'; +import { healthRoutes, syncRoutes, enhancedSyncRoutes, statsRoutes } from './routes'; // Initialize configuration with automatic monorepo config inheritance const config = await initializeServiceConfig(); @@ -50,140 +57,11 @@ let mongoClient: MongoDBClient | null = null; // Initialize shutdown manager const shutdown = Shutdown.getInstance({ timeout: 15000 }); -// Basic health check endpoint -app.get('/health', c => { - return c.json({ - status: 'healthy', - service: 'data-sync-service', - timestamp: new Date().toISOString(), - }); -}); - -// Manual sync trigger endpoints -app.post('/sync/symbols', async c => { - try { - const result = await syncManager.syncQMSymbols(); - return c.json({ success: true, result }); - } catch (error) { - logger.error('Manual symbol sync failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -app.post('/sync/exchanges', async c => { - try { - const result = await syncManager.syncQMExchanges(); - return c.json({ success: true, result }); - } catch (error) { - logger.error('Manual exchange sync failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -// Get sync status -app.get('/sync/status', async c => { - try { - const status = await syncManager.getSyncStatus(); - return c.json(status); - } catch (error) { - logger.error('Failed to get sync status', { error }); - return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); - } -}); - -// Enhanced sync endpoints -app.post('/sync/exchanges/all', async c => { - try { - const clearFirst = c.req.query('clear') === 'true'; - const result = await enhancedSyncManager.syncAllExchanges(clearFirst); - return c.json({ success: true, result }); - } catch (error) { - logger.error('Enhanced exchange sync failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -app.post('/sync/provider-mappings/qm', async c => { - try { - const result = await enhancedSyncManager.syncQMProviderMappings(); - return c.json({ success: true, result }); - } catch (error) { - logger.error('QM provider mappings sync failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -app.post('/sync/symbols/:provider', async c => { - try { - const provider = c.req.param('provider'); - const clearFirst = c.req.query('clear') === 'true'; - const result = await enhancedSyncManager.syncSymbolsFromProvider(provider, clearFirst); - return c.json({ success: true, result }); - } catch (error) { - logger.error('Enhanced symbol sync failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -// Clear data endpoint -app.post('/sync/clear', async c => { - try { - const result = await enhancedSyncManager.clearPostgreSQLData(); - return c.json({ success: true, result }); - } catch (error) { - logger.error('Clear PostgreSQL data failed', { error }); - return c.json( - { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, - 500 - ); - } -}); - -// Enhanced status endpoints -app.get('/sync/status/enhanced', async c => { - try { - const status = await enhancedSyncManager.getSyncStatus(); - return c.json(status); - } catch (error) { - logger.error('Failed to get enhanced sync status', { error }); - return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); - } -}); - -app.get('/sync/stats/exchanges', async c => { - try { - const stats = await enhancedSyncManager.getExchangeStats(); - return c.json(stats); - } catch (error) { - logger.error('Failed to get exchange stats', { error }); - return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); - } -}); - -app.get('/sync/stats/provider-mappings', async c => { - try { - const stats = await enhancedSyncManager.getProviderMappingStats(); - return c.json(stats); - } catch (error) { - logger.error('Failed to get provider mapping stats', { error }); - return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); - } -}); +// Mount routes +app.route('/health', healthRoutes); +app.route('/sync', syncRoutes); +app.route('/sync', enhancedSyncRoutes); +app.route('/sync/stats', statsRoutes); // Initialize services async function initializeServices() { diff --git a/apps/data-sync-service/src/routes/enhanced-sync.routes.ts b/apps/data-sync-service/src/routes/enhanced-sync.routes.ts new file mode 100644 index 0000000..60c58bd --- /dev/null +++ b/apps/data-sync-service/src/routes/enhanced-sync.routes.ts @@ -0,0 +1,62 @@ +import { Hono } from 'hono'; +import { getLogger } from '@stock-bot/logger'; +import { enhancedSyncManager } from '../services/enhanced-sync-manager'; + +const logger = getLogger('enhanced-sync-routes'); +const enhancedSync = new Hono(); + +// Enhanced sync endpoints +enhancedSync.post('/exchanges/all', async c => { + try { + const clearFirst = c.req.query('clear') === 'true'; + const result = await enhancedSyncManager.syncAllExchanges(clearFirst); + return c.json({ success: true, result }); + } catch (error) { + logger.error('Enhanced exchange sync failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +enhancedSync.post('/provider-mappings/qm', async c => { + try { + const result = await enhancedSyncManager.syncQMProviderMappings(); + return c.json({ success: true, result }); + } catch (error) { + logger.error('QM provider mappings sync failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +enhancedSync.post('/symbols/:provider', async c => { + try { + const provider = c.req.param('provider'); + const clearFirst = c.req.query('clear') === 'true'; + const result = await enhancedSyncManager.syncSymbolsFromProvider(provider, clearFirst); + return c.json({ success: true, result }); + } catch (error) { + logger.error('Enhanced symbol sync failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +// Enhanced status endpoints +enhancedSync.get('/status/enhanced', async c => { + try { + const status = await enhancedSyncManager.getSyncStatus(); + return c.json(status); + } catch (error) { + logger.error('Failed to get enhanced sync status', { error }); + return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); + } +}); + +export { enhancedSync as enhancedSyncRoutes }; \ No newline at end of file diff --git a/apps/data-sync-service/src/routes/health.routes.ts b/apps/data-sync-service/src/routes/health.routes.ts new file mode 100644 index 0000000..68d8afd --- /dev/null +++ b/apps/data-sync-service/src/routes/health.routes.ts @@ -0,0 +1,14 @@ +import { Hono } from 'hono'; + +const health = new Hono(); + +// Basic health check endpoint +health.get('/', c => { + return c.json({ + status: 'healthy', + service: 'data-sync-service', + timestamp: new Date().toISOString(), + }); +}); + +export { health as healthRoutes }; \ No newline at end of file diff --git a/apps/data-sync-service/src/routes/index.ts b/apps/data-sync-service/src/routes/index.ts new file mode 100644 index 0000000..b106768 --- /dev/null +++ b/apps/data-sync-service/src/routes/index.ts @@ -0,0 +1,5 @@ +// Export all route modules +export { healthRoutes } from './health.routes'; +export { syncRoutes } from './sync.routes'; +export { enhancedSyncRoutes } from './enhanced-sync.routes'; +export { statsRoutes } from './stats.routes'; \ No newline at end of file diff --git a/apps/data-sync-service/src/routes/stats.routes.ts b/apps/data-sync-service/src/routes/stats.routes.ts new file mode 100644 index 0000000..813679c --- /dev/null +++ b/apps/data-sync-service/src/routes/stats.routes.ts @@ -0,0 +1,29 @@ +import { Hono } from 'hono'; +import { getLogger } from '@stock-bot/logger'; +import { enhancedSyncManager } from '../services/enhanced-sync-manager'; + +const logger = getLogger('stats-routes'); +const stats = new Hono(); + +// Statistics endpoints +stats.get('/exchanges', async c => { + try { + const statsData = await enhancedSyncManager.getExchangeStats(); + return c.json(statsData); + } catch (error) { + logger.error('Failed to get exchange stats', { error }); + return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); + } +}); + +stats.get('/provider-mappings', async c => { + try { + const statsData = await enhancedSyncManager.getProviderMappingStats(); + return c.json(statsData); + } catch (error) { + logger.error('Failed to get provider mapping stats', { error }); + return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); + } +}); + +export { stats as statsRoutes }; \ No newline at end of file diff --git a/apps/data-sync-service/src/routes/sync.routes.ts b/apps/data-sync-service/src/routes/sync.routes.ts new file mode 100644 index 0000000..68eaf47 --- /dev/null +++ b/apps/data-sync-service/src/routes/sync.routes.ts @@ -0,0 +1,61 @@ +import { Hono } from 'hono'; +import { getLogger } from '@stock-bot/logger'; +import { syncManager } from '../services/sync-manager'; +import { enhancedSyncManager } from '../services/enhanced-sync-manager'; + +const logger = getLogger('sync-routes'); +const sync = new Hono(); + +// Manual sync trigger endpoints +sync.post('/symbols', async c => { + try { + const result = await syncManager.syncQMSymbols(); + return c.json({ success: true, result }); + } catch (error) { + logger.error('Manual symbol sync failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +sync.post('/exchanges', async c => { + try { + const result = await syncManager.syncQMExchanges(); + return c.json({ success: true, result }); + } catch (error) { + logger.error('Manual exchange sync failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +// Get sync status +sync.get('/status', async c => { + try { + const status = await syncManager.getSyncStatus(); + return c.json(status); + } catch (error) { + logger.error('Failed to get sync status', { error }); + return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500); + } +}); + +// Clear data endpoint +sync.post('/clear', async c => { + try { + const result = await enhancedSyncManager.clearPostgreSQLData(); + return c.json({ success: true, result }); + } catch (error) { + logger.error('Clear PostgreSQL data failed', { error }); + return c.json( + { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, + 500 + ); + } +}); + +export { sync as syncRoutes }; \ No newline at end of file