Журнал разработки Николая Ланца

11 сент. 2026 г.

Зафиксирован прогресс по автоматическому восстановлению форматирования старого контента после миграции из draft-editor.

Написан резолвер, который берет старые варианты контента (contentText и content) и через ИИ-агента пересобирает публикацию в Markdown с сохранением исходных слов, смысла и стилистики.

import { Resource } from '@prisma/client'
import { PrismaContext } from 'server/context/interfaces'
import {
  LLMChatMessageRole,
  LlmModel,
  LlmProvider,
} from 'server/llm/client/interfaces'
import { llmChatCompletionResolver } from 'server/schema/types/LLM/resolvers/chatCompletion'

type ProcessConceptsArgs = {
  ctx: PrismaContext
  resource: Resource
}

export async function processOldContent({
  ctx,
  resource,
}: ProcessConceptsArgs): Promise<string | null | undefined> {
  const systemPrompt = `# Ты рерайтер.

Тебе будут даны разные варианты текста одной и той же публикации. Это может быть и чистый текст, и технический со всякими техническими тегами и т.п. Твоя задача пересобрать полностью статью, с сохранением слов, смысла и стилистики, но оформить все в формате маркдаун.

Так же могут быть приведены листинги кода, их надо вставить в блок кода с указанием языка. Например

\`\`\`js
const foo = 0
\`\`\`

Список всех поддерживаемых языков: 
'': 'Plain Text',
text: 'Plain Text',
js: 'JavaScript',
ts: 'TypeScript',
tsx: 'TypeScript (React)',
jsx: 'JavaScript (React)',
css: 'CSS',
html: 'HTML',
json: 'JSON',
bash: 'Bash',
shell: 'Shell',
sql: 'SQL',
gql: 'GraphQL',
python: 'Python',
markdown: 'Markdown',
django: 'Jinja/Django',
env: 'Environment',
yaml: 'YAML',

Если никакой не подходит, то не указывай явно используемый язык.


## !!! Очень важно !!! 

Важно сохранить смысл, слова и стилистику. Твоя задача отформатировать статью, а не переписать ее своими словами. Нельзя ничего додумывать, придумаывать и т.п. Если где-то есть недосказанность, эта недосказанность так и должна остаться - твоя задача только отформатировать статью.

Вернуть надо только отформатированную статью в формате маркдаун, без какого-либо технического сопроводительного кода, текста, твоих комментариев и т.п. Только сама статья. 


## Форматирование конечной публикации

Корректный Markdown с поддержкой html (но предпочтительней именно маркдаун форматирование)

Важно учитывать, что много где пропущены пробелы в тексте. Очень важно распознавать такое и корректно вставлять пробелы.

Картинки вставляются как картинки с предпросмотром. Ссылки как ссылки.

Если встречаются ссылки, ссылающиеся на домен community.modx-cms.ru, то вставляй просто текстом, а не ссылкой.
На другие домены вставляй ссылки как есть. 

Если есть картинки с внешних файлообменников типа joxi и т.п., не надо их вставлять, они не актуальны. Локальные картинки обязательно вставляй, где они указаны.
`

  const {
    content,
    contentText,

    /**
     * contentV2 не берем, потому что он формировался из content и contentText
     */
    // contentV2
  } = resource

  const peaces = [contentText, content]
    .map((n) =>
      n === null ? null : typeof n === 'string' ? n.trim() : JSON.stringify(n),
    )
    .filter((n) => !!n)

  if (!peaces.length) {
    return ''
  }

  const userPrompt = `## Вот тебе исходные данные статьи. Перепиши это в конечную статью в формате маркдаут, с сохранением слов, смысла и стилистики, и верни мне только ее, без всякого дополнительного технического текста и твоих комметариев

---

${peaces.join(`

---

`)}
  
`

  const chatResponse = await llmChatCompletionResolver(
    null,
    {
      input: {
        provider: LlmProvider.OpenRouter,
        messages: [
          {
            role: LLMChatMessageRole.system,
            content: systemPrompt,
          },
          {
            role: LLMChatMessageRole.user,
            content: userPrompt,
          },
        ],
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        model: LlmModel.GEMINI_3_5_FLASH_LITE as any,
      },
    },
    ctx,
  )

  const responseContent = chatResponse.choices?.[0]?.message?.content

  return responseContent
}

