Commit Graph
48 Commits
Author SHA1 Message Date
Andrey 41a4b0dd84 ✨ feat: запуск без .env — всё настраивается в UI, и порталы по дизайну
Первичное требование: поднял докер — прошёл мастер — дальше всё в интерфейсе.
Ни одной переменной окружения задавать не нужно и негде.

Запуск и секреты:
- .env.example удалён, мёртвые переменные вычищены; секреты инстанса
  генерирует одноразовый сервис secrets в именованный том, пароли БД —
  через POSTGRES_*_PASSWORD_FILE;
- Caddy: catch-all :80 и on_demand TLS вместо хостов в конфиге — свежая
  коробка отвечает по IP и по любому домену, до мастера дойти можно;
- адрес установки, SMTP и TURN переехали в настройки (InstanceSettings,
  миграции 0027–0030), внешние ссылки строятся от него;
- deploy/cli больше не читает .env; сборка образов в ghcr через GitHub
  Actions, release.env с digest-пинами;
- куки Secure/__Host- выставляются по факту TLS запроса, а не настройкой.

Порталы (дизайн-базлайн v2, кадры PT1–PT8):
- список, карточка портала, библиотека материалов, редактор статьи и
  настройки — ширины и ритм как в остальных разделах;
- файлы статьи: изображение вставляется в текст своим механизмом, файл
  прикрепляется вложением и выводится на портале списком с иконкой формата;
- ссылки на файлы приводятся к относительным: абсолютный хост резал CSP
  портала и картинка не появлялась;
- «Опубликовать» сверяется с сервером и публикует то, что на экране, а не
  ранее выбранную редакцию;
- колонка «Оценки» в списке статей и блок оценок в редакторе.

Первый запуск: полоса «демо-данные устанавливаются» — установка идёт в
worker, и без неё человек видел пустые разделы без объяснения.

Починен фон: вторичное хранилище стало best-effort — при живых остаточных
S3-ключах повторная загрузка файла падала в 500.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:37:48 +03:00
AndreyandClaude Opus 5 3672463363 ✨ feat(ui): Агенты и Сотрудники по дизайн-базлайну v2, общий поиск и фильтр списков
Агенты (кадры G1–G5, S1): список с порядком активные → на паузе →
отключённые, цвет плитки по id агента, подключения и знания на карточке,
диалог выбора знаний, стоимость и лимиты.

Сотрудники (кадры E1–E10): список, карточка, панель создания в четыре шага,
пароль первичного доступа (показать или письмом), завершение сессий,
передача владения. Бэкенд: employee_password.py, reset-password и
revoke-sessions вместо заглушек, password_changed_at.

Общие контролы: один поиск и один фильтр-селект на всё приложение —
SearchInput с реакцией на фокус и клавишей «/», FilterDropdown на antd
Dropdown вместо нативного select; копии в контактах и списке диалогов
удалены. Ширина списков Сотрудники/Контакты/Агенты ограничена колонкой
1220px как в макете вместо растяжки на всё окно.

Тем же коммитом уходит незакоммиченная работа предыдущих сессий этого дня:
Профиль отдельной страницей, субменю Настроек, интеграции, метаданные
сессий и TOTP, объединение контактов.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 18:57:17 +03:00
AndreyandClaude Fable 5.1 a891947016 🧹 chore!: продукт без привязок к вендору — домены, почта, продукты, скоупы, события виджета
- нет зашитых доменов: help-домен по умолчанию localhost (задаёт установщик через
  CHATBALLS_HELP_BASE_DOMAIN), фронт определяет портал помощи пробой /api/v1/help/,
  ALLOWED_HOSTS без вендорских хостов, CI environment url — из CHATBALLS_APP_DOMAIN
- DEFAULT_FROM_EMAIL по умолчанию no-reply@localhost; JWT-аудитория support-токена
  chatballs.support; загрузчик виджета: window.ChatballsChat, события chatballs-chat-*
