Dashboard Endpoint¶
Аудитория: разработчики, frontend-инженеры Последнее обновление: 2025-11-17 Краткое содержание: Детальная документация Dashboard endpoint — получение полной сводки пользователя (баланс, активные инвестиции, недавние транзакции, notifications) в одном API вызове. Optimized для главной страницы user-app.
Обзор Endpoint¶
| Метод | Endpoint | Описание | Auth требуется |
|---|---|---|---|
| GET | /api/user/dashboard |
Полная сводка dashboard пользователя | ✅ Да |
GET /api/user/dashboard¶
Получить полную dashboard информацию для аутентифицированного пользователя — баланс, инвестиции, транзакции, уведомления в одном запросе.
Запрос¶
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Query параметры:
| Параметр | Тип | Обязательно | Описание | По умолчанию |
|---|---|---|---|---|
includeCharts |
boolean | ❌ Нет | Включить данные для графиков | false |
period |
number | ❌ Нет | Период для графиков в днях (7, 30, 90) | 30 |
recentTransactions |
number | ❌ Нет | Количество недавних транзакций | 5 |
recentNotifications |
number | ❌ Нет | Количество недавних уведомлений | 3 |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"user": {
"id": 42,
"email": "user@saga-test.com",
"firstName": "John",
"lastName": "Doe",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"createdAt": "2025-09-01T00:00:00Z",
"lastLoginAt": "2025-10-06T08:00:00Z"
},
"balance": {
"total": "5000.00",
"available": "2500.00",
"invested": "2500.00",
"currency": "USDC",
"breakdown": {
"deposits": "5000.00",
"withdrawals": "0.00",
"earnings": "150.50",
"fees": "10.00"
},
"change24h": {
"amount": "+50.25",
"percentage": "+1.02%"
}
},
"investments": {
"active": [
{
"id": "inv_abc123",
"strategyId": "balanced-10",
"strategyName": "Balanced 10% APY",
"amount": "1500.00",
"currentValue": "1575.25",
"apy": 10.0,
"earnedToDate": "75.25",
"startDate": "2025-09-15T00:00:00Z",
"daysActive": 21,
"performance": {
"roi": "+5.02%",
"dailyEarnings": "4.11"
}
},
{
"id": "inv_def456",
"strategyId": "conservative-5",
"strategyName": "Conservative 5% APY",
"amount": "1000.00",
"currentValue": "1025.00",
"apy": 5.0,
"earnedToDate": "25.00",
"startDate": "2025-09-20T00:00:00Z",
"daysActive": 16,
"performance": {
"roi": "+2.50%",
"dailyEarnings": "1.37"
}
}
],
"summary": {
"totalInvested": "2500.00",
"totalCurrentValue": "2600.25",
"totalEarnings": "100.25",
"averageAPY": 7.5,
"totalROI": "+4.01%"
}
},
"recentTransactions": [
{
"id": "txn_abc123",
"type": "deposit",
"amount": "1000.00",
"currency": "USDC",
"status": "completed",
"createdAt": "2025-10-06T10:00:00Z"
},
{
"id": "txn_def456",
"type": "investment",
"amount": "500.00",
"currency": "USDC",
"status": "completed",
"strategyName": "Balanced 10% APY",
"createdAt": "2025-10-06T11:00:00Z"
},
{
"id": "txn_ghi789",
"type": "earning",
"amount": "5.50",
"currency": "USDC",
"status": "completed",
"strategyName": "Balanced 10% APY",
"createdAt": "2025-10-06T12:00:00Z"
}
],
"recentNotifications": [
{
"id": "notif_abc123",
"type": "investment",
"title": "Инвестиция успешно создана",
"message": "Ваша инвестиция в стратегию Balanced (10% APY) на сумму $500.00 успешно создана",
"isRead": false,
"createdAt": "2025-10-06T12:00:00Z"
},
{
"id": "notif_def456",
"type": "earning",
"title": "Получена доходность",
"message": "Вы получили $5.50 доходности от стратегии Balanced (10% APY)",
"isRead": true,
"createdAt": "2025-10-06T00:00:05Z"
}
],
"portfolio": {
"totalValue": "5000.00",
"profitLoss": "+150.50",
"profitLossPercentage": "+3.10%",
"bestPerformer": {
"strategy": "Balanced 10% APY",
"roi": "+5.02%"
},
"assetAllocation": [
{
"category": "Stablecoins",
"amount": "2500.00",
"percentage": 50.0
},
{
"category": "DeFi Strategies",
"amount": "2500.00",
"percentage": 50.0
}
]
},
"charts": {
"portfolioValue": [
{ "date": "2025-09-06", "value": "5000.00" },
{ "date": "2025-09-13", "value": "5025.50" },
{ "date": "2025-09-20", "value": "5050.25" },
{ "date": "2025-09-27", "value": "5100.00" },
{ "date": "2025-10-04", "value": "5150.50" }
],
"earningsHistory": [
{ "date": "2025-09-06", "earnings": "0.00" },
{ "date": "2025-09-13", "earnings": "25.50" },
{ "date": "2025-09-20", "earnings": "50.25" },
{ "date": "2025-09-27", "earnings": "100.00" },
{ "date": "2025-10-04", "earnings": "150.50" }
],
"investmentDistribution": [
{ "strategy": "Balanced 10% APY", "amount": "1500.00", "percentage": 60.0 },
{ "strategy": "Conservative 5% APY", "amount": "1000.00", "percentage": 40.0 }
]
},
"quickActions": [
{
"action": "deposit",
"label": "Пополнить баланс",
"url": "/deposits",
"enabled": true
},
{
"action": "invest",
"label": "Создать инвестицию",
"url": "/investments/create",
"enabled": true
},
{
"action": "withdraw",
"label": "Вывести средства",
"url": "/withdrawals/create",
"enabled": true,
"requiresApproval": true
}
],
"systemStatus": {
"blockchain": "healthy",
"database": "healthy",
"api": "healthy",
"lastUpdate": "2025-10-06T12:34:56Z"
}
},
"timestamp": "2025-10-06T12:34:56Z"
}
Секции ответа:
user¶
Информация о пользователе:
- id, email, firstName, lastName
- walletAddress - Ethereum адрес
- createdAt, lastLoginAt - Timestamps активности
balance¶
Финансовая сводка:
- total - Общий баланс (available + invested)
- available - Доступно для инвестиций/вывода
- invested - Заблокировано в стратегиях
- breakdown - Детали (deposits, withdrawals, earnings, fees)
- change24h - Изменение за последние 24 часа
investments¶
Активные инвестиции:
- active[] - Список активных инвестиций с performance
- summary - Агрегированная статистика (total invested, earnings, ROI)
- Каждая инвестиция включает currentValue, apy, earnedToDate, performance.roi
recentTransactions¶
Последние N транзакций (по умолчанию 5):
- type - deposit, investment, earning, withdrawal, fee
- amount, currency, status
- strategyName - Для investment/earning операций
recentNotifications¶
Последние N уведомлений (по умолчанию 3):
- type - investment, earning, withdrawal, security, system
- title, message, isRead
portfolio¶
Портфолио сводка:
- totalValue - Общая стоимость портфолио
- profitLoss - Profit/Loss в абсолютных числах
- profitLossPercentage - Profit/Loss в процентах
- bestPerformer - Лучшая стратегия
- assetAllocation - Распределение активов
charts (опционально)¶
Данные для графиков (если includeCharts=true):
- portfolioValue[] - История стоимости портфолио
- earningsHistory[] - История заработка
- investmentDistribution[] - Распределение инвестиций
quickActions¶
Быстрые действия для UI:
- action - deposit, invest, withdraw
- label - Текст кнопки
- url - Путь навигации
- enabled - Доступность действия
systemStatus¶
Статус системы:
- blockchain, database, api - healthy/degraded/down
- lastUpdate - Timestamp последнего обновления
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
| 401 | TOKEN_INVALID |
Некорректная JWT подпись |
| 404 | USER_NOT_FOUND |
Аккаунт пользователя не существует |
| 503 | PARTIAL_DATA_AVAILABLE |
Часть данных недоступна (blockchain/database проблемы) |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
# Получить полный dashboard
curl -X GET "https://app.saga.surf/api/user/dashboard" \
-H "Authorization: Bearer $TOKEN"
# Получить dashboard с графиками за 30 дней
curl -X GET "https://app.saga.surf/api/user/dashboard?includeCharts=true&period=30" \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
// Загрузить dashboard данные
async function loadDashboard(includeCharts: boolean = false, period: number = 30) {
const params = new URLSearchParams({
includeCharts: includeCharts.toString(),
period: period.toString()
});
const response = await fetch(`/api/user/dashboard?${params}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
const { data } = await response.json();
return data;
}
// Отрисовать dashboard
async function renderDashboard() {
const dashboard = await loadDashboard(true, 30);
// Отобразить баланс
document.getElementById('total-balance').textContent = `$${dashboard.balance.total}`;
document.getElementById('available-balance').textContent = `$${dashboard.balance.available}`;
document.getElementById('invested-balance').textContent = `$${dashboard.balance.invested}`;
// Отобразить изменение за 24ч
const change24h = document.getElementById('change-24h');
change24h.textContent = `${dashboard.balance.change24h.amount} (${dashboard.balance.change24h.percentage})`;
change24h.className = dashboard.balance.change24h.amount.startsWith('+') ? 'positive' : 'negative';
// Отобразить активные инвестиции
const investmentsList = document.getElementById('active-investments');
dashboard.investments.active.forEach(inv => {
const item = document.createElement('div');
item.innerHTML = `
<h3>${inv.strategyName}</h3>
<p>Amount: $${inv.amount} → $${inv.currentValue}</p>
<p>ROI: ${inv.performance.roi} | APY: ${inv.apy}%</p>
<p>Daily Earnings: $${inv.performance.dailyEarnings}</p>
`;
investmentsList.appendChild(item);
});
// Отобразить график портфолио
if (dashboard.charts) {
renderPortfolioChart(dashboard.charts.portfolioValue);
renderEarningsChart(dashboard.charts.earningsHistory);
}
}
Распространённые сценарии использования¶
Dashboard компонент React¶
import { useEffect, useState } from 'react';
function Dashboard() {
const [dashboard, setDashboard] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
loadDashboardData();
}, []);
async function loadDashboardData() {
try {
const response = await fetch('/api/user/dashboard?includeCharts=true&period=30', {
headers: { 'Authorization': `Bearer ${token}` }
});
const { data } = await response.json();
setDashboard(data);
} catch (error) {
console.error('Failed to load dashboard:', error);
} finally {
setLoading(false);
}
}
if (loading) return <LoadingSpinner />;
if (!dashboard) return <ErrorMessage />;
return (
<div className="dashboard">
{/* Balance Card */}
<div className="balance-card">
<h2>Общий баланс</h2>
<div className="amount">${dashboard.balance.total} {dashboard.balance.currency}</div>
<div className={`change ${dashboard.balance.change24h.amount.startsWith('+') ? 'positive' : 'negative'}`}>
{dashboard.balance.change24h.amount} ({dashboard.balance.change24h.percentage}) за 24ч
</div>
<div className="breakdown">
<span>Доступно: ${dashboard.balance.available}</span>
<span>Инвестировано: ${dashboard.balance.invested}</span>
</div>
</div>
{/* Investments Summary */}
<div className="investments-summary">
<h2>Активные инвестиции</h2>
<div className="summary">
<p>Всего заработано: +${dashboard.investments.summary.totalEarnings}</p>
<p>Средний APY: {dashboard.investments.summary.averageAPY}%</p>
<p>ROI: {dashboard.investments.summary.totalROI}</p>
</div>
{dashboard.investments.active.map(inv => (
<InvestmentCard key={inv.id} investment={inv} />
))}
</div>
{/* Recent Activity */}
<div className="recent-activity">
<h2>Недавние транзакции</h2>
{dashboard.recentTransactions.map(tx => (
<TransactionItem key={tx.id} transaction={tx} />
))}
</div>
{/* Notifications */}
<div className="notifications">
<h2>Уведомления</h2>
{dashboard.recentNotifications.map(notif => (
<NotificationItem key={notif.id} notification={notif} />
))}
</div>
{/* Charts */}
{dashboard.charts && (
<>
<PortfolioValueChart data={dashboard.charts.portfolioValue} />
<EarningsHistoryChart data={dashboard.charts.earningsHistory} />
</>
)}
{/* Quick Actions */}
<div className="quick-actions">
{dashboard.quickActions.map(action => (
<button
key={action.action}
onClick={() => router.push(action.url)}
disabled={!action.enabled}
>
{action.label}
</button>
))}
</div>
</div>
);
}
Performance optimization с SWR¶
import useSWR from 'swr';
function useDashboard(includeCharts = true, period = 30) {
const fetcher = (url: string) =>
fetch(url, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json()).then(d => d.data);
const { data, error, mutate } = useSWR(
`/api/user/dashboard?includeCharts=${includeCharts}&period=${period}`,
fetcher,
{
revalidateOnFocus: true,
refreshInterval: 60000, // Обновление каждые 60 секунд
}
);
return {
dashboard: data,
isLoading: !error && !data,
isError: error,
refresh: mutate
};
}
// Использование
function DashboardWithSWR() {
const { dashboard, isLoading, refresh } = useDashboard(true, 30);
if (isLoading) return <Spinner />;
return (
<div>
<button onClick={refresh}>Обновить</button>
<DashboardContent data={dashboard} />
</div>
);
}
Partial data handling¶
// Graceful degradation при partial data
async function loadDashboardWithFallback() {
try {
const response = await fetch('/api/user/dashboard', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (response.status === 503) {
// Partial data available
const { data, warning } = await response.json();
console.warn('Dashboard loaded with partial data:', warning);
// Отобразить что доступно с индикацией проблем
return {
...data,
hasWarnings: true,
warningMessage: warning
};
}
const { data } = await response.json();
return data;
} catch (error) {
console.error('Failed to load dashboard:', error);
throw error;
}
}
Связанная документация¶
Другие User Endpoints:
- Balance & Transactions - Детальная информация о балансе
- Investments - Управление инвестициями
- Notifications - Система уведомлений
- Deposits - Операции депозита
Архитектура:
📋 Метаданные¶
Версия: 2.6.268
Обновлено: 2025-10-21
Статус: Published