Статистика выполнения:

  • 100 публикаций — около 5 минут, бюджет ~$0.30.
  • 1296 ресурсов — около 43 минут, бюджет $2.53.

В целом обработка отработала нормально: текст стал заметно более удобочитаемым. До этого после миграции из draft-editor значительная часть публикаций превратилась фактически в сплошной текст без исходного форматирования.

При этом автоматическая обработка не дает полностью чистый результат и оставляет отдельные артефакты. Например, встречается такой результат:

В create- процессоре она есть, а в update- процессоре ее нет. Уточню, что это ключ массива данных, передаваемых в массив 
s
c
r
i
p
t
P
r
o
p
e
r
t
i
e
s
,
доступныйвнавешиваемыхплагинах
.
Приэтомониещеисоветуютэтотключнеиспользовать
,
ииспользуйтетипаключ
scriptProperties,доступныйвнавешиваемыхплагинах.Приэтомониещеисоветуютэтотключнеиспользовать,ииспользуйтетипаключthis->objectType.

Исходный HTML этого предложения:

<p>В create- процессоре она есть, а в update- процессоре ее нет. Уточню, что это ключ массива данных, передаваемых в массив <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>c</mi><mi>r</mi><mi>i</mi><mi>p</mi><mi>t</mi><mi>P</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>e</mi><mi>r</mi><mi>t</mi><mi>i</mi><mi>e</mi><mi>s</mi><mo separator="true">,</mo><mtext>доступныйвнавешиваемыхплагинах</mtext><mi mathvariant="normal">.</mi><mtext>Приэтомониещеисоветуютэтотключнеиспользовать</mtext><mo separator="true">,</mo><mtext>ииспользуйтетипаключ</mtext></mrow><annotation encoding="application/x-tex">scriptProperties, доступный в навешиваемых плагинах. При этом они еще и советуют этот ключ не использовать, и используйте типа ключ </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0278em">scr</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.1389em">ptP</span><span class="mord mathnormal" style="margin-right:0.0278em">r</span><span class="mord mathnormal">o</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.0278em">er</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">es</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord cyrillic_fallback">доступныйвнавешиваемыхплагинах</span><span class="mord">.</span><span class="mord cyrillic_fallback">Приэтомониещеисоветуютэтотключнеиспользовать</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord cyrillic_fallback">ииспользуйтетипаключ</span></span></span></span>this-&gt;objectType.</p>

Здесь проблема уже заложена в старом HTML: обычный текст оказался завернут в KaTeX/MathML, из-за чего модель пытается интерпретировать сильно искаженную структуру и местами дублирует/разбивает текст.

Вывод: автоматическая обработка существенно улучшает базовое состояние контента и подходит как массовый первый проход, но финальная вычитка и небольшие ручные правки все равно нужны.

Объем — около 1500 топиков за 13 лет. С учетом того, что большая часть после обработки визуально уже вполне читабельна и ручного внимания требуют в основном отдельные артефакты и местами сложная верстка, объем финальной ручной работы выглядит приемлемым.

Отформатировать контент

11 сент. 2026 г.

Нужно доресерчить и доработать текущую поддержку LaTeX.

Сейчас, судя по поведению интеграции, LaTeX/KaTeX-плагин пытается парсить слишком широкий фрагмент контента — возможно, фактически весь текст. Это и замедляет рендеринг, и приводит к предупреждениям/ошибкам на обычном Unicode-тексте, например:

LaTeX-incompatible input and strict mode is set to 'warn': Unicode text character "а" used in math mode [unicodeTextInMathMode]

Нужно исследовать, как именно подключен текущий плагин и на каком этапе он получает AST/контент. Цель — сделать так, чтобы LaTeX-парсер обрабатывал только явно математические фрагменты: inline math и отдельные math-блоки, а обычный Markdown/текст вообще не проходил через KaTeX.

