Clone
2
Architecture
s.zotov edited this page 2026-04-13 12:25:01 +05:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Архитектура

Структура проекта

aspekter/
├── z51-pug-builder/              # Фронтенд + API сервер
│   ├── src/
│   │   ├── App.svelte            # Основной SPA компонент (~7000 строк)
│   │   ├── app.css               # Все стили (~3300 строк)
│   │   └── lib/
│   │       ├── api.js            # HTTP-клиент для всех API endpoints
│   │       ├── parsing.js        # Парсинг Pug: buildBaseSchema, parseQuotedArgs, etc.
│   │       ├── utils.js          # Утилиты: форматирование, ID, экранирование
│   │       └── spellcheck.js     # Интеграция Яндекс.Спеллер
│   ├── vite.config.js            # API middleware (~2300 строк): CRUD, auth, фиды, FTP, аудит
│   ├── data/                     # Данные проектов (Docker volume, persist)
│   │   ├── _system/
│   │   │   ├── users.json        # Пользователи (scrypt хэши)
│   │   │   └── logs/YYYY-MM.jsonl # Аудит-логи
│   │   ├── {project}/
│   │   │   ├── block.pug         # Исходные блоки/шаблоны
│   │   │   ├── settings.json     # Настройки: миксины, FTP, цвета, фид, extraFields
│   │   │   ├── draft.json        # Текущий черновик
│   │   │   ├── drafts/{uid}.json # Черновики per-user
│   │   │   ├── presets.json      # Сохранённые пресеты
│   │   │   ├── letters.json      # Индекс писем (общий для всех пользователей)
│   │   │   ├── letters/*.json    # Файлы писем + .history.json
│   │   │   └── notes/            # Заметки проекта
│   │   └── images/               # Локальное хранение картинок
│   ├── public/Block.pug          # Дефолтный блок для новых проектов
│   └── Dockerfile
├── email-gen/                    # Pug-шаблоны и рендерер
│   └── emails/
│       ├── includes/mixins.pug   # Общие миксины (buttonRounded, table, spacer, etc.)
│       └── {project}/
│           ├── layout/layout.pug # Layout письма (header, footer, meta)
│           ├── css/style.css     # CSS проекта (инлайнится через Juice)
│           ├── blocks/           # Блоки проекта
│           └── includes/         # Локальные миксины проекта
├── email-gen-overrides/          # Локальные override файлов email-gen (safe across git pull)
├── deploy/
│   ├── email-gen-api/
│   │   ├── server.js             # HTTP-сервер рендеринга с валидацией Pug
│   │   └── Dockerfile
│   └── nginx/
│       ├── prod.conf             # app.aspekter.ru
│       └── coins.conf            # coins.aspekter.ru
├── coin-scout/                   # Отдельный сервис подбора монет
│   ├── server.js
│   └── data/coins.db             # SQLite: price_history, coins
├── docker-compose.yml            # Базовый compose (сервисы, volumes)
├── docker-compose.dev.yml        # Dev: порт 5174, data-dev/, HMR
└── docker-compose.prod.yml       # Prod: порт 5175 на 127.0.0.1, volume mounts

Поток генерации HTML

Пользователь → собирает письмо из блоков в конструкторе
         ↓
    Pug-код собирается из block.content каждого блока
         ↓
    POST /api/project/:name/render-email → vite middleware
         ↓
    vite пересылает на email-gen-api (порт 8787)
         ↓
    email-gen-api:
      1. validatePugSafety() — проверка на инъекции
      2. Создаёт уникальный temp-файл (crypto.randomBytes)
      3. renderWithNode() — запускает email-templates
      4. Juice инлайнит CSS из style.css
      5. Возвращает HTML строку
         ↓
    vite middleware:
      1. processMindboxTags() — подставляет данные из фида для превью
      2. Возвращает HTML клиенту
         ↓
    Конструктор показывает:
      - Превью в iframe (600px)
      - HTML-код (копирование)
      - Очищенный HTML (без Mindbox-тегов)

Модули vite.config.js

Модуль Строки Описание
Auth system 155-310 Сессии, пароли, cookie, middleware
Admin endpoints 332-450 CRUD пользователей, аудит-логи
Project CRUD 470-670 Проекты, письма, заметки, пресеты
Image upload 770-850 Загрузка картинок (локальная)
Render proxy 850-870 Пересылка на email-gen-api
Link checker 870-930 Проверка ссылок в HTML
Sheets integration 930-1000 Google Sheets
Mindbox tags 1000-1100 Обработка Mindbox-переменных для превью
Feed cache 1100-1250 YML-фид: парсинг, кэш 3 часа, поиск
Auto-assemble 1250-1800 Авто-подбор товаров: фильтры, группировка, scoring
FTP/SFTP 1800-2000 Загрузка картинок + локальное хранение
Project data 2000-2300 GET/PUT данных проекта

Решения и компромиссы

Парсинг Pug на фронте (parsing.js)

Regex-парсинг вместо AST. Работает для шаблонных блоков с предсказуемой структурой. Полноценный Pug-парсер на фронте — overkill для внутреннего инструмента. Схема полей (schema) строится из content каждого блока + правил mixinRules из settings.

Один файл App.svelte (7000 строк)

Исторически сложилось. Планируется разбивка на компоненты. Не критично для работоспособности.

vite.config.js как бэкенд (2300 строк)

Vite dev server используется как application server в проде. API живёт в middleware. Для внутреннего инструмента с 5 проектами — приемлемо. Следующий шаг при масштабировании — вынос в Express/SvelteKit.

processMindboxTags — обработка Mindbox-переменных

НЕ парсер шаблонного языка. Предпросмотрщик: подставляет данные из фида для превью. В финальном HTML теги остаются as-is — Mindbox обрабатывает их при отправке. Если шаблон изменится — сломается только превью, не рассылка.

resolveProductProp — маппинг свойств

Маппит Mindbox-пропсы на поля YML-фида. Fallback product[cfMatch[1]] подхватывает новые поля автоматически. Ручное добавление нужно только для нетривиального маппинга (sohrannost → condition).