- «Контакты»: продукты берутся из данных организации ({code, name}), цвет —
  детерминированно по коду; зашитый список продуктов вендора убран
- npm-скоупы @chatballs/*, тема chatballsTheme/buildTheme
- тестовый bootstrap: организация demo, сотрудник staff.member@example.org,
  продукты site/app; фикстуры на example.com
- убрана мёртвая привязка Shell к e-mail сотрудника вендора

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 00:33:22 +03:00
AndreyandClaude Fable 5.1 99203aa561 💄 feat(ui): по макету — обои из lucide-иконок, 6 пунктов навигации, фото сотрудников, карточка контакта
- обои «Chatbolls — Lucide Pattern» (макет владельца): филлотаксис по золотому углу
  с тремя вихрями, те же 25 иконок, размеры, прозрачности и цвета двух тем
  (серо-зелёная #dedfd9/#5d635d, графитовая #25292e/#f1f2f3); на экранах входа и
  за лентой чата; лента принимает фон обоев (--surface-feed)
- верхней панели нет ни у одной роли; заголовок «Настройки» — в самой странице;
  «Знания» и «Аудит» — ссылки из «Настроек», навигация менеджера — ровно 6 пунктов
- фото сотрудников: Avatar с img, загрузка/удаление в «Настройки → Профиль»,
  в сайдбаре, подписях сообщений, поле «Ответственный», поповере охвата
- карточка контакта (решение 5): описание, компания, город; карандаш у имени —
  inline-правка имени/описания/телефона/компании/города
- цвет группы из настроек (свотчи в модалке группы) — точки в дереве, поповере,
  строках списка и меню переноса
- композер: кнопка «Эмодзи» (antd Dropdown с сеткой), как в макете
- история контакта (кадр F): тема — первая реплика клиента, «вела Анна Ким» / «AI»
- список: превью без системных событий; сообщения с одинаковым временем — по id
- демо: длительности голосовых, история Марии в архиве (в списке ровно 7 строк),
  Дмитрий ждёт 6 мин; БД: SET NULL на FK аудита/outbox к пользователю и права на
  каскад удаления — снятие демо runtime-ролью

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 20:51:14 +03:00
AndreyandClaude Fable 5.1 54f19f783e 💄 fix(ui): чат — адаптив S2/M1/M2, кадры S1 и G по дизайн-базлайну v2
- снят глобальный min-width 1024 (медиазапросы ≤768 не срабатывали); ограничение
  осталось только у страниц вне чата
- M1: мобильная шапка ☰ · «Все диалоги ▾» + «Организация · N диалогов» · аватар 32;
  ☰ открывает дерево «Диалоги» выезжающим сайдбаром (состояние поднято в Shell);
  строки 12/16, аватар 42, шрифты по макету
- M2: шапка ленты «назад · аватар 36 · имя/статус · контакт · ⋯», компактный
  композер (поле + кнопка-иконка 38 r10, плейсхолдер «Сообщение…»)
- S2: затемнение ленты при открытой панели, крестик в шапке панели, кнопка
  «Контакт» подсвечена только при открытой панели
- S1: пустой список с иконкой в круге 44; без выбранного диалога — только
  «Выберите диалог», без панели и композера
- бренд сайдбара: логотип + переключатель организации (153×32, шеврон 14);
  дерево показывает «Группы»/«Агенты» и без элементов
- G: меню полей блока «Диалог» — 283px, заголовок «Перенести в группу», галочка
  у выбранного, подпись «Диалог без группы видят все сотрудники»; все меню
  приложения по макету: 220px, пункты 33 r7, разделитель n-9, тень 0 6 20
- textarea/select наследуют шрифт (композер был моноширинным)
- backend: GET /conversations/directory/ — все группы и активные коллеги для
  оператора (сотруднику менеджерские списки закрыты, а переносить/назначать он
  может); чат грузит справочник для всех ролей

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 19:14:32 +03:00
AndreyandClaude Fable 5.1 5dcc98d594 💄 fix(ui): чат по дизайн-базлайну v2 — аудит вычисленных стилей против макета
Покадровое сравнение кадров A1/A2 и A–H макета с приложением по вычисленным
стилям (размеры, цвета, границы, радиусы, шрифты, композиция) в обеих темах.

Сайдбар: 220px на surface2, шапка «лого 28 + имя», пункты 36/10px без
акцентной полосы, бейдж очереди — жёлтая плашка, профиль с онлайн-точкой и
«роль · e-mail», меню ⋯ (уведомления переехали сюда — верхней панели в чате у
менеджера по макету нет).

Список: 323px, переключатель охвата со счётчиком на подложке n9, сортировка и
«Скрыть список», подсказка «/» в поиске, вкладки-подчёркивание, строка
диалога: канал + агент → имя · время («вчера») → превью с «↩» и непрочитанными →
таймер ожидания · группа · метки (h20, r5); активная строка — n9 без полосы.

Лента: шапка с точкой режима и строкой «статус · канал · агент · группа»,
одно действие «Взять диалог» (решение 2) и «Вернуть AI», звонки — в карточке
контакта; у входящих нет аватара и обводки (msg-in), исходящие — тинт акцента
22% / AI 16% с подписью «AI · Консультант» и «Имя · вы», разделители дней,
системные события-чипы с тоном. Первое сообщение сотрудника атомарно
перехватывает диалог (backend: ConversationMessageView → claim).

Композер: поле сверху, инструменты снизу (голосовое, «Шаблоны»), «Отправить ⏎»,
строка-предупреждение о режиме; кадры D/E — карточка с замком.

Контекст-панель 320px: карточка контакта (аватар 64, плашка канала, имя 20,
поля с копированием, «Позвонить»/«Видеозвонок»), блок «Диалог» (селекты
36px с точками/индикатором, Агент и Режим read-only, метки-чипы с
«+ Добавить», «Начат»), «Заметка» — жёлтая карточка с карандашом, «История» —
карточки с плашкой канала.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 18:22:40 +03:00
AndreyandClaude Fable 5.1 e5e51ce695 🔥 feat(ui)!: снос командного центра и «Обзора поддержки» (SPEC-HUB-0031)
По спеке навигация менеджера — шесть пунктов, командный центр удаляется.
Удалены features/command, SupportOverviewPage, роуты command/supportOverview
и бэкенд-сводка conversations/command-overview/ (conversations/command.py).
Корень «/» и дефолтный маршрут менеджера — «Чат»; устаревшие
/command и /departments/support ведут в «Чат» и на «Доску».

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 14:14:57 +03:00
AndreyandClaude Fable 5 09e9819fdd 💄 feat(ui): мобильный чат — список ↔ диалог (кадры M1/M2, S1)
На ≤768px сайдбар в чате скрыт: экран списка с шапкой бренда (логотип,
организация, меню профиля), лента открывается выбором диалога, назад —
стрелкой в шапке. Контекст — по кнопке в шапке (drawer S2 на всю ширину).
Пустой список — текст кадра S1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-05 01:27:30 +03:00
AndreyandClaude Fable 5 445e3c83c2 ✨ feat(chat)!: единый чат и оболочка сотрудника по дизайн-базлайну v2
Sales- и support-диалоги объединены в один экран «Чат» (маршрут /chat,
старые адреса — алиасы). Контекст-панель сама выбирает представление по
identity диалога. У сотрудника нет верхней панели и разделов — сайдбар
это дерево «Все диалоги · Группы · Агенты», управляющее охватом списка;
у менеджера — плоские шесть пунктов макета и группа «Ещё» для служебных
разделов. Роуты уведомлений и карточек обзора на бэкенде — chat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-05 01:17:10 +03:00
AndreyandClaude Fable 5 774eb3215a ✨ feat(agents)!: агент и канал — одна сущность (этап 3 пивота, ADR-HUB-0041 §4)
- новый агрегированный API /api/v1/agents/: мастер одного шага (имя+группа,
  код из имени), объединённый PATCH канала и AI-конфигурации, удаление с
  блокерами, активация AI, привязка/отвязка подключений, тест-чат;
- data-миграция ai/0015: DRAFT-агент каждому каналу без агента;
- UI: разделы «Каналы» и «AI-агенты» слиты в «Агенты» (список + карточка-центр
  администрирования); legacy-URL редиректят; форма интеграции выбирает агента;
- чистка: features/channels и features/ai/{list,create,detail} удалены,
  битые @import styles.css (этапы 1-2) починены — прод-сборка снова собирается;
- дизайн-базлайн v2 владельца добавлен в design/baseline/Chatbolls Baseline v2/.

Backend 582 теста OK (докер, миграции с нуля), frontend tsc + vitest 69 OK, build OK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 19:14:52 +03:00
AndreyandClaude Fable 5 446a438776 🔥 feat(platform)!: контакт-центр Chatbolls — снос домена продаж и ребрендинг
Пивот по ADR-HUB-0041/0042: продукт становится open-source контакт-центром,
домен продаж удаляется целиком, прод-данные по решению владельца не сохраняются.

Backend:
- удалены приложения sales и orders (модели, API, ingest, команды, миграции);
- из products удалены Offer/Price/MarketplacePublication и ingest_token_hash
  (products/0011); таблицы, ingress-вьюхи и служебные записи Django снимаются
  миграцией tenancy/0017_drop_commerce;
- вычищены метрики выручки и заказов из conversations (stats/clients/command),
  типы уведомлений PAYMENT_* (notifications/0007), capabilities sales.*
  (identity/0019), коммерческие блокеры каналов, ingress-роуты продаж;
- демо-сид очищен от commerce; исторические миграции tenancy/0002-0004
  вычищены от таблиц orders_*/sales_* для чистой установки, tenancy/0003
  получила явные зависимости sessions/auth/contenttypes.

