# Flamy Trade — Frontend Публичный лендинг и дашборд ML-прогнозов для крипторынка. Построен на **SvelteKit 5** (Runes API), **Tailwind v4**, **TypeScript** и **lightweight-charts v5**. --- ## Стек | Слой | Технология | |---|---| | Фреймворк | SvelteKit 5 (runes, SSR) | | Язык | TypeScript (strict) | | Стили | Tailwind CSS v4 (Vite plugin, `@theme`) | | Графики | lightweight-charts v5 (TradingView) | | Сервер | `@sveltejs/adapter-node` (Node.js) | | Пакетный менеджер | pnpm | --- ## Быстрый старт **Требования:** Node.js ≥ 20, pnpm ≥ 9 ```bash # 1. Установить зависимости pnpm install # 2. Запустить dev-сервер pnpm dev # 3. Открыть в браузере # http://localhost:5173 ``` Остальные команды: ```bash pnpm build # Сборка для продакшена (папка build/) pnpm preview # Превью продакшен-сборки pnpm check # Svelte + TypeScript проверка типов pnpm lint # ESLint + Prettier проверка pnpm format # Автоформатирование ``` --- ## Структура проекта ``` src/ ├── lib/ │ ├── components/ │ │ ├── Chart.svelte # lightweight-charts обёртка │ │ ├── home/ │ │ │ ├── DashboardMockup.svelte # 3D-макет на главной │ │ │ └── DashboardStatus.svelte │ │ ├── layout/ │ │ │ ├── Header.svelte # Фиксированная шапка + мобильное меню │ │ │ └── Footer.svelte │ │ └── ui/ │ │ ├── Button.svelte # Универсальная кнопка/ссылка │ │ └── Logo.svelte │ ├── blog/ │ │ └── posts.ts # Статьи блога (статические данные) │ ├── stores/ │ │ └── chartStore.ts # Типы + генератор фейковых данных │ ├── utils.ts # cn() — утилита для className │ └── index.ts │ ├── routes/ │ ├── +layout.svelte # Корневой layout: Header, Footer, шрифты │ ├── +page.svelte # Главная страница (секции) │ ├── +error.svelte # Страница ошибки │ ├── (sections)/ # Секции главной страницы │ │ ├── Hero.svelte │ │ ├── Ticker.svelte │ │ ├── About.svelte │ │ ├── Features.svelte │ │ ├── Stats.svelte │ │ ├── BlogPreview.svelte │ │ └── Cta.svelte │ ├── about/ │ │ ├── +page.svelte │ │ └── _data.ts │ ├── blog/ │ │ ├── +page.svelte # Список статей │ │ └── [slug]/ │ │ ├── +page.ts # Загрузка статьи по slug │ │ └── +page.svelte # Статья │ └── dashboard/ │ └── +page.svelte # Интерактивный дашборд с графиком │ └── routes/layout.css # Tailwind @theme + глобальные стили ``` --- ## Дизайн-система ### Цвета (`layout.css`) ```css --color-primary: #fe4b07 /* Акцент — оранжевый */ --color-primary-h:#c83e06 /* Hover-состояние */ --color-bg: #09080a /* Фон страницы */ --color-bg-e: #0f0e10 /* Elevated (шапка, карточки) */ --color-bg-c: #141318 /* Card background */ --color-bg-h: #1a191e /* Hover / бордеры */ --color-title: #f0ede6 /* Основной текст */ --color-desc: #8a887f /* Вторичный текст */ ``` В Tailwind используются как `bg-primary`, `text-desc`, `border-bg-h` и т.д. ### Шрифты | Переменная | Семейство | Применение | |---|---|---| | `font-display` | Unbounded | Заголовки, кнопки, тикеры | | `font-sans` | DM Sans | Основной текст | | `font-mono` | JetBrains Mono | Цены, метки, метаданные | Подключаются через Google Fonts в `+layout.svelte`. ### Компонент `Button.svelte` ```svelte ``` Props: `href?`, `target?`, `variant?: 'primary' | 'secondary'`, `class?` --- ## Дашборд и Charts ### Архитектура данных ``` chartStore.ts → generateChartData(symbolId, timeframeId) └── возвращает ChartData ├── candles: CandleBar[] // 160 свечей ├── prediction: PredPoint[] // 19 прогнозных точек ├── signal: Signal // direction, confidence, entry/tp/sl ├── currentPrice: number └── change24h(Pct): number ``` `generateChartData` — **заглушка с детерминированными фейковыми данными**. При подключении реального бекенда её нужно заменить на API-запрос, сохранив возвращаемые типы: ```typescript // chartStore.ts — заменить эту функцию на реальный запрос: export async function fetchChartData(symbolId: string, tfId: TimeframeId): Promise { const res = await fetch(`/api/chart/${symbolId}?tf=${tfId}`); return res.json(); } ``` ### Компонент `Chart.svelte` ```svelte ``` | Prop | Тип | Описание | |---|---|---| | `data` | `ChartData` | Свечи + прогноз + сигнал | | `decimals` | `number` | Кол-во знаков после запятой для цены | | `height` | `number` | Высота canvas в пикселях (default: 520) | Что рендерится: - **CandlestickSeries** — исторические зелёные/красные свечи - **LineSeries** — пунктирная оранжевая линия ML-прогноза (19 свечей вперёд) - **PriceLine** × 3 — горизонтальные линии Entry / TP / SL с подписями на шкале - **OHLC тултип** — кастомный HTML-оверлей при наведении (показывает O/H/L/C и ML-значение) - **ResizeObserver** — автоматически подстраивает ширину и высоту при изменении окна ### Таймфреймы и символы Определены в `chartStore.ts`: ```typescript SYMBOLS // 8 монет: BTC ETH SOL BNB XRP ADA DOGE LINK TIMEFRAMES // 6 таймфреймов: 1m 5m 15m 1h 4h 1d ``` --- ## Контракт API (для бекенда) Дашборд ожидает от бекенда следующую форму ответа: ```typescript type ChartData = { candles: Array<{ time: number; // Unix timestamp (UTC seconds) open: number; high: number; low: number; close: number; }>; prediction: Array<{ time: number; // Unix timestamp будущих свечей value: number; // Прогнозная цена (mid/close) }>; signal: { direction: 'long' | 'short'; confidence: number; // 0–100 entry: number; tp: number; sl: number; }; currentPrice: number; change24h: number; change24hPct: number; }; ``` Эндпоинт (предполагаемый): ``` GET /api/chart/:symbol?tf=5m ``` --- ## Блог Статьи хранятся в `src/lib/blog/posts.ts` как статический массив `Post[]`. ```typescript type Post = { id: number; slug: string; // URL: /blog/:slug date: string; // ISO 8601 title: string; description: string; tags: string[]; content: string; // HTML-строка }; ``` Для подключения CMS — заменить `posts` на API-запрос в `+page.ts` / `+page.server.ts`. --- ## Конфигурация ### SvelteKit (`svelte.config.js`) - Адаптер: `adapter-node` (деплой как Node.js-сервер) - Runes: принудительно включены для всех файлов вне `node_modules` ### Tailwind v4 (`layout.css`) Tailwind подключается через Vite-плагин (`@tailwindcss/vite`), конфиг CSS-первый — все кастомные токены в блоке `@theme` в `src/routes/layout.css`. **Добавить новый токен:** ```css /* layout.css */ @theme { --color-accent: #your-color; } ``` После этого доступен как `bg-accent`, `text-accent` и т.д. --- ## Деплой Сборка производит Node.js-сервер: ```bash pnpm build node build/index.js ``` Переменные окружения: ``` PORT=3000 # порт (default: 3000) HOST=0.0.0.0 # хост ORIGIN=https://... # обязательно при deploy за проксей ``` Docker (минимальный `Dockerfile`): ```dockerfile FROM node:22-alpine WORKDIR /app COPY build/ ./build/ COPY package.json . RUN npm install --omit=dev --ignore-scripts CMD ["node", "build/index.js"] ``` --- ## Соглашения по коду - **Svelte 5 Runes** везде: `$state`, `$derived`, `$effect`, `$props` — никакого legacy API - **Нет `export let`** — только деструктуризация `$props()` - **Tailwind-first** — inline-стили только там, где Tailwind не справляется (динамические значения, chart dimensions) - **cn()** из `$lib/utils` для условного объединения классов - **Нет комментариев** если смысл очевиден из имён; комментарий — только для неочевидного инварианта - **SSR-safe** — всё что требует `window`/`document` — только в `onMount` - **Cleanup** — каждый `onMount` возвращает функцию очистки (removeEventListener, disconnect, remove) --- ## Известные ограничения - Данные в дашборде — **фейковые** (детерминированный генератор). Требует подключения реального API бекенда через замену `generateChartData` в `chartStore.ts` - Прогнозная линия — условная визуализация; реальная модель возвращает `prediction[]` из бекенда - Блог — статические данные в коде; для production рекомендуется CMS или headless API