Отдельно проверить:

  • какие синтаксические маркеры математики уже поддерживаются ($...$, $$...$$, возможно fenced/directive-блоки);
  • можно ли ограничить трансформацию на уровне Markdown AST только узлами inlineMath / math;
  • не включён ли режим/плагин, который ошибочно трактует обычный текст как math mode;
  • влияние текущей реализации на производительность;
  • после исправления проверить отсутствие unicodeTextInMathMode на обычном русском тексте и корректный рендеринг формул.
Добавить поддержку LaTex

10 сент. 2026 г.

Уточнение приоритета дизайна

Новая версия сайта уже собрана, но глубокая визуальная переработка и полное восстановление оформления старых внутренних страниц сознательно не являются текущим приоритетом.

Сначала нужно проверить, вернётся ли поисковая видимость и появится ли органическая посещаемость после обновления технической базы и контента. Если рост подтвердится, главную страницу и остальные ключевые точки входа имеет смысл переработать уже в рамках нового дизайна, не оглядываясь на старую CSS- и шаблонную архитектуру.

Обновить главную страницу и ключевые точки входа

10 сент. 2026 г.

Задача становится одним из главных следующих этапов

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

AI-driven pipeline нужен для массовой переработки Concepts: улучшения структуры, форматирования, ясности, внутренней перелинковки и общей полезности материалов. Это особенно важно сейчас, когда первичная цель проекта — восстановить поисковую видимость и проверить, способен ли обновлённый сайт снова получать органический трафик.

Разработать AI-процесс обновления импортированных Concepts

10 сент. 2026 г.

Новый приоритет после технической переделки сайта

После сборки новой версии основной ценностью проекта становится уже не восстановление внешнего вида legacy-страниц, а качество и развитие контентной базы.

Текущий фокус:

  • завершить перенос полезного старого содержания в Concepts;
  • нормализовать legacy HTML и Markdown;
  • привести материалы к новой единой модели;
  • улучшать структуру и подачу;
  • развивать внутреннюю перелинковку;
  • использовать AI-driven обработку для массового обновления накопленного контента.

Именно контент и его поисковая доступность должны показать, есть ли у проекта потенциал снова получать посещаемость. Глубокий визуальный редизайн сознательно отложен до появления сигнала роста.

Перенести весь полезный legacy-контент в Concepts и медиа

10 сент. 2026 г.

Приоритет этапа: проверить восстановление поисковой видимости

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

До появления такого сигнала нет смысла тратить существенный ресурс на глубокий редизайн внутренних страниц. Приоритет — корректный SEO-слой, индексируемый полезный контент, понятная структура, внутренние ссылки и дальнейшая переработка материалов.

Если поисковая видимость начнёт восстанавливаться, дизайн можно развивать как следующий этап уже на подтверждённо работающем контентном основании.

Сформировать SEO-слой нового сайта и обеспечить поисковый переезд

10 сент. 2026 г.

Прогресс: публичный слой новой версии собран

Новый сайт уже фактически работает поверх новой архитектуры и универсального рендеринга. При переносе выяснилось, насколько дорого обходилась старая модель: у разных legacy-сущностей были собственные представления и во многих случаях отдельный CSS.

Полное восстановление визуального оформления всех внутренних страниц сознательно не выполнялось. Это означало бы дополнительную работу по воспроизведению старых специализированных шаблонов, которые затем всё равно пришлось бы переделывать при обновлении дизайна.

На текущем этапе достаточно функционально корректного и единообразного отображения контента. Следующая визуальная итерация должна строиться уже на новой общей модели, а не имитировать legacy-структуру.

Сделать универсальный рендеринг и маршрутизацию Concepts

10 сент. 2026 г.

Этап: сайт фактически полностью пересобран на новой системе

Основная техническая переделка bizneshelper.ru выполнена. Новый сайт собран на haih-cms и больше не зависит от необходимости воспроизводить старую Ruby-архитектуру как рабочую систему.

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

Текущий этап проекта — не финальная визуальная полировка, а проверка того, сможет ли сайт снова выйти в поисковую видимость и вернуть органическую посещаемость, которая сейчас фактически отсутствует. Если видимость и трафик начнут восстанавливаться, визуальную часть имеет смысл развивать уже как отдельный следующий этап на новой архитектуре.