Frontend (internal-ui):
- удалены разделы «Продукты», «Обзор продаж», «Заказы», реестр и карточка
  продажи, вкладка «Продажи» и статус лид/клиент в контактах, коммерция
  в командном центре; роуты, навигация и доступы приведены в соответствие.

Ребрендинг CustoCRM → Chatbolls (видимый слой): UI, письма, TOTP issuer,
тексты ботов, заголовок API, README; виджет — window.ChatbollsChat
с legacy-алиасом CustoCRMChat. Технические идентификаторы (схема БД,
роли, cookie, CUS_-переменные, домены) — отдельным шагом (ADR-HUB-0042 §5).

Тесты: internal-ui 100/100, web-chat 5/5, backend RLS-сьют 10/10.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-03 21:36:22 +03:00
Andrey 3f07d76173 ✨ feat(portals): complete custom domains and unified navigation 2026-07-29 16:49:50 +03:00
Andrey 2b246e193b ✨ feat(support): add reusable multi-portal help centers 2026-07-28 21:39:25 +03:00
Andrey 7e9667ee88 ✨ feat(ui): align channel management with design baseline 2026-07-23 11:08:16 +03:00
AndreyandClaude Opus 4.8 4c77a4e5b8 ✨ feat(ui): add the channels section
SPEC-HUB-0027 §10-§11, этап 4. Раздел «Каналы» в группе КОМПАНИЯ после
«Продукты»: список с фильтрами по отделу, карточка канала одной страницей и
мастер создания из трёх шагов. Вёрстка следует принятому design baseline
DG-02 (кадры A-E/S).

