/
kleara
/
KlearaFintech-MVP
Обзор
Документация
Войти
/
kleara
/
KlearaFintech-MVP
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
backend/server.js
370 строк
13 KB
Eugene Nefediev
Initial commit: Kleara MVP
05 фев 2026, 15:05
05 фев 2026, 15:05
ce56b07
Код
Авторство
О чём код?
const express = require('express'); const { Pool } = require('pg'); const cors = require('cors'); const app = express(); const port = 3000; console.log('🚀 Kleara Backend запущен (с blockchain integration)'); // CORS настройки app.use(cors({ origin: ['http://localhost:8080', 'http://localhost:3000', 'http://localhost:4000'], credentials: true })); app.use(express.json()); // Подключение к PostgreSQL const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgresql://postgres:password123@postgres:5432/payments', }); // URL Blockchain API const BLOCKCHAIN_API_URL = process.env.BLOCKCHAIN_API_URL || 'http://localhost:4000'; // Health check app.get('/health', (req, res) => { res.json({ status: 'OK', message: 'Kleara Backend работает', timestamp: new Date().toISOString(), version: '2.0.0', currencies: ['RUB', 'CNY', 'INR'], blockchain: { integration: true, mode: 'simulation', api: BLOCKCHAIN_API_URL, domain: 'kleara.net' } }); }); // Функция для создания/обновления таблицы async function ensureTableStructure() { try { await pool.query(` CREATE TABLE IF NOT EXISTS transactions ( id SERIAL PRIMARY KEY, sender VARCHAR(255) NOT NULL, receiver VARCHAR(255) NOT NULL, amount DECIMAL(15, 2) NOT NULL, currency VARCHAR(3) DEFAULT 'RUB', status VARCHAR(50) DEFAULT 'pending', blockchain_tx_id VARCHAR(255), blockchain_status VARCHAR(50) DEFAULT 'not_sent', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) `); // Добавляем колонки если их нет (для существующих таблиц) await pool.query(` ALTER TABLE transactions ADD COLUMN IF NOT EXISTS blockchain_tx_id VARCHAR(255), ADD COLUMN IF NOT EXISTS blockchain_status VARCHAR(50) DEFAULT 'not_sent'; `); console.log('✅ Database table structure verified'); } catch (error) { console.error('Error ensuring table structure:', error); } } // Проверка статуса блокчейна app.get('/health/blockchain', async (req, res) => { try { const response = await fetch(`${BLOCKCHAIN_API_URL}/health`); const data = await response.json(); res.json({ core: 'OK', blockchain: data, integrated: true }); } catch (error) { res.json({ core: 'OK', blockchain: { status: 'OFFLINE', error: error.message }, integrated: false }); } }); // Тест базы данных app.get('/api/test', async (req, res) => { try { // Гарантируем структуру таблицы await ensureTableStructure(); // Проверяем есть ли тестовые данные const countResult = await pool.query('SELECT COUNT(*) FROM transactions'); const count = parseInt(countResult.rows[0].count); if (count === 0) { // Добавляем тестовые данные с blockchain статусами await pool.query(` INSERT INTO transactions (sender, receiver, amount, currency, status, blockchain_status, blockchain_tx_id) VALUES ('alice@example.com', 'bob@example.com', 10000.00, 'RUB', 'completed', 'simulated_completed', 'kleara_tx_1_simulated'), ('bob@example.com', 'charlie@example.com', 5000.00, 'CNY', 'pending', 'not_sent', NULL), ('charlie@example.com', 'alice@example.com', 7500.00, 'INR', 'completed', 'simulated_completed', 'kleara_tx_3_simulated') `); } const result = await pool.query('SELECT COUNT(*) as count FROM transactions'); res.json({ success: true, message: 'База данных работает', count: parseInt(result.rows[0].count), supported_currencies: ['RUB', 'CNY', 'INR'], blockchain_ready: true, mode: 'simulation' }); } catch (error) { console.error('Database test error:', error); res.status(500).json({ success: false, error: error.message }); } }); // Получить все транзакции app.get('/api/transactions', async (req, res) => { try { const result = await pool.query(` SELECT * FROM transactions ORDER BY created_at DESC LIMIT 50 `); res.json({ success: true, count: result.rowCount, data: result.rows, blockchain_integration: true, mode: 'simulation' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Создать новую транзакцию (с blockchain integration) app.post('/api/transactions', async (req, res) => { try { const { sender, receiver, amount, currency = 'RUB' } = req.body; // Валидация валюты const allowedCurrencies = ['RUB', 'CNY', 'INR']; if (!allowedCurrencies.includes(currency)) { return res.status(400).json({ success: false, error: `Валюта ${currency} не поддерживается. Доступные: ${allowedCurrencies.join(', ')}` }); } if (amount <= 0) { return res.status(400).json({ success: false, error: 'Сумма должна быть больше 0' }); } // Гарантируем структуру таблицы await ensureTableStructure(); // Сохраняем в PostgreSQL const result = await pool.query( `INSERT INTO transactions (sender, receiver, amount, currency, status, blockchain_status) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, [sender, receiver, amount, currency, 'pending', 'pending_blockchain'] ); const transaction = result.rows[0]; // Асинхронно отправляем в blockchain API setTimeout(async () => { try { const blockchainResponse = await fetch(`${BLOCKCHAIN_API_URL}/api/transactions/blockchain`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transactionId: transaction.id }) }); if (blockchainResponse.ok) { console.log(`Transaction ${transaction.id} submitted to blockchain simulation`); } } catch (blockchainError) { console.error(`Failed to submit transaction ${transaction.id} to blockchain:`, blockchainError); } }, 100); res.status(201).json({ success: true, message: 'Транзакция создана. Отправка в блокчейн...', data: transaction, blockchain: { status: 'pending', mode: 'simulation', domain: 'kleara.net', note: 'Will be processed asynchronously' } }); } catch (error) { console.error('Create transaction error:', error); res.status(500).json({ success: false, error: error.message }); } }); // Получить статус блокчейн транзакции app.get('/api/transactions/:id/blockchain', async (req, res) => { try { const { id } = req.params; const txResult = await pool.query('SELECT * FROM transactions WHERE id = $1', [id]); if (txResult.rows.length === 0) { return res.status(404).json({ success: false, error: 'Transaction not found' }); } const tx = txResult.rows[0]; if (!tx.blockchain_tx_id) { return res.json({ success: true, data: { postgres_id: id, blockchain: { status: 'not_submitted', message: 'Transaction not yet submitted to blockchain', mode: 'simulation' } } }); } // Запрашиваем статус из blockchain-api try { const response = await fetch(`${BLOCKCHAIN_API_URL}/blockchain/transactions/${tx.blockchain_tx_id}`); const blockchainData = await response.json(); res.json({ success: true, data: { postgres: tx, blockchain: blockchainData.data } }); } catch (blockchainError) { res.json({ success: true, data: { postgres: tx, blockchain: { status: tx.blockchain_status || 'unknown', error: 'Blockchain API temporarily unavailable', mode: 'simulation' } } }); } } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Получить пулы ликвидности из блокчейна app.get('/api/blockchain/pools', async (req, res) => { try { const response = await fetch(`${BLOCKCHAIN_API_URL}/blockchain/pools`); const data = await response.json(); res.json({ success: true, source: 'blockchain_api', domain: 'kleara.net', mode: 'simulation', data: data.data }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Получить статистику блокчейна app.get('/api/blockchain/stats', async (req, res) => { try { const response = await fetch(`${BLOCKCHAIN_API_URL}/blockchain/stats`); const data = await response.json(); res.json({ success: true, domain: 'kleara.net', mode: 'simulation', data: data.data }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Статистика транзакций app.get('/api/stats', async (req, res) => { try { const result = await pool.query(` SELECT currency, COUNT(*) as transaction_count, SUM(amount) as total_amount, AVG(amount) as avg_amount, COUNT(CASE WHEN blockchain_status LIKE 'simulated_%' THEN 1 END) as blockchain_count, COUNT(CASE WHEN blockchain_status = 'simulated_completed' THEN 1 END) as blockchain_completed FROM transactions GROUP BY currency ORDER BY total_amount DESC `); res.json({ success: true, data: result.rows, blockchain_integration: true, mode: 'simulation', domain: 'kleara.net' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Синхронизировать с блокчейном app.post('/api/blockchain/sync', async (req, res) => { try { const response = await fetch(`${BLOCKCHAIN_API_URL}/blockchain/sync`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); res.json({ success: true, message: 'Synchronization initiated', data: data }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // Инициализация при запуске ensureTableStructure().then(() => { console.log('✅ Database initialization complete'); }); app.listen(port, () => { console.log(`✅ Backend запущен на порту ${port}`); console.log(`✅ Health: http://localhost:${port}/health`); console.log(`✅ Blockchain API: ${BLOCKCHAIN_API_URL}`); console.log(`✅ Domain: kleara.net`); console.log(`✅ Mode: Simulation (для MVP)`); console.log(`✅ Валюта: RUB, CNY, INR`); });