const express = require('express'); const { Pool } = require('pg'); const neo4j = require('neo4j-driver'); const redis = require('redis'); const app = express(); app.use(express.json()); // PostgreSQL const pgPool = new Pool({ host: 'localhost', port: 5433, database: 'quixzoom', user: 'quixzoom', password: 'quixzoom_secure_2026' }); // Neo4j const neo4jDriver = neo4j.driver('bolt://localhost:7687', neo4j.auth.basic('neo4j', 'quixzoom_neo4j_2026')); // Redis const redisClient = redis.createClient({ url: 'redis://localhost:6380' }); redisClient.connect().catch(console.error); // Health check app.get('/health', async (req, res) => { const status = { status: 'ok', timestamp: new Date().toISOString(), services: {} }; try { await pgPool.query('SELECT 1'); status.services.postgresql = 'ok'; } catch (e) { status.services.postgresql = 'error'; } try { const session = neo4jDriver.session(); await session.run('RETURN 1'); await session.close(); status.services.neo4j = 'ok'; } catch (e) { status.services.neo4j = 'error'; } try { await redisClient.ping(); status.services.redis = 'ok'; } catch (e) { status.services.redis = 'error'; } res.json(status); }); // Stats app.get('/stats', async (req, res) => { try { const pgResult = await pgPool.query(` SELECT (SELECT COUNT(*) FROM objects) as objects, (SELECT COUNT(*) FROM observations) as observations, (SELECT COUNT(*) FROM zoomers) as zoomers, (SELECT COUNT(*) FROM events) as events `); res.json({ postgresql: pgResult.rows[0], timestamp: new Date().toISOString() }); } catch (e) { res.status(500).json({ error: e.message }); } }); // Create object app.post('/objects', async (req, res) => { try { const { object_id, type, latitude, longitude, attributes } = req.body; const result = await pgPool.query( 'INSERT INTO objects (object_id, type, latitude, longitude, attributes) VALUES ($1, $2, $3, $4, $5) RETURNING *', [object_id, type, latitude, longitude, JSON.stringify(attributes || {})] ); await pgPool.query( 'INSERT INTO events (sequence_number, type, stream_id, aggregate_id, payload, timestamp) VALUES ((SELECT COALESCE(MAX(sequence_number), 0) + 1 FROM events), $1, $2, $3, $4, NOW())', ['ObjectRegistered', 'objects', object_id, JSON.stringify({ type, latitude, longitude, attributes })] ); res.json(result.rows[0]); } catch (e) { res.status(500).json({ error: e.message }); } }); // List objects app.get('/objects', async (req, res) => { try { const result = await pgPool.query('SELECT * FROM objects ORDER BY created_at DESC LIMIT 100'); res.json(result.rows); } catch (e) { res.status(500).json({ error: e.message }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log('[API] QUIXZOOM API Server running on port ' + PORT); console.log('[API] Health: http://localhost:' + PORT + '/health'); console.log('[API] Stats: http://localhost:' + PORT + '/stats'); });