Главный ближайший приоритет смещается на работу с контентом: перенос, нормализацию, обновление, внутреннюю перелинковку, SEO и AI-driven переработку материалов.

Важный вывод по стоимости миграции

Фактически основная переделка заняла порядка 3–4 дней, но значительная часть этого времени была потрачена не на создание новой функциональности, а на обход особенностей старой технической реализации. Legacy-сайт оказался существенно сложнее в переносе, чем должен был быть при сопоставимом объёме контента.

Основные источники лишней сложности:

  • слишком большое количество специализированных сущностей и таблиц;
  • разные модели хранения для похожих по сути видов контента;
  • отдельная логика представления для разных сущностей;
  • собственный CSS у многих типов страниц и компонентов;
  • накопленные особенности WYSIWYG/HTML, которые приходилось нормализовать при импорте;
  • высокая связанность структуры данных с конкретными старыми шаблонами.

Это практическое подтверждение принятого архитектурного решения: унификация содержательных сущностей вокруг Concept нужна не ради абстрактной аккуратности схемы, а чтобы будущие изменения не требовали снова проходить через такой объём специальной логики.

С точки зрения проекта результат важен именно этим: несмотря на плохое внутреннее состояние legacy, новая версия была собрана за несколько дней, а дальнейшее развитие теперь можно вести уже поверх значительно более простой и AI-дружелюбной среды.

Миграция bizneshelper.ru с Ruby на haih-cms

10 сент. 2026 г.

Новый кейс: нормализация legacy HTML перед MDX/Markdown-рендерингом

При импорте контента из старого CKEditor проявилась новая категория несовместимости: даже после устранения вложенных <p> часть HTML остаётся синтаксически допустимой для браузера, но плохо переживает MDX-парсинг и последующий SSR-render.

Симптомы

MDX-парсер падал с ошибками вида:

Error parsing markdown: Expected the closing tag `</p>` either after the end of `paragraph` ...
Error parsing markdown: Expected the closing tag `</div>` either after the end of `paragraph` ...

Типичный legacy-фрагмент выглядел так:

<p style="text-align:justify"><img alt="" src="/ckeditor_assets/pictures/40/content_oil.png" style="border-style:solid; border-width:1px; height:503px; width:703px"><br>
<span style="font-family:trebuchet ms,helvetica,sans-serif; font-size:14px">Текст...</span></p>

Здесь одновременно сочетаются несколько проблем:

  • <br> записан в HTML-форме, но MDX/JSX-пайплайн ожидает self-closing вариант;
  • старый WYSIWYG активно использует <p> как универсальный контейнер;
  • переносы строк и whitespace между HTML-тегами могут быть интерпретированы MDX уже не как нейтральное форматирование исходника, а как границы markdown-параграфов.

Что было проверено

Сначала рассматривалась нормализация через htmlparser2 + dom-serializer, но этот вариант оказался неудобен для задачи: self-closing теги нормализовались не так, как нужно MDX, а текст мог сериализоваться с нежелательными HTML entities.

Рабочим вариантом оказался rehype, который позволяет сначала привести legacy HTML к более стабильной сериализации, а затем уже передать результат в общий Markdown-normalization pipeline.

Текущий pipeline

Нормализация теперь состоит из нескольких последовательных шагов.

1. Legacy <p> заменяются на <div>

Это устраняет невалидную вложенность параграфов и снижает риск hydration mismatch:

function replacePWithDiv(html: string): string {
  const $ = cheerio.load(html, { xml: false }, false)

  $('p').each((_, el) => {
    const $el = $(el)
    const div = $('<div></div>')

    div.html($el.html() || '')

    for (const attr of el.attributes) {
      div.attr(attr.name, attr.value)
    }

    $el.replaceWith(div)
  })

  return $.html()
}

2. HTML прогоняется через rehype

rehype используется как parser/stringifier для исправления и канонизации legacy-разметки:

const normalized = await rehype()
  .data('settings', {
    fragment: true,
    closeSelfClosing: true,
  })
  .process(html)

Ключевой эффект — self-closing элементы вроде <br> приводятся к форме, которая безопаснее проходит через MDX/JSX-обработку.

3. Удаляется whitespace между соседними тегами