Карточка не имеет вкладок. Секции идут сверху вниз: Назначение, Политика,
Подключения, AI-агент, Счётчики. Секция агента — одна строка сводки
(имя · статус · модель) и ссылка наружу на его существующую страницу: полей
агента, знаний и их счётчиков в карточке нет, как и ссылки на саму себя.

Секция «Политика» показывает причину недоступности флага, запрещённого
инвариантом при текущем продукте. Причина выводится на клиенте из продукта и
обязательной идентичности: правила P1-P5 детерминированы, а источником прав
остаётся backend — он отклоняет запрос независимо от того, что показал
интерфейс. Флаг не игнорируется молча при сохранении.

Модалка ChannelEditForm удалена: ссылка на канал в шапке агента теперь ведёт
в карточку канала. Маршруты aiAgents, aiAgentCreate, aiAgentDetail,
aiKnowledge* и aiUsage не изменены и не редиректят — покрыто тестом.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:33:40 +03:00
Andrey 960cf24238 fix(ci): fix deploy 2026-07-19 13:41:56 +03:00
Andrey 6cfb2ec5e0 🐛 fix(ui): align knowledge layout with design baseline 2026-07-19 05:41:22 +03:00
AndreyandClaude Opus 4.8 6d36534b24 💄 feat(ui): rename nav labels, add settings page and sidebar user menu
- Rename «Командный центр» → «Обзор», «Уровень компании» → «Управление
  компанией», статус «Нормально» → «Штатно», «Открыть отдел» → «Перейти»
