# Dashboard Generation Guide — Self-Learning Instruction
**Version:** 1.0.0  
**Created:** 2026-02-17  
**Last Updated:** 2026-02-17  
**Author:** AI Agent (self-learning from 4 dashboard generation attempts)

---

## Обзор

Инструкция по программатическому созданию дашбордов через INSERT в PostgreSQL таблицы:
- `app_card_configurations` — KPI карточки
- `app_chart_configurations` — графики
- `app_dashboard_configurations` — страницы (layout + виджеты)
- `app_permissions` — права доступа

---

## ⚠️ КРИТИЧЕСКИЕ ПРАВИЛА (выучено на ошибках)

### 1. ВСЕГДА убирай внутренний title графика
```json
"title": ""
```
Если `title` не пустой — он дублируется с заголовком виджета на странице. Это была ошибка №1 на ВСЕХ страницах.

### 2. ВСЕГДА выдавай права после создания dashboard
```sql
INSERT INTO app_permissions (role, resource_key, access_level) VALUES
('admin', 'tab:НазваниеТаба', 'view'),
('admin', 'dashboard:<ID>', 'view')
ON CONFLICT (role, resource_key) DO NOTHING;
```
Без прав — редирект на первый доступный таб. Ошибка на Нейро v2.

### 3. showLabels: false для графиков с множеством категорий
Если xAxisColumn имеет >7-8 уникальных значений — ОБЯЗАТЕЛЬНО `"showLabels": false`. Иначе подписи налезают друг на друга. Tooltip достаточно.

Критичные случаи:
- Bar chart по ЖК (18 значений) — labels нечитаемы
- Bar chart по этажам (24 значения) — labels мелкие
- Bar chart по микрорайонам — полная каша

### 4. Не смешивай KPI и charts в одной строке
В dashboard layout одна строка = только `type: "kpi"` ИЛИ только `type: "chart"`. Микс ломает вёрстку.

### 5. Форматирование чисел — платформа использует compact format
- `compactNumbers: true` в карточках — включает сокращения (1.43В, 6.88M)
- Проблема: "В" вместо "млрд", "M" вместо "млн" — это системное, не фиксится через конфиг
- Для осей графиков форматирование захардкожено — англоязычные запятые (100,000,000)
- **TODO:** Нужен fix в коде для русской локали

### 6. Фильтры с dataColumn "Расторгнуто (Да/Нет)" — name должно совпадать с COMMENT
Название колонки в фильтрах и dataSettings ДОЛЖНО точно совпадать с `COMMENT ON COLUMN`:
- ✅ `"Расторгнуто (Да/Нет)"`
- ❌ `"rastorgnuto"`

---

## 📐 Layout: Проверенные сетки

### Хорошо работает:
| Layout | Назначение | Пример |
|--------|-----------|--------|
| `1-col` filters | Фильтры на всю ширину | Всегда первая строка |
| `4-col` KPI | 4 простых карточки в ряд | Базовые метрики |
| `3-col` KPI | 3 сложных карточки | Финансы / Площади / Сделки |
| `2-col` charts | Два графика рядом | Bar + Treemap |
| `1-col` chart | Один широкий график | Line тренд, 3D |

### Проблемные:
| Layout | Проблема |
|--------|----------|
| `3-col` charts | Графики слишком сжаты, подписи нечитаемы |
| `2-col` с treemap | Treemap в половину ширины — текст обрезается |
| `2-col` с sunburst | Sunburst мелкий, без подписей бесполезен |

### Рекомендация по структуре страницы:
```
1. Фильтры (1-col)
2. KPI карточки (3-col или 4-col)  
3. Графики парами (2-col) — bar + bar или bar + pie
4. Широкий график (1-col) — line тренд или 3D
5. НЕ более 5-6 строк — иначе слишком длинный скролл
```

---

## 🎨 Карточки KPI

### Простая карточка (value + title + sparkline)
```json
{
  "elements": [
    {"type": "value", "style": {"top": 15, "left": 25, "fontSize": 38, "fontWeight": "bold", "color": "#E8F5E9"}, "dataSettings": {...}},
    {"type": "title", "style": {"top": 65, "left": 25, "fontSize": 14, "color": "rgba(255,255,255,0.5)"}},
    {"type": "chart", "chartType": "area", "style": {"top": 90, "left": 15, "width": 320, "height": 95, "opacity": 0.5, "color": "#81C784"}, "dataSettings": {"dataLimit": 30, "groupByColumn": "Дата продажи", "treatDateAsUpperBound": true}}
  ],
  "gradientFrom": "#2E7D32", "gradientTo": "#1B5E20",
  "showIcon": false, "compactNumbers": true
}
```

