Skip to content

Техническая архитектура сервиса портфолио

Общее описание

Сервис портфолио — клиентский модуль приложения Pirate Place для отслеживания криптовалютных инвестиций. Ключевая особенность — работа без авторизации: все данные хранятся в localStorage браузера. Рыночные данные поступают с бекенда через REST API и WebSocket (Centrifuge).

Стек технологий

  • Vue.js 2.7 + Nuxt.js 2.17 — фреймворк
  • Vuex — управление состоянием (модули transactions, assetsColors)
  • vee-validate 2.2 — валидация форм
  • amCharts 4 / eCharts 5.6 — графики
  • CryptoJS — шифрование экспорта
  • file-saver — скачивание файлов
  • localStorage — персистентное хранилище

Структура модуля

app/landings/portfolio/
├── pages/                     # Маршруты
│   ├── portfolio.vue          # Layout-обёртка
│   ├── portfolio/index.vue    # Главная страница
│   └── portfolio/_overview.vue # Внутренняя страница монеты
├── modules/                   # 22 UI-модуля
│   ├── assetsTable/           # Таблица активов
│   ├── transactionsTable/     # Таблица транзакций
│   ├── transactionsChart/     # График транзакций
│   ├── portfolioChart/        # График портфолио
│   ├── holdingsChart/         # Круговая диаграмма холдингов
│   ├── holdingWidget/         # Виджет холдинга
│   ├── gainLossCards/         # Карточки прибыли/убытка
│   ├── portfolioHeader/       # Шапка портфолио
│   ├── coinHeader/            # Шапка монеты (внутренняя страница)
│   ├── infoShortGeneral/      # Карточки показателей
│   ├── portfolioHoldings/     # Блок распределения холдингов
│   ├── portfolioPoster/       # Постер (пустое состояние)
│   ├── fomoAssetsPopup/       # FOMO-оповещения
│   ├── importTransactionsPopup/ # Импорт транзакций
│   ├── exportTransactionsPopup/ # Экспорт транзакций
│   ├── deleteAssetPopup/      # Удаление одного актива
│   ├── deleteAssetsPopup/     # Удаление всех активов
│   ├── viewTransactionPopup/  # Просмотр транзакции
│   ├── coinWithPortfolioButton/ # Кнопка на странице монеты
│   └── featuresController/    # Управление feature-флагами
├── components/                # Компоненты
│   ├── ui/                    # UI-элементы
│   ├── transaction/           # Компоненты транзакций
│   ├── sections/              # Импорт/экспорт секции
│   ├── toasts/                # Уведомления
│   └── popups/AssetPopups/    # Попапы создания/редактирования
│       ├── AddAssetPopup.vue
│       ├── EditTransactionPopup.vue
│       ├── AddAssetFormsPopup.vue
│       └── forms/
│           ├── AddTransactionForm.vue
│           └── AddAssetTransferForm.vue
├── tools/                     # Бизнес-логика
│   ├── transactions/
│   │   ├── transaction/
│   │   │   ├── BaseTransaction.js
│   │   │   ├── BuySellTransaction.js
│   │   │   ├── OtherTransaction.js
│   │   │   ├── transactionBuy.js
│   │   │   ├── transactionSell.js
│   │   │   ├── transactionMining.js
│   │   │   ├── transactionTransferIn.js
│   │   │   ├── transactionTransferOut.js
│   │   │   └── transactionAggregator.js
│   │   ├── transactionLink.js
│   │   ├── transactionMath.js
│   │   ├── transactionAssets.js
│   │   ├── transactionType.js
│   │   ├── utils.js
│   │   └── validation/
│   │       ├── validationTransaction.js
│   │       └── validationRules.js
│   └── helpers.js
├── mixins/                    # Миксины с логикой
│   ├── transactions/
│   │   ├── index.js           # Главный миксин: CRUD, импорт/экспорт
│   │   └── transactionData.js
│   ├── transactionPeriod.js
│   ├── filteredCoins.js
│   ├── portfolioFile.js       # Шифрование/дешифрование файлов
│   ├── hideData.js            # Скрытие данных
│   ├── assetDataAdapter.js
│   ├── featuresManagement.js
│   └── onboardingPortfolioPopup.js
├── store/                     # Vuex-модули
│   ├── transactions.js        # Состояние транзакций и ассетов
│   └── assetsColors.js        # Цвета для графиков
├── services/
│   └── assetsColorsHelpers.js
├── subdomains/
│   └── notes/                 # Независимые заметки
│       ├── modules/noteCard/, notePopup/, userNotes/
│       ├── store/notes.js
│       ├── tools/notes/
│       └── mixins/notes.js
└── ui/
    └── UiDataRow.vue

Диаграмма архитектуры

mermaid
graph TB
    subgraph "Клиент (Браузер)"
        UI["Vue-компоненты<br/>Страницы портфолио"]
        Store["Vuex Store<br/>transactions / assetsColors / notes"]
        Tools["Tools Layer<br/>TransactionMath, TransactionAssets,<br/>TransactionAggregator, Validation"]
        Mixins["Mixins Layer<br/>transactions, portfolioFile,<br/>hideData, filteredCoins"]
        LS["localStorage<br/>transactions / notes"]
    end

    subgraph "Бекенд"
        API["REST API<br/>Данные о криптовалютах"]
        WS["WebSocket (Centrifuge)<br/>Обновления цен"]
    end

    UI -->|"dispatch/commit"| Store
    Store -->|"getters"| UI
    Mixins -->|"методы"| UI
    Mixins -->|"actions/mutations"| Store
    Store -->|"расчёты"| Tools
    Tools -->|"результат"| Store
    Store <-->|"чтение/запись"| LS
    API -->|"цены, графики"| Store
    WS -->|"real-time"| Store

Потоки данных

mermaid
flowchart LR
    LS["localStorage"] -->|"JSON.parse"| Vuex["Vuex Store"]
    Vuex -->|"JSON.stringify"| LS
    Backend["Backend API"] -->|"цены монет"| Vuex
    Vuex -->|"TransactionAssets"| Calc["Расчёт ассетов"]
    Calc -->|"setAssetData"| Vuex
    Vuex -->|"getters"| Pages["Страницы"]
    User["Пользователь"] -->|"формы"| Pages
    Pages -->|"handlers"| Vuex