- Remove «Инструменты/Доска» sidebar section; enable «Настройки» nav item
- Add dropdown user menu (Профиль/Настройки/Выйти) in all sidebars
- Add /settings route and page; move password, notifications, TOTP and
  sessions out of profile, keeping only personal info on the profile page

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 22:15:02 +03:00
Andrey 9a701a354b fix(design): remove old, add new baseline 2026-07-13 07:27:18 +03:00
AndreyandClaude Opus 4.8 cb3932e3f6 ✨ feat(identity): employee roles, position and org placement (ADR-HUB-0027 этап 1)
Системные роли OWNER/ADMIN/EMPLOYEE (удалён OPERATOR), обязательная должность
position_title и основной отдел primary_department. Инварианты: владелец на уровне
компании, ровно один OWNER на организацию. Двухфазная миграция OPERATOR->EMPLOYEE
без расширения прав; операционный доступ сохранён compatibility-адаптером.
Обновлены DTO/API/формы, список и карточка сотрудника, тесты модели и инвариантов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 21:25:10 +03:00
AndreyandClaude Opus 4.8 1b93b1ee80 ✨ feat(sales): external sales tracking domain + UI (ADR-HUB-0025)
Заменяет учёт заказов Hub на учёт подтверждённых внешних продаж по
ADR-HUB-0025 / SPEC-HUB-0014. Legacy orders оставлен как есть до миграции.

Backend (новый app hub_platform.sales):
- модели Sale (проекция) / SaleEvent (append-only журнал) / SalesSource /
  AttributionToken / ExternalCustomerIdentity
- единый application service: событие сохраняется raw, проекция применяется
  идемпотентно и синхронно в транзакции (async-воркера в проекте нет)
- Product Sales API POST /api/v1/product-sales/events (Bearer на источник)
- ручная фиксация + correct/cancel/partial-refund/refund через /api/v1/sales/
- attribution token issue, аналитика gross/refund/net
- команда issue_sales_source_credential; 19 тестов

Frontend (internal-ui):
- единый реестр продаж (registry) вместо вкладок Заказы/Платежи/Исполнение
- карточка продажи (sale-detail) с append-only таймлайном событий и
  действиями OWNER; вкладка клиента Заказы -> Продажи