### Сложная карточка (containers с text + value парами)
```json
{
  "width": "500px", "height": "400px",
  "elements": [
    {"type": "text", "content": "Заголовок", "style": {"top": 12, "left": 20, "fontSize": 22, "color": "#E0E0E0"}},
    {"type": "container", "style": {"top": 55, "left": 15, "width": 470, "height": 45, "display": "flex", "alignItems": "flex-end"},
     "children": [
       {"type": "text", "content": "Метка", "style": {"width": 240, "fontSize": 16, "color": "rgba(255,255,255,0.5)"}},
       {"type": "value", "style": {"width": 220, "fontSize": 28, "textAlign": "right", "fontWeight": "900", "color": "#4CAF50"}, "dataSettings": {...}}
     ]
    }
    // Повторять container каждые 45px по top
  ],
  "gradientFrom": "#16213E", "gradientTo": "#1A1A2E"
}
```

**Правило container spacing:** каждый следующий container = предыдущий top + 45px

### Выученные ошибки по карточкам:
- ❌ `"filters"` в карточке расторжений показывал ВСЕ записи (208=208) — фильтр должен быть в `dataSettings` каждого value, а НЕ на уровне карточки
- ❌ Карточки без sparkline в одном ряду с карточками с sparkline — визуальное несоответствие
- ✅ Единый стиль gradient для ряда — тёмные оттенки, не кислотные

---

## 📊 Графики

### Проверенные типы:
| Тип | Когда использовать | showLabels | Примечание |
|-----|-------------------|------------|------------|
| `bar` | Сравнение категорий (<8) | true | Без segment если >5 категорий |
| `bar` + segment | Stacked/grouped | false | Max 3-4 segment значения |
| `line` | Временные тренды | false | С segmentColumn по городам |
| `treemap` | Иерархия (2-3 уровня) | true | Только в 1-col! В 2-col текст обрезается |
| `sunburst` | Иерархия + info panel | true | Только в 1-col! С infoPanelEnabled=true |
| `bar3d` | Презентация | false | В 1-col, height: "700"+ |
| `pie` | Доля от целого (<6 сегментов) | — | Только внутри карточки |

### Info Panel для sunburst/treemap:
```json
{
  "infoPanelEnabled": true,
  "infoPanelPosition": "right",
  "infoPanelMaxWidth": 300,
  "infoPanelSplit": 40,
  "infoPanelItems": [
    {"type": "field", "column": "id", "aggregation": "count", "label": "Кол-во"},
    {"type": "divider"},
    {"type": "field", "column": "Стоимость квартиры, ₽", "aggregation": "sum", "label": "Выручка"},
    {"type": "variable", "label": "Среднее на ЖК", "vars": [
      {"name": "total", "column": "Стоимость квартиры, ₽", "aggregation": "sum"},
      {"name": "gk", "column": "ЖК", "aggregation": "uniqueCount"}
    ], "formula": "{total}/{gk}"}
  ]
}
```

### Доступные aggregation:
`count`, `sum`, `average`, `min`, `max`, `uniqueCount`

---

## 🎨 Цветовая палитра

### Рекомендация — единая палитра градиентов для карточек:
| Тема | gradientFrom | gradientTo | Accent |
|------|-------------|-----------|--------|
| Зелёный (выручка) | #2E7D32 | #1B5E20 | #81C784 |
| Синий (количество) | #1565C0 | #0D47A1 | #64B5F6 |
| Фиолетовый (цена) | #7B1FA2 | #4A148C | #CE93D8 |
| Оранжевый (средний) | #E65100 | #BF360C | #FFB74D |
| Красный (расторжения) | #C62828 | #B71C1C | #EF5350 |
| Тёмный (сложная карточка) | #16213E | #1A1A2E | — |

### Цвета текста:
- Заголовок карточки: `#E0E0E0`
- Метки: `rgba(255,255,255,0.5)`
- Значения: акцентный цвет темы
- Title в графике: `""` (пустой!)

---

## ✅ Чеклист перед созданием дашборда

- [ ] Все chart configurations имеют `"title": ""`
- [ ] showLabels: false для графиков с >7 категориями по X
- [ ] Каждая строка — однородная (только KPI или только charts)
- [ ] Права выданы для admin роли (tab + dashboard)
- [ ] Фильтры карточек в `dataSettings`, не на уровне карточки
- [ ] Treemap и sunburst — только в `1-col` layout
- [ ] Не более 6 строк на странице
- [ ] Скриншот + визуальная проверка после создания
- [ ] Нет дублирования заголовков

---

## 🐛 Известные ограничения платформы

1. **compactNumbers** использует латинские суффиксы (M, B вместо млн, млрд)
2. **Оси графиков** форматируют числа с запятыми (англ. формат)
3. **Puppeteer** может не рендерить тяжёлые страницы (3D, sunburst с panel) — нужно увеличивать timeout
4. **Токен** протухает — перед скриншотом всегда получать свежий
5. **Пустое пространство внизу** — системная проблема, графики не заполняют viewport

---

## 📈 Метрики прогресса

| Версия | Оценка UX | Основные проблемы |
|--------|----------|-------------------|
| Нейротест | 3/10 | Дубли заголовков, нечитаемые labels, пустота |
| Нейро v2 | 4/10 | Дубли (частично фикс), sunburst бесполезен |
| Нейро v3 | 3.5/10 | Все 208=баг данных, дубли, хаос цветов |
| Нейро v4 | ?/10 | Не отрендерился в Puppeteer |
