Files
docs.a2v.space/public/leadera/index.html
T
2026-04-26 17:09:31 +03:00

537 lines
27 KiB
HTML
Raw Blame History

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.
<!DOCTYPE html>
<html lang="ru-ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Leadera — docs.a2v.space</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body>
<header class="site-header">
<nav class="navbar navbar-expand-lg">
<div class="container-fluid">
<a class="navbar-brand" href="../">docs.a2v.space</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarMain" aria-controls="navbarMain" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarMain">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="../diary/">Дневник</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../kb/">База знаний</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../plans/">Планы</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../leadera/">Leadera</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../guides/">Инструкции</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../creds/">Креды</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../personal-site/">Личный сайт</a>
</li>
</ul>
<form class="d-flex search-form" role="search">
<input class="form-control me-2" type="search" placeholder="Поиск..." aria-label="Search" id="search-input">
<button class="btn btn-outline-light" type="submit">Найти</button>
</form>
</div>
<button class="btn btn-outline-light d-md-none ms-2" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar" aria-expanded="false" aria-controls="sidebar">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"/>
</svg>
</button>
</div>
</nav>
<div id="search-results" class="search-results" style="display: none;">
<div class="search-results-content">
<button type="button" class="btn-close float-end" id="close-search"></button>
<h5>Результаты поиска</h5>
<ul id="results-list"></ul>
</div>
</div>
</header>
<div class="container-fluid">
<div class="row">
<aside class="col-md-3 col-lg-2 d-md-block sidebar collapse" id="sidebar">
<div class="sidebar-content">
<h6>Разделы</h6>
<ul class="nav flex-column">
<li class="nav-item"><a class="nav-link" href="../diary/">Дневник</a></li>
<li class="nav-item"><a class="nav-link" href="../kb/">База знаний</a></li>
<li class="nav-item"><a class="nav-link" href="../plans/">Планы</a></li>
<li class="nav-item"><a class="nav-link" href="../leadera/">Leadera</a></li>
<li class="nav-item"><a class="nav-link" href="../guides/">Инструкции</a></li>
<li class="nav-item"><a class="nav-link" href="../creds/">Креды</a></li>
<li class="nav-item"><a class="nav-link" href="../personal-site/">Личный сайт</a></li>
</ul>
</div>
</aside>
<main class="col-md-9 col-lg-10 main-content">
<div class="article-content">
<h1>Leadera</h1>
<h1 id="leadera">Leadera</h1>
<p>SaaS-система управления IT-ландшафтом с диаграммами Ганта.</p>
<ul>
<li><strong>Прод:</strong> <a href="https://leadera.pro">leadera.pro</a></li>
<li><strong>Дев:</strong> <a href="https://sand.a2v.space">sand.a2v.space</a></li>
</ul>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-gantt-public-access/">Leadera — Публичный доступ к диаграмме Ганта</a></h3>
<p class="card-text"><h1 id="публичный-доступ-к-диаграмме-ганта-share">Публичный доступ к диаграмме Ганта (Share)</h1>
<p><strong>Дата:</strong> 09.04.2026
<strong>Статус:</strong> Требования
<strong>Проект:</strong> Leadera</p>
<hr>
<h2 id="общее-описание">Общее описание</h2>
<p>Пользователь может создать публичную ссылку на фрагмент диаграммы Ганта, доступную для просмотра без авторизации. Открывший ссылку видит диаграмму в read-only режиме с возможностью масштабирования таймлайна, но без каких-либо элементов управления (создание, редактирование, удаление задач/секций/вех).</p>
<hr>
<h2 id="пользовательский-сценарий-создатель-ссылки">Пользовательский сценарий (создатель ссылки)</h2>
<ol>
<li>Пользователь открывает диаграмму Ганта проекта</li>
<li>Нажимает кнопку «Экспорт» / «Общий доступ»</li>
<li>Указывает диапазон дат, который должен отображаться на диаграмме</li>
<li>Система генерирует уникальную ссылку (UUID) и показывает её пользователю</li>
<li>Пользователь копирует ссылку и передаёт заинтересованным лицам</li>
</ol>
<h3 id="управление-ссылками">Управление ссылками</h3>
<ul>
<li>Вызывается через меню экспорта → модальное окно «Общий доступ»</li>
<li>В модальном окне отображается список созданных ссылок с указанием диапазона дат</li>
<li>Каждую ссылку можно <strong>удалить</strong> (полное удаление из БД, не soft delete)</li>
<li>Ссылки <strong>нельзя редактировать</strong> — только создавать и удалять</li>
<li>Ограничений на количество активных ссылок нет</li>
<li>Статистика просмотров (сколько раз открывали) — <strong>не нужна</strong></li>
</ul>
<hr>
<h2 id="пользовательский-сценарий-зритель-по-ссылке">Пользовательский сценарий (зритель по ссылке)</h2>
<ol>
<li>Зритель переходит по ссылке (без авторизации)</li>
<li>Открывается отдельная страница с диаграммой Ганта</li>
<li>Зритель видит:
<ul>
<li>Задачи и вехи, попадающие в заданный диапазон</li>
<li>Секции (заголовки группировок)</li>
<li>Таймлайн с цветовой раскраской задач</li>
</ul>
</li>
<li>Зритель может:
<ul>
<li>Масштабировать таймлайн</li>
<li>Переключать отображение «по ячейкам» / «по дням»</li>
</ul>
</li>
<li>Зритель <strong>не может</strong>:
<ul>
<li>Создавать, редактировать, удалять задачи / секции / вехи</li>
<li>Видеть любые контролы управления (кнопки создания, контекстные меню, drag-and-drop и т.д.)</li>
<li>Авторизоваться через эту страницу</li>
</ul>
</li>
</ol>
<hr>
<h2 id="данные-и-фильтрация">Данные и фильтрация</h2>
<h3 id="что-попадает-в-представление">Что попадает в представление</h3>
<p>Задачи и вехи, у которых хотя бы одно из условий верно:</p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/public-access/" class="tag">public-access</a>
<a href="../tags/sharing/" class="tag">sharing</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-gantt-excel-export/">Leadera — Экспорт диаграммы Ганта в Excel</a></h3>
<p class="card-text"><h1 id="экспорт-диаграммы-ганта-в-excel">Экспорт диаграммы Ганта в Excel</h1>
<p><strong>Дата:</strong> 09.04.2026
<strong>Статус:</strong> Требования
<strong>Проект:</strong> Leadera</p>
<hr>
<h2 id="общее-описание">Общее описание</h2>
<p>Пользователь нажимает кнопку экспорта в интерфейсе диаграммы Ганта. Система запрашивает диапазон дат выгрузки (по умолчанию — текущий видимый диапазон из интерфейса). После указания диапазона скачивается Excel-файл с визуальным представлением диаграммы Ганта.</p>
<hr>
<h2 id="вводные-данные">Вводные данные</h2>
<ul>
<li><strong>Источник:</strong> текущая диаграмма Ганта проекта (один проект = одна диаграмма)</li>
<li><strong>Диапазон дат:</strong> пользователь указывает начальную и конечную дату. По умолчанию подставляется видимый в момент запроса диапазон из интерфейса</li>
<li><strong>Масштаб таймлайна:</strong> берётся тот, который выбран пользователем в интерфейсе в момент запроса (не сохранённый в системе, а текущий). Варианты: по ячейкам или по дням</li>
</ul>
<hr>
<h2 id="структура-excel-файла">Структура Excel-файла</h2>
<h3 id="шапка-первые-строки">Шапка (первые строки)</h3>
<ul>
<li>Название диаграммы (название проекта)</li>
<li>Диапазон дат, в рамках которого сделана выгрузка</li>
</ul>
<h3 id="лист--один">Лист — один</h3>
<p>Вся диаграмма размещается на одном листе.</p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/excel/" class="tag">excel</a>
<a href="../tags/export/" class="tag">export</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-milestones/">Leadera: Вехи (Milestones) на диаграмме Ганта</a></h3>
<p class="card-text"><h2 id="бизнес-требования">Бизнес-требования</h2>
<h3 id="br-1-сущность-веха-milestone">BR-1: Сущность «Веха» (Milestone)</h3>
<p>Веха — это маркер на таймлайне диаграммы Ганта, обозначающий важную дату в проекте. В отличие от задач, веха не имеет длительности и привязана к конкретной дате.</p>
<p><strong>Поля вехи:</strong></p>
<table>
<thead>
<tr>
<th>Поле</th>
<th>Тип</th>
<th>Описание</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>UUID</td>
<td>Идентификатор</td>
</tr>
<tr>
<td>gantt_chart_id</td>
<td>UUID</td>
<td>Принадлежность к диаграмме (не к секции!)</td>
</tr>
<tr>
<td>title</td>
<td>string</td>
<td>Название вехи (обязательное, 1–255 символов)</td>
</tr>
<tr>
<td>date</td>
<td>date</td>
<td>Дата вехи (без времени, обязательная)</td>
</tr>
<tr>
<td>color</td>
<td>string</td>
<td>Цвет маркера (HEX, по умолчанию <code>#dc3545</code> — красный)</td>
</tr>
<tr>
<td>created_by</td>
<td>UUID</td>
<td>Кто создал (не отображается в UI, хранится для аудита)</td>
</tr>
<tr>
<td>updated_by</td>
<td>UUID</td>
<td>Кто обновил (не отображается в UI)</td>
</tr>
<tr>
<td>created_at</td>
<td>timestamp</td>
<td>Дата создания</td>
</tr>
<tr>
<td>updated_at</td>
<td>timestamp</td>
<td>Дата обновления</td>
</tr>
<tr>
<td>deleted_at</td>
<td>timestamp</td>
<td>Soft delete</td>
</tr>
</tbody>
</table>
<p><strong>Права доступа:</strong> Создание, редактирование и удаление вех доступно участникам с правами выше «только чтение» (аналогично задачам).</p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/angular/" class="tag">angular</a>
<a href="../tags/go/" class="tag">go</a>
<a href="../tags/api/" class="tag">api</a>
<a href="../tags/ux/" class="tag">ux</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-gantt-filters/">Leadera — Фильтры и реорганизация списка диаграмм Ганта</a></h3>
<p class="card-text"><h1 id="фильтры-и-реорганизация-списка-диаграмм-ганта">Фильтры и реорганизация списка диаграмм Ганта</h1>
<p><strong>Дата:</strong> 07.04.2026
<strong>Статус:</strong> Требования
<strong>Проект:</strong> Leadera (dev — sand.a2v.space)</p>
<hr>
<h2 id="1-постановка-задачи">1. Постановка задачи</h2>
<p>Список диаграмм Ганта должен показывать <strong>все доступные пользователю диаграммы</strong> из всех пространств (spaces), с возможностью фильтрации и поиска. Сейчас список привязан к одному пространству — нужно убрать эту зависимость и добавить удобный toolbar.</p>
<hr>
<h2 id="2-изменения-api">2. Изменения API</h2>
<h3 id="21-новый-endpoint-списка-диаграмм">2.1. Новый endpoint списка диаграмм</h3>
<p><strong>Было:</strong></p>
<pre tabindex="0"><code>GET /api/v1/spaces/{spaceId}/gantt-charts?page=1&amp;per_page=10
</code></pre><p><strong>Стало:</strong></p>
<pre tabindex="0"><code>GET /api/v1/gantt-charts?page=1&amp;per_page=10
</code></pre><p>Пользователь видит все диаграммы из <strong>всех пространств</strong>, где он является подтверждённым участником (статус <code>accepted</code>).</p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/api/" class="tag">api</a>
<a href="../tags/frontend/" class="tag">frontend</a>
<a href="../tags/requirements/" class="tag">requirements</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-websocket-gantt/">Leadera — WebSocket для диаграмм Ганта</a></h3>
<p class="card-text"><h1 id="websocket-для-диаграмм-ганта--realtime-совместное-редактирование">WebSocket для диаграмм Ганта — realtime-совместное редактирование</h1>
<p><strong>Дата:</strong> 07.04.2026
<strong>Статус:</strong> Планирование
<strong>Проект:</strong> Leadera (dev — sand.a2v.space)</p>
<hr>
<h2 id="1-постановка-задачи">1. Постановка задачи</h2>
<p>Диаграммы Ганта должны обновляться в реальном времени при совместной работе: если два или более пользователей редактируют один Гант, изменения каждого мгновенно отображаются у остальных — без перезагрузки страницы и ручного обновления.</p>
<hr>
<h2 id="2-архитектура">2. Архитектура</h2>
<pre tabindex="0"><code>Angular frontend ←── WebSocket ──→ Go backend (Hub) ──→ PostgreSQL
│ │
│ HTTP (мутации) │ Broadcast
└──→ REST API ──→ Service ──→ DB ──→ Hub ──→ все клиенты комнаты
</code></pre><p><strong>Ключевой принцип:</strong> мутации данных идут через HTTP (REST), WebSocket используется <strong>только для доставки уведомлений</strong>. Сервер — источник истины, клиент не может обойти проверки через WS.</p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/websocket/" class="tag">websocket</a>
<a href="../tags/realtime/" class="tag">realtime</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/architecture/" class="tag">architecture</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-section-constraints/">Leadera: Ограничения секций в диаграмме Ганта</a></h3>
<p class="card-text"><h2 id="бизнес-требования">Бизнес-требования</h2>
<h3 id="br-1-лимит-одновременных-задач-concurrency-limit">BR-1: Лимит одновременных задач (Concurrency Limit)</h3>
<p>У каждой секции появляется параметр <strong>max_concurrent_tasks</strong> (целое число ≥ 0, по умолчанию 0).</p>
<p><strong>Поведение:</strong></p>
<ul>
<li>Если <code>max_concurrent_tasks = 3</code> — в любой данный день в этой секции не может быть больше 3 активных задач одновременно</li>
<li>Если <code>max_concurrent_tasks = 0</code> — ограничение отключено, лимита нет</li>
<li>Пересечение считается по дате: задача занимает дни с <code>start_date</code> по <code>end_date</code> включительно. Две задачи «пересекаются», если у них есть хотя бы один общий день</li>
<li>Ограничение работает <strong>только в рамках одной секции</strong>. Задачи из разных секций не влияют друг на друга</li>
</ul>
<p><strong>Срабатывание при:</strong></p></p>
<div class="tags">
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/gantt/" class="tag">gantt</a>
<a href="../tags/angular/" class="tag">angular</a>
<a href="../tags/go/" class="tag">go</a>
<a href="../tags/api/" class="tag">api</a>
<a href="../tags/ux/" class="tag">ux</a>
</div>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body">
<h3 class="card-title"><a href="../leadera/leadera-audit/">Аудит Leadera — полный отчёт</a></h3>
<p class="card-text"><h1 id="аудит-проекта-leadera">Аудит проекта Leadera</h1>
<p><strong>Дата:</strong> 30.03.2026<br>
<strong>Версия:</strong> pre-production, миграции 15</p>
<hr>
<h2 id="1-обзор-проекта">1. Обзор проекта</h2>
<p>Leadera — SaaS-система управления IT-ландшафтом с диаграммами Ганта.</p>
<h3 id="стек">Стек</h3>
<table>
<thead>
<tr>
<th>Компонент</th>
<th>Технологии</th>
</tr>
</thead>
<tbody>
<tr>
<td>Backend</td>
<td>Go 1.21+, Gin, PostgreSQL 16, pgx/v5 + sqlx, JWT (HMAC-SHA256)</td>
</tr>
<tr>
<td>Frontend</td>
<td>Angular 21.1, Bootstrap 5, NgBootstrap, RxJS, Signals</td>
</tr>
<tr>
<td>Инфраструктура</td>
<td>Docker (Colima), pm2, nginx reverse proxy, VPS reg.ru</td>
</tr>
</tbody>
</table>
<h3 id="доменная-модель">Доменная модель</h3>
<pre tabindex="0"><code>User ──┬── Space (через space_members с role)
└── GanttChart (принадлежит Space)
├── GanttSection
└── GanttTask
</code></pre><p><strong>Роли:</strong> admin, editor, viewer — назначаются <strong>на уровне Space</strong> через таблицу <code>space_members</code>.</p></p>
<div class="tags">
<a href="../tags/audit/" class="tag">audit</a>
<a href="../tags/leadera/" class="tag">leadera</a>
<a href="../tags/security/" class="tag">security</a>
<a href="../tags/architecture/" class="tag">architecture</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<footer class="site-footer">
<div class="container">
<p class="text-center mb-0">&copy; 2026 docs.a2v.space</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.0.0/dist/fuse.min.js"></script>
<script src="../js/search.js"></script>
<script src="../js/creds.js"></script>
</body>
</html>