docs: describe manual bank card accounting
Document exact balances, corrections, archive behavior and safe migration and rollback. Update product navigation and UI catalog.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
# WealthLedger: документация системы
|
||||
|
||||
WealthLedger помогает частному инвестору понимать состав портфеля T-Bank,
|
||||
исполненные операции, полученный доход и будущие выплаты. Здесь объясняются
|
||||
исполненные операции, полученный доход и будущие выплаты, а также вручную вести
|
||||
банковские карты и повседневные расходы. Здесь объясняются
|
||||
продукт, понятия, функции, взаимодействия и причины архитектурных решений.
|
||||
Основной текст можно читать без исходников; технические ссылки нужны для
|
||||
дальнейшей проверки и изменения системы.
|
||||
@@ -28,6 +29,7 @@ WealthLedger помогает частному инвестору понимат
|
||||
| --- | --- |
|
||||
| [Аутентификация](domains/authentication/overview.md) | Регистрация, вход, восстановление и завершение сессии |
|
||||
| [Счета](domains/accounts/overview.md) | Доступные счета, сводки и состояния каждого счёта |
|
||||
| [Банковские карты](domains/cards/overview.md) | Ручные остатки, операции, категории, возвраты, месячные сводки и исправления |
|
||||
| [Портфель](domains/portfolio/overview.md) | Позиции, остатки, суммы, структура и свежесть |
|
||||
| [Все счета](domains/portfolio/all-accounts.md) | Общий портфель, происхождение строк и сводные разделы |
|
||||
| [Операции](domains/operations/overview.md) | Исполненные операции, фильтры и пагинация |
|
||||
@@ -48,7 +50,7 @@ WealthLedger помогает частному инвестору понимат
|
||||
| Узнать причину архитектурного решения | [Журнал ADR](adr/README.md) |
|
||||
| Изменить или проверить систему | [Сопровождение](development/README.md), затем инструкции нужного репозитория |
|
||||
|
||||
Практический tutorial первого финансового сценария пока не подготовлен:
|
||||
Практический tutorial первого инвестиционного сценария пока не подготовлен:
|
||||
он требует подключения брокера, а запуск на новой базе имеет известное
|
||||
ограничение. Маршрут первого знакомства выше — чтение, не учебный запуск.
|
||||
UI-каталог содержит безопасные вымышленные примеры и поясняет границы их использования.
|
||||
|
||||
@@ -38,7 +38,7 @@ SPA выполняется в браузере пользователя. Backend
|
||||
| --- | --- |
|
||||
| React SPA | Экраны, навигация, формы, состояние входа и клиентский кэш ответов; форматирование денежных значений |
|
||||
| Backend API | Локальная идентичность, сессии, проверка доступа, подключение брокера, нормализация внешних данных, точные расчёты и серверные кэши |
|
||||
| SQLite | Долговременное хранение локальных пользователей, сессий и зашифрованных подключений |
|
||||
| SQLite | Долговременное хранение локальных пользователей, сессий, зашифрованных подключений и ручной банковской истории |
|
||||
| Внешние системы | Данные брокера, публичные сведения об инструментах и изображения в пределах своей ответственности |
|
||||
|
||||
Frontend организован слоями `app → pages → features → entities → shared`:
|
||||
@@ -66,6 +66,19 @@ SQLite содержит пользователя с нормализованны
|
||||
Пароли хешируются bcrypt; token брокера шифруется AES-256-GCM. Plaintext
|
||||
credentials не являются сохраняемым представлением этих данных.
|
||||
|
||||
Ручной банковский учёт хранит карты, пользовательские категории и операции
|
||||
в отдельных таблицах, связанных с User. Начальный остаток и суммы записаны
|
||||
целыми bigint-копейками, календарные даты — днями без времени. Перевод хранится
|
||||
одной операцией с двумя картами; возврат связан с исходной покупкой. Баланс
|
||||
вычисляется из неудалённой истории и отдельно не сохраняется.
|
||||
|
||||
Банковские запросы проверяют локального владельца каждой связи и не используют
|
||||
подключение брокера. Транзакции, ограничения уникальности и версии согласуют
|
||||
переводы, возвраты и конкурирующие исправления. Fingerprint исходного ввода
|
||||
и отметка удаления защищают от повторного создания после потерянного ответа
|
||||
или перезапуска. Архив обратим и сохраняет историю. Подробности —
|
||||
[банковские карты](../domains/cards/overview.md).
|
||||
|
||||
Сессии и подключение связаны с владельцем. Access token подтверждает
|
||||
локального пользователя, но `accountId` из URL сам по себе не даёт права
|
||||
читать брокерский счёт. Backend получает текущее подключение пользователя
|
||||
|
||||
@@ -28,8 +28,10 @@ T-Bank token вводится пользователем через интерф
|
||||
**Известное ограничение:** ранее была зафиксирована ошибка `Schema engine error`
|
||||
на новой временной SQLite-базе до создания схемы. Условия проверки и пересмотра —
|
||||
в [ограничении сквозной проверки](verification.md#известное-ограничение-сквозной-проверки).
|
||||
Пользовательская база для такого воспроизведения не нужна; полный первый запуск
|
||||
на чистой базе этим свидетельством не подтверждён.
|
||||
На Node 22.21.0 / Prisma 7.9.1 подтверждено три последовательных применения
|
||||
миграций к новым временным базам с `RUST_LOG=info` вне sandbox. Без этой
|
||||
переменной ошибка воспроизводится. Пользовательская база для воспроизведения
|
||||
не нужна; успешная миграция сама по себе не подтверждает полный первый запуск.
|
||||
|
||||
В development доступна [локальная Swagger UI](http://localhost:3000/api/docs)
|
||||
при стандартном порте API. Она показывает контракт, но не доказывает доступность
|
||||
@@ -57,8 +59,36 @@ refresh-cookie получает Secure flag и требует защищённо
|
||||
4. «Доходы» показывают полученные выплаты, «События» — будущие.
|
||||
5. При выходе локальная сессия и её клиентский кэш очищаются.
|
||||
|
||||
Без T-Bank token доступны регистрация, вход и состояние отсутствующего
|
||||
подключения. Это не подтверждает работу финансовых сценариев.
|
||||
Без T-Bank token доступны регистрация, вход, состояние отсутствующего
|
||||
подключения и [ручной банковский учёт](../domains/cards/overview.md).
|
||||
Банковский сценарий не подтверждает доступность инвестиционных поставщиков.
|
||||
|
||||
## Сохранение данных и откат
|
||||
|
||||
Перед обновлением сохраняется согласованный SQLite backup; ключ шифрования
|
||||
T-Bank хранится отдельно. Для работающей базы используется SQLite backup API,
|
||||
который учитывает WAL. Несогласованное копирование файлов базы и WAL не является
|
||||
резервной копией. Восстановление сначала проверяется на отдельном файле.
|
||||
|
||||
Банковская миграция добавляет таблицы, сохраняя User, Session и TbankConnection.
|
||||
При необходимости отката приложения сначала прекращаются новые записи и
|
||||
сохраняется актуальный снимок. Затем возвращается совместимая предыдущая версия
|
||||
backend при сохранении расширенной схемы. Старый backup не восстанавливается
|
||||
поверх новой истории: это удалило бы введённые банковские операции.
|
||||
|
||||
Совместимость проверена с исходной версией backend
|
||||
`8ec172f48eefa2237dc0c16919fbb2e726b39a65`: она выполняла вход с расширенной
|
||||
схемой, а новая версия после возврата читала прежние карты и операции.
|
||||
Отдельно проверены перезапуск, служебные данные защиты повторов и приложение
|
||||
на восстановленной SQLite-копии. Это подтверждение конкретной пары версий,
|
||||
а не гарантия совместимости любого будущего изменения схемы.
|
||||
|
||||
Проверка воспроизводится через
|
||||
[процессный сценарий](../../backend/test/bank-cards-durability.cjs)
|
||||
с каталогом отдельно собранного baseline: после активации backend `.nvmrc`
|
||||
выполнить `node test/bank-cards-durability.cjs <baseline-directory>`.
|
||||
Сценарий создаёт собственные временные базы и вымышленные данные. Migrations
|
||||
и HTTP/DB-ограничения описаны в [проверке системы](verification.md).
|
||||
|
||||
## Если запуск или сценарий не работает
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Storybook 10.6.0 показывает реальные представлени
|
||||
|
||||
## Компоненты и работа с примерами
|
||||
|
||||
Каталог включает 10 групп и 41 пример:
|
||||
Каталог включает 12 групп и 50 примеров:
|
||||
|
||||
| Группа | Что показывает |
|
||||
| --- | --- |
|
||||
@@ -26,6 +26,8 @@ Storybook 10.6.0 показывает реальные представлени
|
||||
| Обновление портфеля | Сохранённые суммы при обновлении и ошибке, локальную повторную попытку |
|
||||
| Загрузка страницы счёта | Контур ожидаемых заголовка, сводки и строк |
|
||||
| Структура портфеля | Валюты и типы активов, только деньги, пустую и неполную оценку, неизвестные и отрицательные значения |
|
||||
| Сводка банковских карт | Расходы и возвраты, отрицательный месяц возврата, известные нули, загрузку, ошибку, сохранённые суммы и длинные точные итоги |
|
||||
| Поля банковской карты | Независимую рублёвую карту и недоступные финансовые поля архива |
|
||||
|
||||
Каталог не перечисляет все элементы библиотеки или приложения. Отсутствие
|
||||
представления в витрине не означает его отсутствия в продукте. Основы показывают
|
||||
|
||||
@@ -39,10 +39,22 @@ SQLite-базе завершалось `Schema engine error` до запуска
|
||||
Предыдущее описание локальной проверки от 12 сентября 2026 года также отмечало
|
||||
ошибку на временной базе без обращения к пользовательской базе.
|
||||
|
||||
Успех unit-проверок и OpenAPI не закрывает эту границу. Принятое условие пересмотра —
|
||||
Успех unit-проверок и OpenAPI не закрывает эту границу. Условие проверки —
|
||||
стабильная версия Prisma с тремя последовательными успешными применениями
|
||||
миграций на новых базах под Node 22. Условия безопасного локального запуска и
|
||||
сохранения данных — в [локальном окружении](local-workspace.md).
|
||||
миграций на новых базах под Node 22.
|
||||
|
||||
При реализации ручных карт Prisma 7.9.1 на Node 22.21.0 трижды подряд применил
|
||||
существующие migrations к новым временным базам командой
|
||||
`RUST_LOG=info DATABASE_URL=file:<новая-временная-база> npx prisma migrate deploy`
|
||||
вне sandbox. Без `RUST_LOG=info` пустой `Schema engine error` воспроизводился
|
||||
и вне sandbox. Поэтому подтверждён именно этот способ запуска; исправление
|
||||
обычного запуска или причина зависимости от журналирования не установлены.
|
||||
Он использует штатную историю migrations без `db push`, reset или ручного SQL-обхода.
|
||||
Результат исходной проверки сохранён в
|
||||
[Tasks ручных карт](../../specs/openspec/changes/add-manual-bank-cards/tasks.md).
|
||||
Применение новой миграции, DB-инварианты и HTTP-сценарии требуют своих проверок.
|
||||
Условия безопасного локального запуска и сохранения данных —
|
||||
в [локальном окружении](local-workspace.md).
|
||||
|
||||
## Где выполнять проверки
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# Ручной учёт банковских карт
|
||||
|
||||
Банковская карта — самостоятельный ручной учёт дебетовой карты в рублях.
|
||||
Пользователь задаёт название, дату начала и начальный остаток; банк и последние
|
||||
четыре цифры необязательны. Даже одинаково названные карты одного банка имеют
|
||||
разные истории и балансы. Полные номера, PIN, срок действия и код безопасности
|
||||
не запрашиваются как реквизиты этого учёта.
|
||||
|
||||
Данные принадлежат локальному пользователю. Для них достаточно сессии
|
||||
WealthLedger; подключение T-Bank не требуется. Банковские суммы не входят
|
||||
в брокерский портфель, пассивный доход или прогноз выплат, а смена подключения
|
||||
брокера не изменяет ручную историю.
|
||||
|
||||
## Откуда берётся баланс
|
||||
|
||||
Начальный остаток означает деньги до всех внесённых операций начиная с даты
|
||||
начала учёта. Баланс равен этому остатку плюс пополнения, входящие переводы
|
||||
и возвраты, минус расходы и исходящие переводы. Он учитывает всю неудалённую
|
||||
историю, независимо от выбранного месяца, страницы журнала и архива.
|
||||
|
||||
Например, остаток 1 ₽ и расходы 0,10 ₽ и 0,20 ₽ дают ровно 0,70 ₽.
|
||||
Отрицательный результат допустим: он не блокирует реальную трату или перевод.
|
||||
Это баланс по внесённым операциям, а не подтверждение остатка в банковском
|
||||
приложении. Пропущенные движения могут создавать расхождения.
|
||||
|
||||
Деньги хранятся целыми копейками и рассчитываются без преобразования в
|
||||
JavaScript Number. Отдельный ввод ограничен signed64: начальный остаток —
|
||||
от −92 233 720 368 547 758,08 ₽ до 92 233 720 368 547 758,07 ₽; сумма операции
|
||||
строго положительна и не выше верхней границы. Допускается не больше двух
|
||||
десятичных знаков, лишняя точность отклоняется без округления. Итог сложения
|
||||
может превышать границу отдельного ввода. HTTP использует общий
|
||||
[Money](../../glossary.md#money), frontend только форматирует финансовые итоги.
|
||||
|
||||
## Операции и категории
|
||||
|
||||
| Вид | Смысл и связи |
|
||||
| --- | --- |
|
||||
| Расход | Уменьшает баланс и относится к категории |
|
||||
| Пополнение | Увеличивает баланс, не входит в расходы |
|
||||
| Перевод | Одной записью уменьшает баланс источника и увеличивает баланс другой своей активной карты; не считается расходом |
|
||||
| Возврат | Связан с исходным расходом той же карты и наследует его текущую категорию |
|
||||
|
||||
Даты сохраняются как календарные дни без времени. Сегодня определяется
|
||||
в Europe/Moscow; операция допускается от начала учёта до сегодня включительно.
|
||||
Для перевода дата должна подходить обеим картам. Описание необязательно.
|
||||
|
||||
При первом добавлении карты создаются категории «Продукты», «Кафе», «Такси»,
|
||||
«Транспорт», «Жильё», «Здоровье», «Покупки», «Развлечения», «Другое».
|
||||
Категории общие для всех карт одного пользователя. Их можно добавлять и
|
||||
переименовывать; уникальность названия не зависит от регистра и внешних пробелов.
|
||||
Переименование сохраняет идентичность, поэтому история показывает новое имя.
|
||||
«Другое» сохраняет роль категории по умолчанию даже после переименования.
|
||||
Подкатегории и удаление категорий в этой версии отсутствуют.
|
||||
|
||||
Возврат может относиться к покупке любого месяца. Несколько частичных
|
||||
возвратов допустимы, если вместе не превышают текущую сумму покупки; возврат
|
||||
не может быть датирован раньше неё. При исправлении возврата его старая сумма
|
||||
заменяется новой, а не учитывается второй раз. Доступный лимит для исправления
|
||||
рассчитывает сервер, поэтому полностью возвращённую покупку можно оставить
|
||||
без изменения суммы и исправить описание.
|
||||
|
||||
## Месяц и сводка
|
||||
|
||||
Журнал и сводка карты относятся к одному выбранному месяцу. Журнал показывает
|
||||
операции по убыванию даты, затем времени создания и идентификатора; доступны
|
||||
следующие страницы. Баланс при выборе прошлого месяца остаётся текущим.
|
||||
Сводка учитывает все подходящие записи, включая не показанные на странице.
|
||||
|
||||
Сводка одной или всех карт отдельно показывает потраченное, возвращённое
|
||||
и разницу, в том числе по категориям. Возврат уменьшает расходы месяца своего
|
||||
получения: августовская покупка 1 000 ₽ и сентябрьский возврат 600 ₽ дают
|
||||
августовский итог 1 000 ₽ и сентябрьский −600 ₽ при отсутствии других трат.
|
||||
Начальный остаток, пополнения и переводы в эти показатели не входят.
|
||||
Сводка всех карт включает архивные карты независимо от фильтра списка.
|
||||
|
||||
## Исправления и архив
|
||||
|
||||
Можно исправить сумму, дату, описание и применимые связи операции. Вид записи
|
||||
и исходная покупка возврата неизменны. Обычный расход или пополнение можно
|
||||
перенести на другую активную карту; изменение или удаление перевода затрагивает
|
||||
обе стороны целиком. Исправление категории покупки перегруппировывает её
|
||||
возвраты, в том числе в других месяцах.
|
||||
|
||||
Расход с возвратами нельзя удалить, перенести, уменьшить ниже уже возвращённого
|
||||
или датировать позже возврата. Сначала исправляются мешающие возвраты.
|
||||
Изменение начала учёта проверяет всю историю, включая входящие переводы;
|
||||
изменение начального остатка не создаёт отдельной операции и не меняет траты.
|
||||
Произвольной операции «исправить баланс» нет.
|
||||
|
||||
Архив сохраняет историю при любом балансе. До возвращения карты из архива
|
||||
недоступны финансовые изменения и изменение начала учёта; описательные
|
||||
реквизиты менять можно. Для исправления перевода должны быть активны и прежние,
|
||||
и новые стороны. Безвозвратное удаление карт не предусмотрено.
|
||||
|
||||
## Сохранение и конфликты
|
||||
|
||||
Карты, операции и категории хранятся в SQLite и переживают повторный вход
|
||||
и перезапуск. Переводы и связанные изменения сохраняются транзакционно.
|
||||
Проверка владельца распространяется на каждую ссылку, включая категорию,
|
||||
обе карты перевода и покупку возврата.
|
||||
|
||||
Создание карты или операции получает постоянный идентификатор намерения.
|
||||
Повтор того же ввода после потерянного ответа возвращает текущую запись;
|
||||
изменённый ввод с тем же идентификатором получает конфликт. Проверка уже
|
||||
сохранённого намерения предшествует проверке нового лимита возврата или архива.
|
||||
Поэтому полный возврат не списывается повторно, а архивная карта не становится
|
||||
активной от запоздалого повтора создания.
|
||||
|
||||
Удалённая операция оставляет служебную отметку и fingerprint первоначального
|
||||
ввода: повтор не восстанавливает её. Это не полный журнал всех редакций.
|
||||
Исправления используют версию записи: устаревшее изменение отклоняется,
|
||||
а форма сохраняет черновик и позволяет получить актуальную запись.
|
||||
При ошибке сохранения неподтверждённые суммы не выдаются за новый баланс.
|
||||
|
||||
[Безопасное восстановление](../../development/local-workspace.md#сохранение-данных-и-откат)
|
||||
сохраняет новую финансовую историю и при откате приложения. Устройство хранения
|
||||
описано в [контейнерах](../../architecture/containers.md#хранимые-данные-и-границы-доступа).
|
||||
Согласованный контракт этой поставки находится в
|
||||
[manual-bank-cards](../../../specs/openspec/changes/add-manual-bank-cards/specs/manual-bank-cards/spec.md).
|
||||
Автоматическая загрузка банковских данных, кредитные карты, другие валюты,
|
||||
бюджеты и общий баланс банковских денег с инвестициями в эту версию не входят.
|
||||
+26
-1
@@ -7,7 +7,8 @@
|
||||
## User
|
||||
|
||||
Локальный владелец данных WealthLedger, идентифицируемый `id` и
|
||||
нормализованным email. User владеет Session и T-Bank connection и видит только
|
||||
нормализованным email. User владеет Session, T-Bank connection и своими
|
||||
ручными банковскими картами, категориями и операциями. Он видит только
|
||||
Brokerage Accounts, доступные через его текущее T-Bank connection.
|
||||
|
||||
_Не использовать_: клиент T-Bank, инвестор T-Bank.
|
||||
@@ -31,6 +32,30 @@ _Не использовать_: T-Bank сессия, browser session.
|
||||
|
||||
_Не использовать_: сумма без валюты, транспортное представление как доменный термин.
|
||||
|
||||
## Bank Card
|
||||
|
||||
Независимая дебетовая карта в RUB для [ручного учёта](domains/cards/overview.md)
|
||||
локального пользователя. Хранит начало учёта, начальный остаток и собственную
|
||||
историю; не является Brokerage Account или общим счётом нескольких карт.
|
||||
|
||||
## Bank Card Balance
|
||||
|
||||
Баланс по внесённым операциям: начальный остаток плюс пополнения, входящие
|
||||
переводы и возвраты, минус расходы и исходящие переводы. Может быть отрицательным
|
||||
и не подтверждает текущий остаток в банковском приложении.
|
||||
|
||||
## Expense Category
|
||||
|
||||
Принадлежащая пользователю категория ручных банковских расходов, общая для
|
||||
его карт. Переименование сохраняет идентичность и роль категории по умолчанию.
|
||||
Возврат использует текущую категорию своей исходной покупки.
|
||||
|
||||
## Net Card Expenses
|
||||
|
||||
Расходы выбранного месяца за вычетом возвратов, полученных в этом месяце.
|
||||
Итог может быть отрицательным; начальные остатки, переводы и пополнения
|
||||
в него не входят.
|
||||
|
||||
## T-Bank connection
|
||||
|
||||
Единственное принадлежащее User подключение к T-Bank Invest, содержащее
|
||||
|
||||
+11
-3
@@ -4,7 +4,8 @@ WealthLedger — локальное приложение для частного
|
||||
понимать свои инвестиции T-Bank: что находится на счетах, какие операции
|
||||
исполнены, сколько купонов и дивидендов получено и какие выплаты ожидаются.
|
||||
Приложение объединяет эти представления, сохраняя связь суммы с валютой,
|
||||
инструментом и брокерским счётом.
|
||||
инструментом и брокерским счётом. Отдельная область ручных банковских карт
|
||||
помогает учитывать рублёвые остатки и повседневные траты.
|
||||
|
||||
## Основные задачи пользователя
|
||||
|
||||
@@ -12,10 +13,12 @@ WealthLedger — локальное приложение для частного
|
||||
[подключает T-Bank Invest](integrations/tbank.md) в настройках. Локальная
|
||||
учётная запись WealthLedger и подключение к брокеру — разные вещи: вход
|
||||
открывает приложение, а подключение определяет доступные инвестиционные счета.
|
||||
Для ручного учёта банковских карт подключение брокера не требуется.
|
||||
|
||||
| Задача | Что показывает WealthLedger |
|
||||
| --- | --- |
|
||||
| Найти свой инвестиционный счёт | [Список счетов](domains/accounts/overview.md), их типы и доступные сводки |
|
||||
| Вести банковские карты | [Ручной учёт](domains/cards/overview.md): независимые балансы, расходы, пополнения, переводы, возвраты и месячные сводки |
|
||||
| Понять текущий состав инвестиций | [Портфель](domains/portfolio/overview.md): позиции, денежные остатки и итоги по валютам |
|
||||
| Разобрать уже совершённые движения | [Журнал операций](domains/operations/overview.md): исполненные операции с фильтрами и последовательной загрузкой истории |
|
||||
| Посчитать полученные выплаты | [Пассивный доход](domains/income/overview.md): исполненные купоны и дивиденды за календарный период |
|
||||
@@ -31,6 +34,10 @@ WealthLedger — локальное приложение для частного
|
||||
Режим «Все счета» объединяет результаты доступных счетов; отдельного
|
||||
брокерского счёта с таким именем он не создаёт.
|
||||
|
||||
Банковские карты имеют собственные операции и общий пользовательский список
|
||||
категорий. Их текущие балансы независимы; месячная сводка всех карт объединяет
|
||||
траты и возвраты, включая архив. Банковские деньги не добавляются к инвестициям.
|
||||
|
||||
Портфель отвечает на вопрос «что есть сейчас», журнал — «что исполнено»,
|
||||
аналитика дохода — «какие выплаты уже получены», будущие события — «что
|
||||
ожидается». Прогноз не подтверждает фактическое зачисление. Полученные купоны
|
||||
@@ -49,8 +56,9 @@ T-Bank поставляет личные брокерские данные и р
|
||||
|
||||
Инвестиционные возможности предназначены для чтения и анализа. Они не
|
||||
описывают размещение торговых поручений или изменение портфеля у брокера.
|
||||
Локально сохраняются учётные данные, сессии и зашифрованное подключение;
|
||||
финансовые снимки служат временными наблюдениями, а не накопленной историей
|
||||
Локально сохраняются учётные данные, сессии, зашифрованное подключение и ручная
|
||||
история банковских карт. Инвестиционные финансовые снимки служат временными
|
||||
наблюдениями, а не накопленной историей
|
||||
портфеля в собственной базе WealthLedger.
|
||||
|
||||
Данные могут зависеть от доступности поставщика и свежести последнего ответа.
|
||||
|
||||
Reference in New Issue
Block a user