После сериализации дополнительно схлопываются переносы и пробелы между HTML-тегами:

html = String(normalized).replace(/>\s+</g, '><')

Это важно именно для MDX: перенос строки между inline/block HTML-узлами может влиять на markdown-парсинг и породить неожиданный paragraph boundary. В браузерном HTML такой whitespace часто безразличен, а в смешанном Markdown+HTML формате уже нет.

Итоговая реализация

Логика собрана в helper cleanupOldContent, который работает как отдельный normalization layer между legacy CKEditor HTML и новой Concept/Markdown-системой:

import * as cheerio from 'cheerio'
import { rehype } from 'rehype'
import { normalizeMarkdownContent } from '../../KBConcept/helpers/normalizeMarkdownContent'

function replacePWithDiv(html: string): string {
  const $ = cheerio.load(html, { xml: false }, false)

  $('p').each((_, el) => {
    const $el = $(el)
    const div = $('<div></div>')
    div.html($el.html() || '')

    for (const attr of el.attributes) {
      div.attr(attr.name, attr.value)
    }

    $el.replaceWith(div)
  })

  return $.html()
}

export async function cleanupOldContent(html: string): Promise<string> {
  html = html.replaceAll(/<u>([^<]+)?<\/u>:/g, '<u>$1:</u>')
  html = replacePWithDiv(html)

  try {
    const normalized = await rehype()
      .data('settings', {
        fragment: true,
        closeSelfClosing: true,
      })
      .process(html)

    html = String(normalized).replace(/>\s+</g, '><')

    return await normalizeMarkdownContent(html)
  } catch (error) {
    console.error(error)
    console.error('cleanupOldContent html', html)
    throw error
  }
}

Архитектурный вывод

Этот случай показывает, что локальный compatibility-layer для BiznesHelper должен нормализовать не только Markdown whitespace, но и embedded legacy HTML до того, как контент попадёт в MDX/SSR pipeline.

То есть фактический путь импорта сейчас выглядит так:

legacy CKEditor HTML
→ DOM-level cleanup
→ HTML normalization через rehype
→ whitespace normalization
→ общий normalizeMarkdownContent
→ сохранение Concept

Это полезное разделение ответственности: браузерно-терпимая, но нестабильная legacy-разметка исправляется один раз на входе, а не компенсируется бесконечно в публичном renderer-е.

Статус

Конкретный кейс с переносами между тегами и self-closing HTML сейчас закрыт локальным normalization helper-ом. Общая проблема совместимости MDXEditor / Markdown renderer остаётся предметом отдельной R&D-задачи в haih-agent.

Добавить локальный Markdown compatibility-компонент

9 сент. 2026 г.

Legacy HTML normalization: замена <p> на <div> при импорте

При переносе старого контента обнаружился ещё один конфликт между legacy WYSIWYG-разметкой и новым React/SSR-рендерингом. Старый редактор оборачивал большие фрагменты HTML в <p>. В новой версии такой импортированный HTML может оказаться внутри уже существующего параграфа, из-за чего React получает невалидную HTML-структуру и предупреждает:

In HTML, <p> cannot be a descendant of <p>. This will cause a hydration error.

Причина

Проблема не в конкретном тексте, а в семантике тега <p>: HTML не допускает вложенные параграфы. Legacy WYSIWYG использовал <p> как универсальную блочную обёртку, хотя для произвольного вложенного содержимого безопаснее нейтральный контейнер вроде <div>.

При SSR это особенно неприятно: браузер может самостоятельно исправить невалидную HTML-структуру не так, как её ожидает React, и итоговая DOM-структура после парсинга отличается от серверной разметки. Это приводит к hydration mismatch/error.

Принятое решение

В импортер добавлен helper на cheerio, который до сохранения legacy HTML заменяет все <p> на <div>, сохраняя внутренний HTML и атрибуты:

import * as cheerio from 'cheerio'

export function replacePWithDiv(html: string): string {
  const $ = cheerio.load(html, { xml: false }, false)

  $('p').each((_, el) => {
    const $el = $(el)
    const div = $('<div></div>')
    div.html($el.html() || '')

    for (const attr of el.attributes) {
      div.attr(attr.name, attr.value)
    }

    $el.replaceWith(div)
  })

  return $.html()
}

