# Техническое задание
## Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н. Оленевой
### `oclinica-brandbook`

---

**Версия:** 1.0-draft
**Дата:** 2026-03-22
**Статус:** На согласовании

---

## Содержание

1. [Общие сведения](#1-общие-сведения)
2. [Назначение и цели](#2-назначение-и-цели)
3. [Пользователи системы](#3-пользователи-системы)
4. [Границы системы](#4-границы-системы)
5. [Функциональные требования](#5-функциональные-требования)
6. [Требования к интеграциям](#6-требования-к-интеграциям)
7. [Требования к данным](#7-требования-к-данным)
8. [Нефункциональные требования](#8-нефункциональные-требования)
9. [Технический стек](#9-технический-стек)
10. [Архитектура системы](#10-архитектура-системы)
11. [Безопасность и авторизация](#11-безопасность-и-авторизация)
12. [Требования к окружению](#12-требования-к-окружению)
13. [Ограничения и допущения](#13-ограничения-и-допущения)
14. [Открытые вопросы](#14-открытые-вопросы)

---

## 1. Общие сведения

| Параметр               | Значение                                                              |
|------------------------|-----------------------------------------------------------------------|
| Полное название        | Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н. Оленевой   |
| Краткое название       | oclinica-brandbook                                                    |
| Сайт клиники           | https://oclinica.ru                                                   |
| Тип системы            | Веб-приложение (Living Styleguide)                                    |
| Режим работы           | Локальная разработка + Vercel (preview + production)                 |
| Аудитория              | Внутренние дизайнеры клиники, внешние подрядчики                     |
| Хостинг (фронтенд)     | Vercel Hobby (бесплатно) — https://web-oclinica.vercel.app           |
| Хостинг (бэкенд + БД)  | TBD — уточняется при переходе к Sprint 11 (экспериментальная секция) |

---

## 2. Назначение и цели

### 2.1 Назначение

`oclinica-brandbook` — интерактивное веб-приложение, которое служит единым источником правды о визуальном языке клиники. Оно содержит все UI-компоненты, блоки страниц и полные страницы сайта в живом виде — с кодом, документацией и реальными данными.

Дополнительно система позволяет дизайнерам создавать экспериментальные компоненты и страницы непосредственно в интерфейсе брендбука, сохранять их в базе данных и переводить в статус «утверждено».

### 2.2 Цели

| № | Цель                                                                                   |
|---|----------------------------------------------------------------------------------------|
| 1 | Обеспечить единый визуальный стандарт для всех, кто работает над сайтом               |
| 2 | Ускорить работу дизайнеров и разработчиков за счёт готовых компонентов с кодом        |
| 3 | Дать возможность безопасно экспериментировать с новыми компонентами без риска для сайта|
| 4 | Показывать компоненты с реальными данными (врачи, новости, цены) с сайта клиники      |
| 5 | Создать живой инструмент, который обновляется вместе с сайтом                         |

---

## 3. Пользователи системы

### 3.1 Роли

Система поддерживает две роли пользователей:

#### Роль: `viewer` (Наблюдатель)

Предназначена для внешних подрядчиков и всех, кому нужно ознакомиться с брендбуком.

**Доступные действия:**
- Просмотр всех разделов брендбука (цвета, типографика, компоненты, блоки, страницы)
- Просмотр кода компонентов (HTML/CSS)
- Копирование кода компонента в буфер обмена
- Просмотр экспериментальных компонентов со статусом `approved`
- Скачивание дизайн-токенов (JSON)

**Недоступные действия:**
- Создание / редактирование / удаление компонентов
- Изменение статуса компонентов
- Управление пользователями

---

#### Роль: `editor` (Редактор)

Предназначена для внутренних дизайнеров клиники.

**Доступные действия** (всё из `viewer`, плюс):
- Создание экспериментального компонента методом дублирования существующего
- Редактирование атрибутов компонента через интерактивную форму
- Сохранение компонента в БД со статусом `draft`
- Смена статуса компонента: `draft` → `review` → `approved`
- Удаление компонента со статусом `draft`
- Просмотр всех экспериментальных компонентов (включая `draft` и `review`)

**Недоступные действия:**
- Управление пользователями (добавление / удаление аккаунтов)
- Прямое редактирование базового кода компонентов (только через форму атрибутов)

---

### 3.2 Управление пользователями

- Создание и удаление пользователей выполняется администратором системы вручную (через API или seed-скрипт) — в рамках v1.0 административный UI не предусмотрен.
- Пользователи хранятся в БД с хешированным паролем (bcrypt).

---

## 4. Границы системы

### Что входит в систему

- Фронтенд брендбука (Next.js) — визуальная документация всех компонентов
- Бэкенд API (NestJS) — управление экспериментальными компонентами, авторизация
- База данных (PostgreSQL + Prisma) — хранение пользователей и экспериментальных данных
- Интеграция с API сайта oclinica.ru — получение реальных данных для отображения в компонентах

### Что не входит в систему (v1.0)

- Административный UI для управления пользователями
- Drag-and-drop конструктор страниц
- История версий компонентов
- Тёмная тема
- Экспорт в Figma
- CMS-функции (редактирование контента самого сайта oclinica.ru)

---

## 5. Функциональные требования

### 5.1 Навигация и структура брендбука

**ФТ-01.** Брендбук имеет постоянную левую (или верхнюю) навигацию с разделами:
- Фундамент → Логотип, Цвета, Типографика, Иконография
- Компоненты → Кнопки, Форм-контролы, Карточки, Бейджи, Алерты, Модальные окна, Таблицы, Навигация
- Блоки → Hero, CEO-текст, Наши врачи, Отзывы, Новости, Формы контакта, Контакт, Услуги
- Страницы → Главная, Заболевание, Все врачи, Врач, Цены, Контакты
- Оффлайн элементы → Форма сотрудников, Бейджи, Внутренняя навигация, Транспорт, Печать
- Эксперименты

**ФТ-02.** Навигация поддерживает прямые URL для каждого раздела (deep linking).

**ФТ-03.** На каждой странице раздела отображается:
- Живой пример компонента/блока
- Все варианты (размеры, состояния, цветовые схемы)
- HTML-код компонента с кнопкой «Скопировать»
- Краткое описание и правила применения

**ФТ-03-LLM.** На каждой странице брендбука, содержащей дизайн-стандарты (цвета, типографика,
компоненты, блоки, страницы), должен присутствовать **LLM-блок** — свёрнутая или отдельная
секция с машиночитаемым описанием стандарта для использования языковыми моделями при
разработке дизайна, макетов, сайта и приложений. LLM-блок содержит:
- Все токены и значения в табличном формате
- Правила применения в формате «разрешено / запрещено»
- Взаимосвязи с другими стандартами (ссылки на разделы)
- Примеры корректного и некорректного использования

Сводный LLM-контекст всего брендбука хранится в файле: **`docs/LLM_CONTEXT.md`**

---

### 5.2 Раздел «Цвета»

**ФТ-10.** Отображаются все цвета палитры: плашка цвета, название, HEX, RGB, HSL.

**ФТ-11.** Клик на цвет — копирует HEX в буфер.

**ФТ-12.** Для каждой пары цветов (текст / фон) отображается коэффициент контрастности и метка WCAG AA / AAA / Fail.

**ФТ-13.** Кнопка «Скачать токены» — выгружает все цвета в JSON-формате, совместимом с Figma Tokens.

---

### 5.3 Раздел «Логотип»

**ФТ-15.** Страница «Логотип» присутствует в брендбуке с Sprint 1 — с PNG-версией из PDF и полным описанием правил (вектор добавляется позже).

**ФТ-16.** На странице отображаются:
- Обе версии логотипа: «Общий» (сеть) и «Основной» (направление)
- Иерархия и область применения каждой версии
- Цветовые варианты: основной, инвертированный (на тёмном фоне), на форме (коричневый / белый)
- Охранная зона с визуализацией отступов
- Минимальные размеры для печати (70×25,5 мм и 90×32,8 мм)
- Запрещённые варианты использования

**ФТ-17.** После получения вектора — кнопки скачивания файлов (SVG, PNG с прозрачным фоном).

---

### 5.4 Раздел «Типографика»

**ФТ-20.** Отображаются оба фирменных шрифта:
- **DINPro** — шрифт бренда (оффлайн, логотип, носители)
- **Fira Sans** (веса 300, 400) — веб-шрифт сайта

**ФТ-21.** Для каждого шрифта отображается полная шкала стилей: h1–h6, body-large, body, body-small, caption, label, overline с параметрами: font-family, font-weight, font-size, line-height, letter-spacing.

**ФТ-22.** Чётко указано, где применяется каждый шрифт: DINPro — оффлайн и носители, Fira Sans — сайт и digital-коммуникации.

---

### 5.5 Компоненты — общие требования

**ФТ-30.** Каждый компонент отображается со всеми своими вариантами и состояниями одновременно на одной странице.

**ФТ-31.** Под каждым вариантом показан HTML-код с кнопкой «Скопировать».

**ФТ-32.** Состояния интерактивных компонентов (hover, focus, disabled) доступны живым взаимодействием — не скриншотами.

---

### 5.6 Страницы

**ФТ-40.** Каждая страница брендбука показывает полноразмерный макет, собранный из утверждённых блоков.

**ФТ-41.** Страницы отображаются с реальными данными, полученными через API oclinica.ru (врачи, новости, услуги, цены).

**ФТ-42.** В брендбуке доступен переключатель «Desktop / Tablet / Mobile» для предпросмотра адаптивности.

---

### 5.7 Раздел «Оффлайн элементы»

> Раздел является справочным — содержит только изображения носителей и правила применения без интерактивных компонентов. Доступен обеим ролям (viewer и editor).

**ФТ-43.** Раздел «Оффлайн элементы» содержит подразделы:
- Форма сотрудников
- Бейджи
- Внутренняя навигация
- Брендирование транспорта
- Печатные материалы

**ФТ-44.** Каждый подраздел содержит:
- Изображение носителя (фото или макет)
- Технические параметры: размеры, цвета (коды Oracal/Pantone и их HEX-эквиваленты), шрифт, отступы
- Текстовые правила применения

**ФТ-45.** Для носителей, использующих цвета бренда, отображаются плашки цветов со ссылкой на соответствующий токен из раздела «Цвета».

**ФТ-46.** Страница «Форма сотрудников» содержит:
- Бежевый вариант: коричневый логотип, левая сторона груди, размеры по таблице размеров (до 46: 70×25,5 мм; от 48: 90×32,8 мм)
- Синий вариант: белый логотип, левая сторона груди
- Цветовые коды: 080M (коричневый) / 010 (белый)

**ФТ-47.** Страница «Бейджи» содержит:
- Размер: 70 × 30 мм
- Серый бейдж и белый бейдж с логотипом
- Состав текста: имя, должность, учёная степень

**ФТ-48.** Страница «Внутренняя навигация» содержит:
- Шаблоны навигационных табличек (этажные указатели, таблички на двери)
- Материал: оргстекло, плёнки Oracal 053M и 073M
- Пример с QR-кодом на профиль врача

**ФТ-49.** Страница «Брендирование транспорта» содержит:
- Макет оклейки трамвая (боковой вид)
- Применяемые цвета: 053M, 073M, 066M, 050M, 081M, 080M

---

### 5.8 Экспериментальная секция

**ФТ-50.** В разделе «Эксперименты» отображается список экспериментальных компонентов:
- Для `viewer`: только со статусом `approved`
- Для `editor`: все (draft, review, approved)

**ФТ-51.** `editor` может создать новый экспериментальный компонент через кнопку «Дублировать» на любом существующем компоненте брендбука.

**ФТ-52.** После дублирования открывается интерактивная форма редактирования атрибутов компонента:
- Текстовые поля (заголовки, описания, подписи)
- Выбор цвета из палитры токенов (colour picker ограничен токенами бренда)
- Выбор размера (из допустимых значений)
- Предпросмотр компонента обновляется в реальном времени при изменении атрибутов
- Кнопки: «Сохранить как черновик», «Отмена»

**ФТ-53.** Созданный компонент сохраняется в БД со статусом `draft` и привязкой к автору.

**ФТ-54.** `editor` может изменить статус компонента:
- `draft` → `review` (передать на согласование)
- `review` → `approved` (утвердить)
- `review` → `draft` (вернуть на доработку)

**ФТ-55.** Удаление возможно только для компонентов со статусом `draft`.

**ФТ-56.** Каждый экспериментальный компонент имеет карточку: название, автор, дата создания, статус, базовый компонент (от которого дублирован), превью.

---

### 5.9 Авторизация

**ФТ-60.** При входе на защищённые страницы неавторизованный пользователь перенаправляется на `/login`.

**ФТ-61.** Форма входа: поле email + поле пароль + кнопка «Войти».

**ФТ-62.** После успешного входа пользователь перенаправляется на страницу, с которой был перенаправлен.

**ФТ-63.** В шапке брендбука отображается: имя пользователя, роль, кнопка «Выйти».

**ФТ-64.** Токен сессии хранится в httpOnly cookie.

---

## 6. Требования к интеграциям

### 6.1 API сайта oclinica.ru

Брендбук получает реальные данные с сайта клиники для отображения в компонентах и страницах.

**Необходимые данные и источники:**

| Данные           | Раздел брендбука                    | Тип запроса     |
|------------------|-------------------------------------|-----------------|
| Список врачей    | Блок «Наши врачи», страница «Врачи» | GET             |
| Профиль врача    | Страница «Врач»                     | GET by ID       |
| Список новостей  | Блок «Новости»                      | GET             |
| Список услуг     | Блок «Услуги / Заболевания»         | GET             |
| Цены             | Страница «Цены»                     | GET             |
| Отзывы           | Блок «Отзывы»                       | GET             |

**ИНТ-01.** Сайт oclinica.ru работает на Drupal. Для получения данных используется Drupal JSON:API (если доступен) или стандартный REST API Drupal (`/node?_format=json`).

> **Требует уточнения:** наличие и формат API на стороне oclinica.ru — необходимо проверить доступные эндпоинты до начала Sprint 1.

**ИНТ-02.** Запросы к API oclinica.ru выполняются на стороне бэкенда (NestJS), не из браузера — для обхода возможных CORS-ограничений.

**ИНТ-03.** Данные кэшируются на бэкенде с TTL 15 минут, чтобы не создавать нагрузку на сайт клиники.

**ИНТ-04.** Если API oclinica.ru недоступен — компоненты отображаются с заглушками (mock data), брендбук не падает.

---

## 7. Требования к данным

### 7.1 Схема базы данных (основные модели)

#### `User`
| Поле         | Тип        | Описание                          |
|--------------|------------|-----------------------------------|
| id           | UUID       | Первичный ключ                    |
| email        | String     | Уникальный, логин                 |
| name         | String     | Имя для отображения               |
| passwordHash | String     | bcrypt-хеш пароля                 |
| role         | Enum       | `viewer` / `editor`               |
| createdAt    | DateTime   |                                   |

#### `ExperimentalComponent`
| Поле            | Тип        | Описание                                     |
|-----------------|------------|----------------------------------------------|
| id              | UUID       | Первичный ключ                               |
| name            | String     | Название компонента                          |
| baseComponent   | String     | Идентификатор базового компонента-источника  |
| attributes      | JSON       | Атрибуты компонента (цвет, текст, размер...) |
| status          | Enum       | `draft` / `review` / `approved`              |
| authorId        | UUID       | FK → User                                    |
| createdAt       | DateTime   |                                              |
| updatedAt       | DateTime   |                                              |

#### `ExperimentalPage` *(планируется в backlog)*
| Поле       | Тип      | Описание                         |
|------------|----------|----------------------------------|
| id         | UUID     |                                  |
| name       | String   |                                  |
| blocks     | JSON     | Упорядоченный список блоков      |
| status     | Enum     | `draft` / `review` / `approved`  |
| authorId   | UUID     | FK → User                        |

---

## 8. Нефункциональные требования

### 8.1 Производительность
- Страница брендбука загружается менее чем за 3 секунды при стабильном соединении.
- Предпросмотр компонента при редактировании атрибутов обновляется без задержки (оптимистичный рендер на клиенте).

### 8.2 Адаптивность
- Брендбук корректно отображается на: Desktop (1440px), Tablet (768px), Mobile (375px).
- Компоненты и страницы имеют встроенный переключатель viewport для предпросмотра.

### 8.3 Доступность (Accessibility)
- Все базовые компоненты соответствуют стандарту **WCAG 2.1 AA**.
- Клавиатурная навигация поддерживается для всех интерактивных элементов.
- Контрастность текста проверяется автоматически в разделе «Цвета».

### 8.4 Кроссбраузерность
- Поддерживаемые браузеры: Chrome 120+, Firefox 120+, Safari 17+, Edge 120+.

### 8.5 Надёжность
- При отсутствии данных от API oclinica.ru — graceful degradation (заглушки, нет ошибок).
- Все API-эндпоинты возвращают понятные коды ошибок (4xx, 5xx) с описанием.

### 8.6 Масштабируемость
- Архитектура monorepo позволяет добавлять новые пакеты (`packages/`) без переработки ядра.
- База данных спроектирована с возможностью расширения моделей без breaking changes.

---

## 9. Технический стек

| Слой              | Технология            | Версия   | Обоснование                                      |
|-------------------|-----------------------|----------|--------------------------------------------------|
| Фронтенд          | Next.js (App Router)  | 16.x     | SSR/SSG, оптимизация, экосистема React           |
| Бэкенд            | NestJS                | 11.x     | Типизированный Node.js фреймворк, DI, модули     |
| База данных       | PostgreSQL            | 16.x     | Надёжная реляционная БД, JSON-поля для атрибутов |
| ORM               | Prisma                | 7.x      | Type-safe запросы, миграции, seed                |
| Стилизация        | Tailwind CSS          | 4.x      | Utility-first, CSS-переменные, нет рантайм-overhead |
| Дизайн-токены     | CSS Custom Properties | —        | Нативно поддерживается всеми браузерами          |
| Шрифт (бренд)     | DINPro                | —        | Фирменный шрифт бренда, оффлайн-носители         |
| Шрифт (веб)       | Fira Sans             | —        | Google Fonts, кириллица, веса 300/400/500/600    |
| Авторизация       | JWT + httpOnly cookie | —        | Безопасное хранение токена                       |
| Пакетный менеджер | pnpm                  | 10.x     | Monorepo workspaces, скорость                    |
| Контейнеризация   | Docker + Compose      | —        | Единообразное окружение локальной разработки     |
| Хостинг фронтенда | Vercel                | —        | Нативная поддержка Next.js, бесплатный Hobby-план |

---

## 10. Архитектура системы

### 10.1 Структура monorepo

```
oclinica-brandbook/
├── apps/
│   ├── web/                    # Next.js — фронтенд брендбука
│   │   ├── app/                # App Router (страницы брендбука)
│   │   ├── components/         # UI-компоненты брендбука
│   │   │   ├── base/           # Базовые компоненты (Button, Input...)
│   │   │   ├── blocks/         # Блоки страниц (Hero, DoctorGrid...)
│   │   │   └── experimental/   # Движок экспериментальных компонентов
│   │   └── lib/                # Утилиты, API-клиент
│   └── api/                    # NestJS — REST API
│       ├── src/
│       │   ├── auth/           # JWT авторизация
│       │   ├── users/          # Управление пользователями
│       │   ├── components/     # CRUD экспериментальных компонентов
│       │   └── oclinica/       # Прокси к API oclinica.ru (с кэшем)
│       └── prisma/
│           ├── schema.prisma
│           └── seed.ts
├── packages/
│   └── tokens/                 # Дизайн-токены (цвета, типографика) — shared
├── docs/                       # Проектная документация
├── .env.example
├── docker-compose.yml
├── pnpm-workspace.yaml
└── README.md
```

### 10.2 Потоки данных

```
Браузер (Next.js)
    │
    ├── Статичные компоненты ──────────► Рендер из кода (нет запросов)
    │
    ├── Реальные данные клиники ───────► NestJS API ──► кэш ──► oclinica.ru API
    │
    └── Экспериментальные компоненты ──► NestJS API ──────────► PostgreSQL
```

---

## 11. Безопасность и авторизация

**БЕЗ-01.** Авторизация реализована на JWT-токенах, хранящихся в httpOnly cookie (не localStorage).

**БЕЗ-02.** Пароли хранятся только в виде bcrypt-хешей (cost factor 12).

**БЕЗ-03.** Все мутирующие эндпоинты API (`POST`, `PATCH`, `DELETE`) защищены Guard-ами NestJS и требуют роль `editor`.

**БЕЗ-04.** CORS настроен явно — разрешены только домены фронтенда.

**БЕЗ-05.** Входные данные форм валидируются на бэкенде через `class-validator` (NestJS Pipes).

**БЕЗ-06.** В production `.env` файл не попадает в репозиторий (`.gitignore`).

---

## 12. Требования к окружению

### 12.1 Локальная разработка

| Требование   | Версия   |
|--------------|----------|
| Node.js      | >= 20 LTS |
| pnpm         | >= 9     |
| Docker       | >= 24    |
| Docker Compose | >= 2   |

### 12.2 Деплой фронтенда (Vercel)

Фронтенд (`apps/web`) деплоится на Vercel Hobby (бесплатно).

**Production URL:** https://web-oclinica.vercel.app

**Команда деплоя** (из директории `apps/web`):
```bash
vercel --prod --yes
```

**Требования:**
- Vercel CLI установлен глобально: `npm install -g vercel`
- Выполнен `vercel login` (однократно)

**Деплой занимает ~30 секунд.** После команды изменения сразу доступны по production URL.

### 12.3 Бэкенд и база данных

> TBD — параметры хостинга бэкенда (NestJS + PostgreSQL) будут определены к Sprint 11,
> когда потребуется работающий API для экспериментальной секции.

Варианты для рассмотрения: Railway, Render, VPS клиники.

---

## 13. Ограничения и допущения

| №  | Ограничение / допущение                                                                            |
|----|----------------------------------------------------------------------------------------------------|
| 1  | Логотип клиники в векторном формате будет предоставлен позже — раздел «Логотип» реализуется отдельно |
| 2  | Наличие и структура API oclinica.ru требуют проверки до начала разработки интеграции               |
| 3  | В v1.0 нет административного UI — управление пользователями через seed-скрипт или прямые запросы к API |
| 4  | Экспериментальные компоненты создаются только методом дублирования — прямое написание HTML/CSS не предусмотрено |
| 5  | Drag-and-drop конструктор страниц — в backlog, не в v1.0                                          |
| 6  | Тёмная тема — в backlog, не в v1.0                                                                |

---

## 14. Открытые вопросы

| №  | Вопрос                                                                              | Ответственный | Срок     |
|----|--------------------------------------------------------------------------------------|---------------|----------|
| ОВ-01 | Доступен ли JSON API или REST API на oclinica.ru? Каков формат ответов?         | Клиника       | Sprint 1 |
| ОВ-02 | ~~Параметры хостинга для production-деплоя~~ **Закрыт:** фронтенд — Vercel Hobby (https://web-oclinica.vercel.app); бэкенд — TBD к Sprint 11 | — | Частично закрыт |
| ОВ-03 | Нужна ли страница «Заболевание» как отдельный тип, или это подвид страницы «Услуга»? | Клиника  | Sprint 9 |
| ОВ-04 | Список иконок — какую стороннюю библиотеку утвердить? (Lucide, Heroicons, и др.) | Совместно     | Sprint 2 |
| ОВ-05 | ~~Нужен ли раздел «Логотип» в v1.0 или ждём вектор?~~ **Закрыт:** страница логотипа реализуется в Sprint 1 с PNG-версией; вектор будет добавлен позже | —  | Закрыт   |
| ОВ-06 | ~~HEX-эквиваленты цветов Oracal~~ **Закрыт:** приблизительные HEX зафиксированы в Sprint 2 (053M=#7ecfca, 073M=#5b7b87, 066M=#5bb5ad, 050M=#1b4c72, 081M=#c4a882, 080M=#5c2e0e). Дополнительно — реальные цвета сайта извлечены из CSS (см. ОВ-07). Точная калибровка Oracal — при получении физических образцов. | — | Закрыт |
| ОВ-07 | **Цвета сайта oclinica.ru** — CSS тема Drupal доступна по адресу: `https://perm.oclinica.ru/sites/all/themes/clinic_bootstrap_mobile/css/style.css`. Тема: `clinic_bootstrap_mobile`. Ключевые цвета извлечены парсингом (python + regex + Counter), 2026-03-22. Добавлены в раздел «Цвета с сайта» в брендбуке (`/foundation/colors`). Расхождение с Oracal-палитрой ожидаемо — цифровые адаптации под экран. | — | Закрыт |

---

*Документ будет обновляться по ходу проекта. Изменения фиксируются в git-истории.*
