ссылки между конвенциями переписаны на темы и идентификаторы
- 41 ссылка вида `lang/go/logging.md` заменена на «конвенция `logging`», идентификатор правила или «базовый слой» для своей же темы - MIGR-8 больше не отсылает за форматом меток времени, а называет его; MIGR-11 перенёс ссылку на KEYS-1/KEYS-2 из нормы в «Почему»
This commit is contained in:
@@ -293,9 +293,9 @@ prefix: CONF
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — формат времени; зона отображения — единственный
|
- конвенция `time` — формат времени; зона отображения — единственный
|
||||||
конфигурируемый параметр времени, семантика описана там.
|
конфигурируемый параметр времени, семантика описана там.
|
||||||
- `arch/app-directories.md` — конфиг лежит в категории «конфигурация» и
|
- конвенция `app-directories` — конфиг лежит в категории «конфигурация» и
|
||||||
доступен приложению только на чтение.
|
доступен приложению только на чтение.
|
||||||
|
|
||||||
<!-- local:связано -->
|
<!-- local:связано -->
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ KEYS-1 требует **сортируемый** строковый иденти
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — метки времени тоже генерирует приложение, а не схема.
|
- конвенция `time` — метки времени тоже генерирует приложение, а не схема.
|
||||||
|
|
||||||
<!-- local:связано -->
|
<!-- local:связано -->
|
||||||
<!-- /local -->
|
<!-- /local -->
|
||||||
|
|||||||
@@ -154,8 +154,8 @@ prefix: TIME
|
|||||||
|
|
||||||
### TIME-11. Зона отображения берётся из конфигурации, по умолчанию `UTC`
|
### TIME-11. Зона отображения берётся из конфигурации, по умолчанию `UTC`
|
||||||
|
|
||||||
**ДОЛЖЕН.** Значение приходит из конфигурации (`arch/config.md`), значение
|
**ДОЛЖЕН.** Значение приходит из конфигурации, значение по умолчанию —
|
||||||
по умолчанию — `UTC`.
|
`UTC`.
|
||||||
|
|
||||||
**Почему.** Зашитая в код зона превращает переезд или второго пользователя в
|
**Почему.** Зашитая в код зона превращает переезд или второго пользователя в
|
||||||
другом поясе в правку кода и релиз. Значение по умолчанию `UTC` выбрано
|
другом поясе в правку кода и релиз. Значение по умолчанию `UTC` выбрано
|
||||||
@@ -184,8 +184,9 @@ prefix: TIME
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/config.md` — где задаётся зона отображения.
|
- конвенция `config` — где задаётся зона отображения.
|
||||||
- `arch/db-identifiers.md` — то же правило «генерирует приложение» для id.
|
- конвенция `db-identifiers` — то же правило «генерирует приложение» для
|
||||||
|
идентификаторов.
|
||||||
|
|
||||||
<!-- local:связано -->
|
<!-- local:связано -->
|
||||||
<!-- /local -->
|
<!-- /local -->
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ extends: arch/config.md
|
|||||||
|
|
||||||
# Конфигурация: реализация на Go
|
# Конфигурация: реализация на Go
|
||||||
|
|
||||||
Как `arch/config.md` выглядит в Go-приложении: формат, загрузчик, границы
|
Как базовый слой выглядит в Go-приложении: формат, загрузчик, границы
|
||||||
запрета на окружение. Форма записи — `LANGUAGE.md`.
|
запрета на окружение. Форма записи — `LANGUAGE.md`.
|
||||||
|
|
||||||
Секретов Go-специфика не касается: они приходят из деплоя уже в файле, а
|
Секретов Go-специфика не касается: они приходят из деплоя уже в файле, а
|
||||||
@@ -224,8 +224,8 @@ zoneinfo, а сообщение указывает не на ту причину
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `lang/go/time.md` — зона отображения и формат времени.
|
- конвенция `time` — зона отображения и формат времени.
|
||||||
- `lang/go/logging.md` — `slog`, которым падает невалидный конфиг.
|
- конвенция `logging` — `slog`, которым падает невалидный конфиг.
|
||||||
|
|
||||||
<!-- local:связано -->
|
<!-- local:связано -->
|
||||||
<!-- /local -->
|
<!-- /local -->
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ extends: arch/db-identifiers.md
|
|||||||
|
|
||||||
# Идентификаторы: реализация на Go
|
# Идентификаторы: реализация на Go
|
||||||
|
|
||||||
Как `arch/db-identifiers.md` выглядит в Go-приложении. Форма записи —
|
Как базовый слой выглядит в Go-приложении. Форма записи —
|
||||||
`LANGUAGE.md`.
|
`LANGUAGE.md`.
|
||||||
|
|
||||||
Единая точка из `KEYS-3` — пакет `internal/ident`: он
|
Единая точка из `KEYS-3` — пакет `internal/ident`: он
|
||||||
@@ -118,8 +118,8 @@ HTTP-кодов. В случае GKEY-8.1 снаружи это неотличи
|
|||||||
**НЕ ДОЛЖЕН.** Обработчик не конструирует доменный sentinel (например
|
**НЕ ДОЛЖЕН.** Обработчик не конструирует доменный sentinel (например
|
||||||
`ErrNotFound`), чтобы тут же сопоставить его со своим ответом.
|
`ErrNotFound`), чтобы тут же сопоставить его со своим ответом.
|
||||||
|
|
||||||
**Почему.** Инверсия правила «трансляция у источника» из
|
**Почему.** Инверсия правила «трансляция у источника» из конвенции
|
||||||
`lang/go/errors.md`. Sentinel — сообщение от слоя, который знает факт:
|
`errors`. Sentinel — сообщение от слоя, который знает факт:
|
||||||
строка не найдена, потому что store её искал. Сфабрикованный транспортом,
|
строка не найдена, потому что store её искал. Сфабрикованный транспортом,
|
||||||
он утверждает непроверенное, и по типу ошибки перестаёт быть видно, был ли
|
он утверждает непроверенное, и по типу ошибки перестаёт быть видно, был ли
|
||||||
вообще поход в хранилище — а на этом держится вся диагностика по ошибкам.
|
вообще поход в хранилище — а на этом держится вся диагностика по ошибкам.
|
||||||
|
|||||||
@@ -119,14 +119,15 @@ down останавливает сразу и заставляет пересо
|
|||||||
таблицы соответствия, которую пришлось бы держать в голове для числового
|
таблицы соответствия, которую пришлось бы держать в голове для числового
|
||||||
кода.
|
кода.
|
||||||
|
|
||||||
### MIGR-8. Метки времени — `TEXT` в формате из `arch/time.md`
|
### MIGR-8. Метки времени — `TEXT` в каноническом формате
|
||||||
|
|
||||||
**ДОЛЖЕН.** Колонка с меткой времени объявляется как `TEXT`, значения
|
**ДОЛЖЕН.** Колонка с меткой времени объявляется как `TEXT`, значения
|
||||||
пишутся в формате из `arch/time.md`.
|
пишутся как RFC 3339 в UTC с суффиксом `Z` и фиксированной шириной.
|
||||||
|
|
||||||
**Почему.** Типа даты в SQLite нет, поэтому единственное, что делает
|
**Почему.** Типа даты в SQLite нет, поэтому единственное, что делает
|
||||||
значения сравнимыми, — договорённость о формате. Текст в формате из
|
значения сравнимыми, — договорённость о формате; сам формат выбран не
|
||||||
`arch/time.md` сортируется лексикографически в том же порядке, что и
|
здесь, а конвенцией `time` (`TIME-1`, `TIME-2`). Текст в нём сортируется
|
||||||
|
лексикографически в том же порядке, что и
|
||||||
хронологически: `ORDER BY` и диапазонные условия работают без функций
|
хронологически: `ORDER BY` и диапазонные условия работают без функций
|
||||||
преобразования, а значит и без потери индекса. Соседство двух форматов в
|
преобразования, а значит и без потери индекса. Соседство двух форматов в
|
||||||
одной колонке ломает и сравнение, и разбор на стороне Go.
|
одной колонке ломает и сравнение, и разбор на стороне Go.
|
||||||
@@ -159,12 +160,12 @@ down останавливает сразу и заставляет пересо
|
|||||||
### MIGR-11. Первичный ключ новой таблицы — TEXT ULID
|
### MIGR-11. Первичный ключ новой таблицы — TEXT ULID
|
||||||
|
|
||||||
**ДОЛЖЕН.** Колонка ключа объявляется как `TEXT`, значение приходит из
|
**ДОЛЖЕН.** Колонка ключа объявляется как `TEXT`, значение приходит из
|
||||||
приложения (`KEYS-1`, `KEYS-2`).
|
приложения.
|
||||||
|
|
||||||
**Почему.** Здесь конвенция схемы ничего не решает — она реализует решение,
|
**Почему.** Здесь конвенция схемы ничего не решает — она реализует решение,
|
||||||
принятое в `arch/db-identifiers.md`. Повторить там ветвление или условие
|
принятое конвенцией `db-identifiers` (`KEYS-1`, `KEYS-2`). Повторить там
|
||||||
значило бы завести второй источник правды, и соседние таблицы разъехались бы
|
ветвление или условие значило бы завести второй источник правды, и соседние
|
||||||
по разным ответам на один вопрос.
|
таблицы разъехались бы по разным ответам на один вопрос.
|
||||||
|
|
||||||
`AUTOINCREMENT` в такой таблице невозможен: SQLite разрешает его только на
|
`AUTOINCREMENT` в такой таблице невозможен: SQLite разрешает его только на
|
||||||
`INTEGER PRIMARY KEY`. То есть для новых таблиц запрещать нечего.
|
`INTEGER PRIMARY KEY`. То есть для новых таблиц запрещать нечего.
|
||||||
@@ -192,9 +193,9 @@ down останавливает сразу и заставляет пересо
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — формат меток времени.
|
- конвенция `time` — формат меток времени.
|
||||||
- `arch/db-identifiers.md` — выбор первичных ключей.
|
- конвенция `db-identifiers` — выбор первичных ключей.
|
||||||
- `lang/go/errors.md` — граничные ошибки `database/sql` транслируются в
|
- конвенция `errors` — граничные ошибки `database/sql` транслируются в
|
||||||
доменные у источника, в слое store.
|
доменные у источника, в слое store.
|
||||||
|
|
||||||
<!-- local:связано -->
|
<!-- local:связано -->
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ prefix: GERR
|
|||||||
# Ошибки
|
# Ошибки
|
||||||
|
|
||||||
Как ошибки строятся, оборачиваются и проверяются. Форма записи —
|
Как ошибки строятся, оборачиваются и проверяются. Форма записи —
|
||||||
`LANGUAGE.md`. Где и когда ошибку **логировать** — в
|
`LANGUAGE.md`. Где и когда ошибку **логировать** — в конвенции `logging`
|
||||||
`lang/go/logging.md` (коротко: лог один раз на доменной границе).
|
(коротко: лог один раз на доменной границе).
|
||||||
|
|
||||||
Две границы, о которых говорят правила ниже:
|
Две границы, о которых говорят правила ниже:
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
### GERR-12. Полная ошибка идёт в приватный канал
|
### GERR-12. Полная ошибка идёт в приватный канал
|
||||||
|
|
||||||
**ДОЛЖЕН.** В лог уходит вся цепочка `%w` с контекстом; где и когда именно
|
**ДОЛЖЕН.** В лог уходит вся цепочка `%w` с контекстом; где и когда именно
|
||||||
— `lang/go/logging.md`.
|
— конвенция `logging`.
|
||||||
|
|
||||||
**Почему.** Цепочка — единственный носитель диагностики (GERR-1), и
|
**Почему.** Цепочка — единственный носитель диагностики (GERR-1), и
|
||||||
единственный канал, где её можно показать целиком, — тот, который видит
|
единственный канал, где её можно показать целиком, — тот, который видит
|
||||||
@@ -231,7 +231,7 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
|
|
||||||
**Почему.** Непокрытая ошибка — не класс отказа, а дефект: ветвь забыли
|
**Почему.** Непокрытая ошибка — не класс отказа, а дефект: ветвь забыли
|
||||||
завести вопреки GERR-16. Адресат у неё владелец в смысле «надо чинить», отсюда
|
завести вопреки GERR-16. Адресат у неё владелец в смысле «надо чинить», отсюда
|
||||||
`ERROR` — уровень выбирается по адресату (`lang/go/logging.md`). Статус
|
`ERROR` — уровень выбирается по адресату (конвенция `logging`). Статус
|
||||||
тоже не выбирается: известное пользовательское состояние лежало бы в
|
тоже не выбирается: известное пользовательское состояние лежало бы в
|
||||||
маппинге, а про неизвестное сказать пользователю нечего, поэтому 4xx
|
маппинге, а про неизвестное сказать пользователю нечего, поэтому 4xx
|
||||||
отпадает.
|
отпадает.
|
||||||
@@ -385,9 +385,8 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `lang/go/logging.md` — где и когда ошибка попадает в лог.
|
- конвенция `logging` — где и когда ошибка попадает в лог.
|
||||||
- `KEYS-7` (`arch/db-identifiers.md`) — формат корреляционного ключа
|
- `KEYS-7` — формат корреляционного ключа из `GERR-14`.
|
||||||
из `GERR-14`.
|
|
||||||
|
|
||||||
<!-- local:механизировано -->
|
<!-- local:механизировано -->
|
||||||
<!-- /local -->
|
<!-- /local -->
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ dev-выводом перестаёшь ежедневно гонять собс
|
|||||||
### SLOG-3. Время записи — UTC
|
### SLOG-3. Время записи — UTC
|
||||||
|
|
||||||
**ДОЛЖЕН.** `time` приводится к UTC через `ReplaceAttr` по `slog.TimeKey`
|
**ДОЛЖЕН.** `time` приводится к UTC через `ReplaceAttr` по `slog.TimeKey`
|
||||||
(см. `lang/go/time.md`).
|
(см. конвенцию `time`).
|
||||||
|
|
||||||
**Почему.** По умолчанию UTC не получится: встроенные хендлеры пишут время
|
**Почему.** По умолчанию UTC не получится: встроенные хендлеры пишут время
|
||||||
в зоне самого `time.Time`, то есть в локальной зоне процесса. Записи одного
|
в зоне самого `time.Time`, то есть в локальной зоне процесса. Записи одного
|
||||||
@@ -54,8 +54,8 @@ dev-выводом перестаёшь ежедневно гонять собс
|
|||||||
событий.
|
событий.
|
||||||
|
|
||||||
Точность `JSONHandler` — миллисекунды фиксированной ширины; это другая
|
Точность `JSONHandler` — миллисекунды фиксированной ширины; это другая
|
||||||
точность, чем в БД, и по `arch/time.md` так и должно быть: ширина
|
точность, чем в БД, и по `TIME-2` так и должно быть: ширина фиксируется
|
||||||
фиксируется на носитель.
|
на носитель.
|
||||||
|
|
||||||
## Сообщение
|
## Сообщение
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ dev-выводом перестаёшь ежедневно гонять собс
|
|||||||
|
|
||||||
**НЕ СЛЕДУЕТ.** Отдельный случайный `trace_id` не заводится, если у
|
**НЕ СЛЕДУЕТ.** Отдельный случайный `trace_id` не заводится, если у
|
||||||
сущностей есть стабильные уникальные идентификаторы. (Как их выбирают —
|
сущностей есть стабильные уникальные идентификаторы. (Как их выбирают —
|
||||||
`arch/db-identifiers.md`, если конвенция взята.)
|
конвенция `db-identifiers`, если взята.)
|
||||||
|
|
||||||
**Почему.** Идентификатор сущности уже существует, стабилен между
|
**Почему.** Идентификатор сущности уже существует, стабилен между
|
||||||
процессами и во времени — по нему собираются записи не одного прохода, а
|
процессами и во времени — по нему собираются записи не одного прохода, а
|
||||||
@@ -347,7 +347,7 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
|
|||||||
|
|
||||||
Нарушение инварианта в собственном коде — паника, недостижимая ветка — в
|
Нарушение инварианта в собственном коде — паника, недостижимая ветка — в
|
||||||
таблицу не входит: это не доменный отказ, и логирует его recover-граница
|
таблицу не входит: это не доменный отказ, и логирует его recover-граница
|
||||||
вместе со стеком (`lang/go/errors.md`). Искать его класс здесь не нужно.
|
вместе со стеком (конвенция `errors`). Искать его класс здесь не нужно.
|
||||||
|
|
||||||
Мимо таблицы идёт и доменная ошибка, которой нет в маппинге: класса у неё
|
Мимо таблицы идёт и доменная ошибка, которой нет в маппинге: класса у неё
|
||||||
нет, потому что её просто забыли завести. Она логируется `ERROR` с
|
нет, потому что её просто забыли завести. Она логируется `ERROR` с
|
||||||
@@ -505,7 +505,7 @@ API-ключи и токены, `Authorization`-заголовки, аутент
|
|||||||
### SLOG-37. `*url.Error` санитизируется на границе клиента
|
### SLOG-37. `*url.Error` санитизируется на границе клиента
|
||||||
|
|
||||||
**ДОЛЖЕН.** Ошибка разворачивается в первопричину **до** лога и до
|
**ДОЛЖЕН.** Ошибка разворачивается в первопричину **до** лога и до
|
||||||
обёртки — раньше трансляции в доменную (`lang/go/errors.md`).
|
обёртки — раньше трансляции в доменную (конвенция `errors`).
|
||||||
|
|
||||||
**Почему.** `*url.Error` встраивает полный URL запроса, а секрет живёт
|
**Почему.** `*url.Error` встраивает полный URL запроса, а секрет живёт
|
||||||
прямо в нём: токен в пути, `api_key` в query. Go редактирует только пароль
|
прямо в нём: токен в пути, `api_key` в query. Go редактирует только пароль
|
||||||
@@ -553,11 +553,11 @@ API-ключи и токены, `Authorization`-заголовки, аутент
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — точность и зона меток времени фиксируются на носитель.
|
- конвенция `time` — точность и зона меток времени фиксируются на носитель;
|
||||||
- `lang/go/time.md` — как ставится UTC в `ReplaceAttr` (SLOG-3).
|
как ставится UTC в `ReplaceAttr` (SLOG-3).
|
||||||
- `lang/go/errors.md` — трансляция ошибки в доменную, порядок относительно
|
- конвенция `errors` — трансляция ошибки в доменную, порядок относительно
|
||||||
санитизации (SLOG-37).
|
санитизации (SLOG-37).
|
||||||
- `arch/db-identifiers.md` — откуда берутся стабильные идентификаторы,
|
- конвенция `db-identifiers` — откуда берутся стабильные идентификаторы,
|
||||||
на которых держится корреляция (SLOG-18).
|
на которых держится корреляция (SLOG-18).
|
||||||
|
|
||||||
<!-- local:механизировано -->
|
<!-- local:механизировано -->
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ extends: arch/time.md
|
|||||||
|
|
||||||
# Время: реализация на Go
|
# Время: реализация на Go
|
||||||
|
|
||||||
Как требования `arch/time.md` выполняются в Go-коде: откуда берётся
|
Как требования базового слоя выполняются в Go-коде: откуда берётся
|
||||||
«сейчас», в каком виде время попадает в базу и в логи, что делать с зонами.
|
«сейчас», в каком виде время попадает в базу и в логи, что делать с зонами.
|
||||||
Форма записи — `LANGUAGE.md`.
|
Форма записи — `LANGUAGE.md`.
|
||||||
|
|
||||||
@@ -178,13 +178,13 @@ func utcTime(_ []string, a slog.Attr) slog.Attr {
|
|||||||
суток у того, что давно посчитано и сохранено.
|
суток у того, что давно посчитано и сохранено.
|
||||||
|
|
||||||
Календарные вычисления бизнес-логики берут зону явно — как описано в
|
Календарные вычисления бизнес-логики берут зону явно — как описано в
|
||||||
`arch/time.md`.
|
базовом слое.
|
||||||
|
|
||||||
<!-- local:механизировано -->
|
<!-- local:механизировано -->
|
||||||
<!-- /local -->
|
<!-- /local -->
|
||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — базовая конвенция: UTC как формат хранения, нормализация
|
- базовый слой — UTC как формат хранения, нормализация чужого входа, явная
|
||||||
чужого входа, явная зона в календарных вычислениях.
|
зона в календарных вычислениях.
|
||||||
- `lang/go/config.md` — валидация зоны отображения загрузчиком конфига.
|
- конвенция `config` — валидация зоны отображения загрузчиком конфига.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ extends: arch/app-directories.md
|
|||||||
|
|
||||||
# Категории директорий: реализация в Ansible
|
# Категории директорий: реализация в Ansible
|
||||||
|
|
||||||
Как категории из `arch/app-directories.md` раскладываются на сервере
|
Как категории из базового слоя раскладываются на сервере
|
||||||
плейбуком. Форма записи — `LANGUAGE.md`.
|
плейбуком. Форма записи — `LANGUAGE.md`.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ prefix: HTMX
|
|||||||
показывает и какие действия поддерживает — в спеках, не здесь. Форма записи
|
показывает и какие действия поддерживает — в спеках, не здесь. Форма записи
|
||||||
— `LANGUAGE.md`.
|
— `LANGUAGE.md`.
|
||||||
|
|
||||||
Логирование запросов — `lang/go/logging.md` (HTTP-поля, рутинно-частое на
|
Логирование запросов — конвенция `logging` (HTTP-поля, рутинно-частое на
|
||||||
`DEBUG`). Трансляция доменных ошибок наружу — `lang/go/errors.md`
|
`DEBUG`). Трансляция доменных ошибок наружу — конвенция `errors`
|
||||||
(приватный канал = логи, публичный = сообщение плюс корреляционный ключ).
|
(приватный канал = логи, публичный = сообщение плюс корреляционный ключ).
|
||||||
Здесь — только специфика htmx-транспорта, без дублирования.
|
Здесь — только специфика htmx-транспорта, без дублирования.
|
||||||
|
|
||||||
@@ -215,8 +215,8 @@ s.render(w, "source_block", view) // фрагмент = тот же шаб
|
|||||||
`?err=` статус по-прежнему используется: там его кто-то читает.
|
`?err=` статус по-прежнему используется: там его кто-то читает.
|
||||||
|
|
||||||
Цена решения: в логе доступа провалившееся действие выглядит как `200`.
|
Цена решения: в логе доступа провалившееся действие выглядит как `200`.
|
||||||
Искать его надо по доменной записи об исходе операции (`lang/go/logging.md`),
|
Искать его надо по доменной записи об исходе операции (конвенция
|
||||||
а не по коду ответа.
|
`logging`), а не по коду ответа.
|
||||||
|
|
||||||
### HTMX-34. Сбой без ответа-фрагмента показывается глобальным слушателем
|
### HTMX-34. Сбой без ответа-фрагмента показывается глобальным слушателем
|
||||||
|
|
||||||
@@ -238,8 +238,8 @@ s.render(w, "source_block", view) // фрагмент = тот же шаб
|
|||||||
|
|
||||||
### HTMX-15. Наружу идёт сообщение публичного канала
|
### HTMX-15. Наружу идёт сообщение публичного канала
|
||||||
|
|
||||||
**ДОЛЖЕН.** Во фрагмент попадает нейтральный текст по правилам
|
**ДОЛЖЕН.** Во фрагмент попадает нейтральный текст публичного канала;
|
||||||
`lang/go/errors.md`; `err.Error()` в разметку не рендерится.
|
`err.Error()` в разметку не рендерится.
|
||||||
|
|
||||||
**Почему.** htmx-фрагмент выглядит внутренней деталью приложения, и на нём
|
**Почему.** htmx-фрагмент выглядит внутренней деталью приложения, и на нём
|
||||||
легче всего забыть, что это тот же публичный канал, что и страница:
|
легче всего забыть, что это тот же публичный канал, что и страница:
|
||||||
|
|||||||
Reference in New Issue
Block a user