Table of Contents
Архитектура
Структура проекта
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).