- роуты salesOrders/salesOrderDetail перенаправлены на новые страницы

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 09:43:32 +03:00
AndreyandClaude Fable 5 a086675283 refactor(ai): упрощение агента и знаний (ADR-HUB-0023)
Знания: плоская сущность Knowledge (заголовок, описание, MD) + файловые
вложения с оригинальными именами (retrieval из md/txt/pdf/docx, публичная
ссылка для клиента). Агент: без релизов, инструкции из трёх частей
(персонализация/тон/инструкции) + выбор знаний из библиотеки; лимит
диалогов упразднён (остался dailyCostUsd). channel.system_prompt/model
удалены — AI-поведение только на агенте. Продукт — техническая запись
без summary/sales_description. Data-миграция переносит опубликованные
документы и активные релизы в новую модель. Internal-UI: раздел Знания,
новая карточка агента, упрощённые продукты, release-страницы удалены.
ADR-0005/0007/0017 → superseded; SPEC-HUB-0012 переписан.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:08:50 +03:00
Andrey 1dc7e79612 chore(ai): упразднение тестового чата (frontend + docs)
Удалён фронтенд-only статический прототип тестового чата (features/ai/test-chat/)
и все точки его подключения: роут aiTestChat, таб поднавигации, кнопки в заголовках
AI-агента/release и таблице агентов, CSS-классы. Мёртвая ветка логики статусов релиза
(параметр tested) убрана, тексты про тест-чат заменены на нейтральные.

Baseline-прототип Тестовый чат.dc.html удалён; упразднение AI-04 зафиксировано
в SPEC-HUB-0001, SPEC-HUB-0004, SPEC-HUB-0005.
2026-07-10 13:46:43 +03:00
Andrey df6389ac75 feat(support): support dialogs inbox
SPEC-HUB-0010 §8.2: support inbox переиспользует общий ConversationWorkspace
(department=support). Оператор видит обращения, тред, composer (claim/release/
return-queue/close/send) и правую панель по контракту — без sales-сущностей.

- SupportDialogsPage: обёртка над ConversationWorkspace (department=support,
  SupportContextPanel через render-prop, заголовок «Обращения»).
- ShellRouteContent: SupportDialogsPage получает selectedConversationId.
- App.navigate: supportDialogs ставит selectedConversationId (как salesDialogs).
- Shell: isDialogsWorkspace применяет sales-dialogs scroll/page-классы и
  sales-workspace-page для support workspace (layout sidebar).
2026-07-09 16:23:20 +03:00
Andrey 1a05ae244a refactor(conversations): extract shared ConversationWorkspace
SPEC-HUB-0010 §8.2: общий conversation workspace для sales и support.

- features/conversations (shared): model (ApiConversation с опциональным contact
  + supportIdentitySnapshot, toConversationListItem, fetchConversations(department)),
  types (ConversationListItem/DialogMode/ControlMode/ListTab), data (modeDots/
  statusFor/channelMeta без mock), DialogList/ConversationThread/Composer,
  ConversationWorkspace (оркестратор, render-prop правой панели), ContextSection,
  FieldRow.
- SalesDialogsPage → тонкая обёртка над ConversationWorkspace (department=sales,
  SalesContextPanel через render-prop). Sales context-компоненты переключены на
  shared-типы.
- Удалены дубликаты sales dialogs (model/types/data/SalesDialogList/
  SalesConversation/SalesComposer/ContextSection/ContactRow) — заменены shared.
- CSS sales-* не переименовываю (design baseline, layout без изменений §8.4).
- fetchConversations теперь с department-фильтром (изоляция inbox §10).
2026-07-09 16:17:15 +03:00
Andrey 58a7e88b22 feat(ui): support department landing pages and workspace navigation
SPEC-HUB-0010 §8.1/§8.4 (этап 2 — посадочные страницы без данных).

- Маршруты supportOverview/supportDialogs (/departments/support[/dialogs]).
- SupportSidebar: навигация отдела поддержки (Обзор, Диалоги) — зеркало
  SalesSidebar, переиспользует существующие CSS-классы baseline.
- SupportOverviewPage / SupportDialogsPage: посадочные с EmptyState (без
  выдуманных данных; backend support-метрики и inbox — этап 3, design gate §8.4).
