mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-05 01:14:58 +03:00
Интерфейс был русским в коде: строки лежали прямо в JSX и в ответах API, даты форматировались прибитым «ru-RU», склонение по числу писалось руками в каждом файле. Теперь текста в коде нет — он живёт в словарях, а язык выбирается человеком. Цепочка одна на обе стороны: профиль сотрудника → организация → установка → браузер. Пустое значение на каждом уровне значит «как выше», а не «русский»: тот, кто язык не трогал, поедет за организацией, когда владелец её переключит, а выбравший явно — останется на своём. Владелец задаёт язык организации («Настройки» → «Организация», рядом с часовым поясом) и язык установки («Платформа») — на нём открываются вход, сброс пароля и мастер первого запуска. Сотрудник переопределяет его в профиле. Русский каталог задаёт набор ключей, английский обязан его повторить: во фронтенде это ловит tsc — пропущенный перевод становится ошибкой сборки, — на бэкенде тест каталога, который заодно сверяет имена параметров в фразах. Формы множественного числа берутся из CLDR через Intl.PluralRules, даты и размеры — через Intl, а не через свои списки месяцев. Отдельно пришлось разобраться с тем, что уже записано в базу. Системные события диалога писались готовой русской фразой, и перевести историю задним числом нельзя — теперь пишется код события, а фразу собирает сервер на языке читателя. То же с уведомлениями: они адресованы операторам, а не одному человеку, и в смешанной команде готовая фраза неверна для половины. Тон системной строки в треде и признак анонимного посетителя больше не угадываются регуляркой по русским словам: под английским бэкендом это просто перестало бы работать. Письма уходят на языке получателя, а не отправителя: приглашение отправляет владелец, а читает другой человек. gettext не взят намеренно: .po/.mo потребовали бы msgfmt в сборке образа ради того же результата, что дают обычные словари, одинаковые на обеих сторонах. Язык запроса при этом активируется штатным механизмом Django, поэтому сообщения DRF переводятся тоже. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
11 KiB
11 KiB
Если в окружении не доступен инструмент, например - Python, PHP, попробуй docker, если в проекте есть его файлы.
Без моего явного указания не меняй ничего! Если я задал вопросы, это не значит что ты можешь менять файлы! Любые правки только после моего явного указания, например - "делай". Соблюдай инструкцию по коммитам. Используй glab, gh если доступны.
Учетные данные / доступы:
- Без явного указания владельца не менять, не сбрасывать, не bootstrap-ить и не пересоздавать никакие учетные данные, пароли, TOTP, recovery-коды, сессии и права доступа.
- Если для проверки нужен вход в приложение, использовать только уже существующие учетные данные, предоставленные владельцем, и не выполнять команды, которые могут изменить пароль или состояние аккаунта.
- Любые команды управления аккаунтами, включая
bootstrap_owner, password reset/change, seed пользователей и изменение ролей, требуют отдельного явного подтверждения владельца перед запуском.
Production deployment / миграция:
- Не принимать самостоятельно решения о способе переноса production-данных, bind mounts, путях хранения, переключении каталогов или удалении старого deployment.
- Перед любым изменяющим действием в production сначала представить владельцу точный план миграции и получить его явное согласование. Разрешение на диагностику или общая просьба «исправить» не являются разрешением самостоятельно выбирать архитектуру миграции.
UI / дизайн:
- Никакой отсебятины в UI: не добавлять экраны, блоки, карточки, иконки, тексты, анимации, цвета, layout-решения и состояния, которых нет в утвержденной документации или design-system.
- Если UI-этап еще не наступил, UI не считается реализованным и не должен маскироваться под готовый продуктовый интерфейс.
- Для построения UI использовать существующие компоненты и их стили, если они уже реализованы; если подходящего компонента нет, создавать переиспользуемый компонент в рамках существующей системы.
- Не упрощать UI, анимации, иконки, состояния или поведение по своему усмотрению. Любое отклонение от baseline требует явного согласования до правок.
- Технические временные заглушки UI не считать готовой реализацией и не использовать как основу продуктового UI без отдельного явного разрешения.
Один стандарт на один элемент:
- Ссылки во всём приложении выглядят одинаково. Единая база — класс
.linkизshared/links.css, одинаковый и для<a>, и для<button>. Роль задаётся модификатором:.is-strong(имя сущности),.is-neutral(тёмное имя, синее при наведении),.is-muted(второстепенная, «Назад», «Отмена»),.is-mono(идентификаторы),.has-icon(с иконкой). Заводить в фиче свой*-name-link,*-meta-link,*-link-buttonзапрещено. - Действие, а не переход, оформляется
<button className="link">, а не<a href="#">сpreventDefault. - Выпадающие меню — только antd
DropdownсoverlayClassName="app-dropdown"и триггером.row-menu-button. Своих меню наposition: absolute/fixed, ручном расчёте координат и подложек-скримов не делать: портал закрывается по клику вне и по Esc сам и не обрезаетсяoverflow. - Перед тем как написать свой элемент, искать существующий в
shared/и в соседних фичах. Второй стандарт того же элемента — это дефект, а не свобода реализации.
Никаких служебных записок в продукте:
- В продуктовом UI не должно быть служебной лексики. Запрещены на экране: коды спек и решений (SPEC-HUB-, ADR-HUB-, DG-*), номера правил (P1-P5 и любые другие), слова «инвариант», «констрейнт», «миграция», «scope» в техническом смысле, имена таблиц, полей и enum-значений БД и API (
allowCheckoutActions,Conversation.channel,PROTECT,OK/ERRORкак есть), ссылки на внутренние документы и любые пометки для разработчика. - Пользователю показывается следствие и способ исправить, а не внутреннее правило. «Коммерческие действия недоступны непродуктовому каналу. Назначьте продукт» — да. «Запрещено инвариантом P1» — нет.
- Технические коды остаются в коде, комментариях, логах и API-ответах, но не в текстах интерфейса.
- Это относится и к baseline-макетам: служебный текст, попавший в макет, не является основанием выводить его на экран. Макет реализуется, дополняется по указанию владельца, служебная лексика в реализацию не переносится.
- Правило действует на прод в первую очередь: ни одна служебная пометка не должна доезжать до пользователя.
Engineering rules / обязательные практики:
- Соблюдать DRY, KISS, SRP, separation of concerns и NO GOD FILES.
- Не реализовывать полноценную страницу, feature или крупный workflow одним большим компонентом/файлом.
- Если компонент превышает примерно 200 строк или смешивает layout, state, data/model и subviews, разделить его до завершения задачи.
- Если новый или измененный файл превышает примерно 300 строк из-за текущей работы, остановиться и вынести части в меньшие модули до финального ответа или коммита.
- Page-компоненты должны быть преимущественно composition-only: subviews выносить в соседние компоненты, демо/static data в model/data файл, повторяемый UI в shared/local reusable components.
- Не инлайнить сложный UI повторно. Выносить компонент, если структура повторяется или секция имеет отдельную ответственность.
- Если реализация по задаче конфликтует с этими правилами, остановиться и явно сообщить blocker вместо поставки плохой структуры.
Язык интерфейса:
- Текста, который видит человек, в коде не бывает. Строка живёт в словаре и подставляется через
t(...): во фронтенде этоsrc/i18nприложения (packages/ui— свой словарь), на бэкендеchatballs/i18n. Русский каталог — источник ключей, английский обязан его повторить: пропущенный перевод во фронтенде ловитtsc, на бэкенде — тест каталога. - Ключ пишется от смысла, а не от фразы:
settings.storage_bucket_name, а не пересказ текста. Строку переформулируют чаще, чем переименовывают. - Число не склоняют вручную: формы задаёт словарь, форму выбирает
tn(...). Дату, размер файла и разряды числа форматируетfmt— прибитые"ru-RU"и свои списки месяцев запрещены. - Что записано в базу, переводится по коду, а не текстом: системные события диалога, уведомления и подписи журнала аудита хранят код, а фразу собирает бэкенд на языке читателя. Писать в историю готовую русскую фразу нельзя — её потом не перевести.
- Язык запроса выбирается цепочкой: профиль сотрудника → организация → установка → браузер. Письмо получает язык адресата, а не отправителя.
- На бэкенде
t(...)не вызывается на уровне модуля: язык там свой на каждый запрос, а константа посчиталась бы один раз при импорте.
Definition of Done:
- Запускать только тесты, относящиеся к изменениям текущей итерации. Полный прогон всех тестов выполнять только по явному указанию владельца.
- Измененные файлы должны быть проверены на NO GOD violations.
- Новый компонент не должен владеть несвязанными ответственностями.
- Не должно быть придуманных текстов, иконок, layout-решений или состояний вне design/docs.
- Любое отклонение от design/docs должно быть явно указано.