Почему нормализация выполняется в импортере

Это legacy-специфичная проблема исходных данных, поэтому безопаснее исправлять её на входе в новую систему, а не заставлять общий Markdown/React renderer постоянно компенсировать старую WYSIWYG-разметку.

Импортер здесь выполняет роль normalization layer: сохраняет смысл старого содержимого, но убирает структуру, которая заведомо конфликтует с валидным HTML и React hydration.

Значение для общей Markdown-задачи

Этот случай дополняет проблему с whitespace/indentation: новый pipeline должен учитывать не только Markdown-синтаксис, но и качество embedded HTML. Даже если Markdown формально один и тот же, legacy HTML внутри него может иметь структуру, которую разные parser/renderer-цепочки обрабатывают по-разному.

Локальное решение остаётся частью BiznesHelper compatibility-слоя до появления более общего normalization/validation pipeline в haih-agent.

Добавить локальный Markdown compatibility-компонент

9 сент. 2026 г.

Коммерческая упаковка будет строиться поверх AI-driven content

Переработка услуг и кейсов больше не требует отдельной специализированной контентной модели. После импорта они остаются обычными Concepts, а AI используется как редактор: помогает структурировать старые материалы, убрать повторы, яснее показать решаемые проблемы и связать услуги с релевантными кейсами и экспертными материалами.

Важно сохранять фактическую основу старого контента и не превращать AI-редактуру в генерацию неподтверждённых маркетинговых утверждений. Цель — сделать реальную экспертизу понятнее и доступнее.

Перепаковать публичную структуру услуг и кейсов

9 сент. 2026 г.

Задача закрыта как неактуальная

Ошибка старого sitemap с www зафиксирована как legacy-дефект, но отдельно исправлять её в Ruby-версии больше нет смысла. После перехода старый сайт не будет продолжать жить параллельно с новой системой.

Канонический sitemap без www должен формироваться уже в haih-cms в рамках задачи нового SEO-слоя. Поэтому работа перенесена на целевую систему, а этот legacy-тикет закрыт.

Исправить URL в sitemap: убрать www

9 сент. 2026 г.

Задача закрыта как неактуальная

Исправлять сломанный Sunspot/Solr-поиск старого Ruby-сайта больше нецелесообразно. Legacy-сайт остаётся резервом и источником данных, а не системой для дальнейшей эксплуатации.

Вместо ремонта старого контура создана новая задача Реализовать поиск по Concepts. Новый поиск будет работать поверх единой целевой модели и сможет в дальнейшем развиваться в сторону семантического/AI-поиска.

Исправить поиск: legacy-сайт падает при поисковом запросе

9 сент. 2026 г.

FAQ включён в общую Concept-модель

Ремонт старого accordion/JavaScript-поведения больше не является целью. Каждый вопрос с ответом переносится как самостоятельный Concept с отдельным URL, а общий FAQ становится каталогом Concepts.

Таким образом FAQ перестаёт быть отдельной CMS-механикой и получает те же возможности, что остальной контент: единое редактирование, индексацию, AI-доработку и внутреннюю перелинковку.

Пересобрать раздел «Вопросы-ответы» на Concepts

9 сент. 2026 г.

Уточнение объёма переноса

Принято решение перенести в Concepts весь полезный старый контент bizneshelper.ru, а не только ограниченный набор страниц. Legacy-структура хранения при этом не сохраняется как целевая архитектура.

Первичный импорт нужен для сохранения фактов и исторического материала. Качество финальной подачи будет повышаться уже после переноса через отдельный AI-процесс: переработка текста, структура, форматирование, актуализация и внутренняя перелинковка.

Перенести весь полезный legacy-контент в Concepts и медиа

9 сент. 2026 г.

Корректировка архитектуры публичного слоя

После решения унифицировать содержательные данные вокруг Concept задача рендеринга также упрощается: не требуется автоматически воспроизводить отдельный шаблон под каждый legacy-тип сущности. Базовым должен стать универсальный renderer Concept, а специализированные представления добавляются только при реальной пользовательской необходимости.