- DepartmentsPage: карточка отдела поддержки с реальными данными (memberCount,
  operatorCount, связанные продукты) — без выдуманных метрик.
- access.ts: department-scoped доступ (§10 изоляция inbox) — sales operator не
  видит support и наоборот; support operator лендингит в support dialogs.
- TopBar/Shell/ShellRouteContent/App: wiring support-маршрутов, breadcrumbs,
  выбор сайдбара по отделу оператора.
- Тесты: router (support routes) + access (department-scoped matrix).
2026-07-09 03:41:00 +03:00
AndreyandClaude Opus 4.8 5ab830b017 feat(sales): real Orders section (list + order detail with actions)
The Orders section was fully mock. Now driven by the real orders domain:
- Orders list: Заказы / Платежи / Доступ продукта tabs are built from real
  orders (dynamic counts + search); Подписки / Возвраты show honest empty
  states (no domain yet). Row opens the order by id.
- Order detail: real compact card (header, statuses, items, totals) with
  owner actions — mark paid / cancel / set fulfillment — wired to the
  orders API; replaces the mock multi-tab page.
- Selection plumbing: selectedOrderId / openOrderRoute through App → Shell.

Removed the seeded demo orders (DB clean); seed_orders command kept for
opt-in local demo. Typecheck + vitest green; verified the create→pay→detail
flow end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 22:53:16 +03:00
AndreyandClaude Opus 4.8 a91ab516a8 feat(sales): real client detail page
The client card was a single hardcoded mock. It now loads a real contact
by id and renders real data:

- Backend: conversations/clients.py client_detail() returns the contact's
  channels/products, dialog list, channel identities, lifecycle-derived
  activity, and real audit events (AuditEvent for the contact's
  conversations). Served at /api/v1/conversations/clients/<id>/.
- Routing: clients list passes the contact id; App/Shell thread
  selectedClientId through to the detail page, which fetches by id.
- UI: header/overview/dialogs/identities/audit show real data; orders and
  consent have no domain in Hub, so they render honest empty states (no
  fabricated orders, revenue, or consent log). Removed the fake
  "Согласие получено" header badge.

Backend suite 85/85; typecheck green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 21:36:21 +03:00
AndreyandClaude Opus 4.8 bc43dc3962 feat(dialogs): close/return-to-queue, search, push on new message, dynamic sidebar badge
- Operator actions completed: return-to-queue (AI->PAUSED, unassign) and close,
  wired into the composer alongside return-to-AI; dialog-list search wired.
- Push on new messages: a customer message in a non-AI dialog (operator/queue)
  emits DIALOG_NEW_MESSAGE to the assigned operator (or operators), deduped per
  message — previously only brand-new dialogs notified.
- Dynamic sidebar badge: conversations stats endpoint (open dialogs whose last
  message is from the customer = awaiting reply); Shell polls it and feeds the
  Диалоги badge in the sales sidebar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 14:20:56 +03:00
AndreyandClaude Opus 4.8 6ec999bbdd feat(notifications): deep-link to conversation + toast on new event
Clicking a dialog notification now opens that exact conversation (conversation
id threaded through navigate → Shell → dialogs page, which selects it). New
unread notifications detected during polling raise a bottom-right toast.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 14:07:44 +03:00
AndreyandClaude Opus 4.8 0f7d60d808 feat(notifications): in-app notification system + foundation
New notifications app: Notification (event, addressed to an audience: ALL/
OWNER/OPERATORS/USER) + per-user NotificationRead, so one event reaches many
recipients but read-state is personal. Service notify() with a type registry
(level + deep-link route) — adding a type is one entry. API: list (+unreadCount)
and read (ids/all). Owner sees operator-addressed events too (oversight).