Это уменьшает количество кода, который должен сопровождаться, и позволяет AI-generated/AI-updated content публиковаться через общий механизм.

Сделать универсальный рендеринг и маршрутизацию Concepts

9 сент. 2026 г.

Прогресс: подтверждён подход к импорту через схлопывание legacy-полей

На импорте admin_experiences уже практически реализован целевой паттерн: множество специализированных полей старой записи (customer, problem, solution, result, review, comment и др.) используются как исходные данные, но не превращаются в такие же поля новой схемы. Они собираются в единое первичное содержимое Concept.

Исторический URL при необходимости обслуживается отдельным RedirectRule, то есть совместимость маршрутов не загрязняет контентную модель.

Следующий этап — распространить тот же принцип на остальные содержательные legacy-таблицы и затем запускать отдельный AI-процесс переработки созданных Concepts.

Импортировать legacy-контент в Concepts и подготовить AI-обогащение

9 сент. 2026 г.

Прогресс: целевая модель определена концептуально

Анализ legacy БД подтвердил сильное дублирование контентной инфраструктуры: разные типы материалов разнесены по специализированным таблицам, при этом повторяют одинаковые возможности — текст, URL, SEO, публикацию, сортировку и т. п.

Принято целевое решение: содержательные сущности нового сайта по возможности сводятся к универсальному Concept. Различия между кейсом, услугой, FAQ, страницей, новостью и другими материалами выражаются содержанием, типом, URI, иерархией и связями, а не обязательным созданием новой таблицы и CRUD.

Такое решение рассматривается как основа для AI-driven content: чем меньше специальных схем должен понимать агент, тем проще массовая автоматическая редактура и дальнейшее развитие проекта.

Унифицировать контент bizneshelper.ru в модели Concept

9 сент. 2026 г.

Архитектурный поворот миграции: Concepts + AI-driven content

По итогам анализа legacy БД и практики других haih-проектов зафиксирован новый основной принцип миграции: весь полезный содержательный контент старого сайта переносится в максимально унифицированную модель Concept, а специализированные legacy-таблицы и поля не воспроизводятся на новой стороне без объективной необходимости.

Главный эффект такой модели — не только упрощение схемы. После первичного импорта контент становится пригодным для единого AI-pipeline: агент может получать исходные данные старой записи и новый Concept, а затем обновлять content, структуру, форматирование, подачу и внутренние связи через один и тот же контракт.

Это напрямую связано с более общим принципом, описанным в материале «Рост производительности специалистов требует развития технологической среды бизнеса»: ускорение работы специалистов и AI даёт реальный экономический эффект только тогда, когда сама система не создаёт лишнее архитектурное трение.

Для фиксации этого подхода создан отдельный публичный кейс: Унифицированные данные как основа AI-driven проектов — кейс VietnamGuru и BiznesHelper.

Миграция bizneshelper.ru с Ruby на haih-cms

9 сент. 2026 г.

Прогресс по Person на fi1osof.ru/about

Согласована актуальная структура JSON-LD для сущности Person на fi1osof.ru/about.

Зафиксированы ключевые решения:

  • @id и url используют единый адрес https://fi1osof.ru/about;
  • alternateName содержит Николай Ланец и Fi1osof;
  • image использует постоянный публичный URL;
  • jobTitle сейчас сформулирован как Systems Architect & AI Researcher;
  • description сфокусирован на systems architecture, AI-native product development, technology foresight и intelligent systems;
  • в sameAs должны оставаться только персональные профили, которые идентифицируют Николая Ланца / Fi1osof;
  • проекты нельзя смешивать с сущностью Person только потому, что они связаны с Николаем;
  • Freecode Academy — отдельный подпроект. Сам проект не является частью Person.sameAs. Персональный профиль внутри него допустим только если он действительно идентифицирует ту же персону;
  • knowsAbout используется для устойчивых областей экспертизы, а не случайного перечня библиотек.

Текущий вариант Person признан в целом корректным по структуре. Следующий этап этой задачи — внедрение и проверка серверного HTML/валидаторов.

Связать профессиональную идентичность Николая Ланца с реализованными проектами через JSON-LD

Написать мне