First source wired: a new inbound dialog emits DIALOG_WAITING to operators
(deduped per conversation). Frontend: real bell badge in the topbar opening a
notification drawer (grouped today/earlier, level icons, unread dots, click →
navigate + mark read, 'mark all read'); Shell polls every 15s.

Verified: operator-audience event visible to operator and owner; marking read is
per-user.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:54:21 +03:00
Andrey 740e410948 ✨ feat(ai): add agent creation flow 2026-06-26 11:28:06 +03:00
Andrey 07288f595c ✨ feat(ai): add agent version setup flow 2026-06-25 21:18:59 +03:00
AndreyandClaude Opus 4.8 2b3dc300fe ✨ feat(ui): AI agent card screen (E04 slice 5b, AI-02)
- Route /ai/agents/{id} (router + App agentId plumbing, breadcrumb, "Открыть агента")
- Agent card on shared components: header + 5 tabs via UnderlineTabs
  (Обзор / Инструкции / Знания / История releases / Метрики)
- Real backend data (model, status, releases, knowledge, prompts);
  degrade missing runtime/metrics to "—" like the products screens
- Clean AI tab CSS to the project convention (gap + ::after underline),
  drop baseline-copied margin/cursor overrides on .ai-agent-tabs/.ai-subnav
- Hoist reusable formatDate into shared/utils

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 13:20:34 +03:00
AndreyandClaude Opus 4.8 5ae5de4474 💄 fix(ai): full-width subnav bar + 1:1 row actions on AI agents
- Render AiSubnav at shell level: full-width white bar under the top bar,
  with tabs constrained to page-content width (background 100%, content aligned)
- Restore AI-01 row actions 1:1 with baseline: "Test chat" button + ⋯ menu
  (Открыть агента / Создать release candidate / Остановить агента), gating unbuilt
- Remove non-baseline footer note from the agents table

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:49:18 +03:00
AndreyandClaude Opus 4.8 e5143c855c ✨ feat(ui): role-based navigation and route guards (E03)
- add role access matrix helper (auth/access) per SPEC-HUB-0004 §9
- OPERATOR lands on sales Диалоги and only sees the sales workspace sidebar
- hide "Назад в Hub" for OPERATOR; OWNER navigation unchanged
- guard owner-only routes with a 403 PermissionScreen and return action
- unit tests covering the access matrix and per-role default route

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:58:27 +03:00
AndreyandClaude Opus 4.8 5154d57610 🔨 refactor(products): extract product & commerce domain into dedicated app
- move Product out of identity into hub_platform.products app with Offer,
  versioned Price and MarketplacePublication models and migrations
- expose product CRUD/activate API and product detail UI (overview, offers/prices)
- add sales order detail UI (timeline, payments, receipts, fulfillment, subscription)
- align commerce ADRs, specs and implementation plan

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:56:15 +03:00
Andrey 6bb23016df ✨ feat(ui): add sales orders page 2026-06-18 22:16:35 +03:00
Andrey 27cce68e15 ✨ feat(ui): add sales client card 2026-06-18 22:05:11 +03:00
Andrey 8d983f844f Add sales clients page 2026-06-18 20:56:01 +03:00
Andrey 16aa068458 Refactor internal UI god components 2026-06-18 20:22:51 +03:00
Andrey 7f9cb481b2 Refactor Hub UI feature structure 2026-06-18 15:08:06 +03:00
Andrey fbef0a6dc1 Add sales department workspace route 2026-06-18 08:39:04 +03:00
Andrey c738150c96 Polish internal UI navigation chrome 2026-06-18 08:22:09 +03:00
Andrey 3f4dc16da9 Add URL routing for internal UI 2026-06-18 08:09:36 +03:00
Andrey 992f957ae0 Make profile controls functional 2026-06-18 07:52:19 +03:00
Andrey 9bb1d4db38 Make employee card actions functional 2026-06-18 07:17:21 +03:00
Andrey 9e3a6735cf Split internal UI into feature modules 2026-06-18 06:57:57 +03:00