Проекты05 / 05
Двадцатилетняя история промоутера переехала с темы на Drupal, которая всё ещё раздавала стили для IE6: три языка за двадцать дней коммитов, и в октябре 2026 архив по-прежнему пополняется на фронтенде, который в последний раз менялся в феврале 2024.
artforte.lv

- Клиент
- ART Forte, латвийская продюсерская компания
- Роль
- Разработка: сайт, контент-модель, CMS
- Период
- Сделано в январе 2023; фронтенд последний раз менялся в феврале 2024
- Стек
- Next.js, TypeScript, Strapi 4, PostgreSQL, S3, Vercel, Heroku
- Онлайн
- artforte.lv
ART Forte привозит в Латвию международную оперу, балет, театр и концерты, по собственным словам, с 2005 года. В архиве — первый концерт Анны Нетребко в Балтии и Хосе Каррерас в 2008 году.
В декабре 2022 эта история жила на сайте на Drupal, который всё ещё отдавал style.ie6.css, и на двух языках. Компании, работающей с международными продюсерами, нужно обратное.
Три задачи: рассказать посетителям, что идёт, и отправить их на нужную страницу билетов на их языке; показать двадцать лет постановок как архив, который можно листать; и отдать каждое слово на сайте, вплоть до подписей на кнопках, в руки клиента.
- 01
Публичный сайт на трёх языках
Латышский, английский и русский: одиннадцать маршрутов на каждом. Списки статические с окном регенерации в пять минут, детальные страницы рендерятся по запросу.
- 02
Контент-модель, а не самописная админка
Шесть типов контента в Strapi, 85 полей, из них 67 локализованы. Сама админка стандартная, намеренно: работа здесь в модели. Каждая подпись — поле в CMS, поэтому текст кнопки можно поменять на трёх языках без деплоя.
- 03
Событие, которое само уходит в архив
Предстоящие события и архив — одна таблица, разделённая по дате. На следующий день после показа событие переходит в архив, а место, дата, цена и кнопка Buy Ticket исчезают с его страницы. Никому ничего делать не нужно.
- 04
Ссылки на билеты по языкам
Запись на каждом языке ведёт на нужную страницу у билетного вендора. Ни чекаута, ни данных карт, ни остатков для синхронизации: вендор продолжает делать своё дело. Цена этого — воронку после клика не видно.
- 05
Двадцать лет, которые можно листать
88 записей на латышском, 86 на русском, 82 на английском, с 2006 по 2026 год. Перевод для каждой записи необязателен, поэтому постановка может существовать на одном языке и отсутствовать на другом, не оставляя дыры в сетке.
Как это устроено
Редакторы
- Strapiтри языка, 85 полей
- S3афиши и фото
Данные
- PostgreSQL
- Одна таблица Eventразделена по дате
Сайт
- Next.js на Vercel
- Регенерациякаждые 5 минут
Посетитель
- Афиша и архив
- Билетный вендордиплинк под каждый язык


То, что обычно не попадает в портфолио. Всё это было на самом деле, и всё это есть в истории коммитов.
Сбой 01
Одна картинка, четыре шлюза, 30 коммитов за пять дней
- Симптом
- Картинки, загруженные в CMS, показывались не всегда. Сюда за пять дней ушло 22% всех коммитов проекта, с заголовками «Fix Image url», «1», «2», «3», «final», откат на следующее утро, «4», «Hardcode domain url».
- Причина
- Единого бага не было. Фото проходит четыре независимо настроенных шлюза, и каждый отказывал по-своему: собственная политика безопасности админки, права объекта на S3, форма URL (фронт дописывал хост к URL, которые уже были абсолютными) и allow-list картинок в Next. Девять часов один конфиг читал
AWS_BUCKET, а другойAWS_BUCKET_NAME. Это прочтение по диффам; коммиты об этом молчат. - Решение
- Шлюзы исправлены по очереди, потом появился
ImageWithFallback: сломанная картинка показывает продуманную заглушку вместо битой иконки. Headless-стеки переносят отказы в стыки: каждая часть работала сама по себе, и ни один конфиг не отвечал за «фото появилось».
Сбой 02
Патч аналитики, отключивший React
- Симптом
- Коммит с заголовком «Fix ui», апрель 2023. Весь его дифф возвращает один элемент в
_document.tsx. - Причина
- Накануне вечером при добавлении Google Tag Manager вместе со сниппетом, который он заменял, был удалён
<NextScript/>. Этот элемент несёт данные для гидратации, поэтому React никак не мог подхватить HTML сервера: бургер, переключатель языка, Load More и форма рассылки были бы мертвы. Симптом говорил об интерфейсе, а причина была в маркетинговых инструментах. - Решение
- Одна строка, восстановлена через 19 часов 44 минуты. Сбой был бы некрасивым, но сайт бы не погас: страницы пререндерятся, так что контент и ссылки переживают отсутствие JavaScript. Ни один тест не мог бы этого поймать, потому что тестов не было.
Сбой 03
Архив, который год показывал 2008-й
- Симптом
- Блок архива на главной начинался с самых старых постановок, а не с последних. Wayback Machine это подтверждает: четыре постановки 2008 года в феврале 2023, те же четыре в июле, через день после крупного концерта.
- Причина
sort[0]=dateпо умолчанию сортирует по возрастанию. Это написано за одиннадцать дней до того, как попали исторические записи, когда порядок ещё не был виден. А выжило потому, что выглядит правдоподобно: стена великих имён 2008 года читается как кураторский выбор, а не как баг.- Решение
date:desc, через 372 дня. Чтобы баг на сайте с большим объёмом данных заметили, данные должны стать видимыми, а смотреть на них должен тот, кто их знает.
Сбой 04
Перевод — это строка, а не столбец
- Симптом
- Переключатель языка не мог попасть на нужный перевод детальной страницы. В новостях и архиве после смены языка на экране оставались карточки предыдущего языка.
- Причина
- Две ловушки. Strapi даёт каждому переводу свой числовой id, так что одна и та же постановка — это 398, 399 и 400. А Next не перемонтирует страницу при смене локали, поэтому
useStateхранит список на старом языке, хотя пропсы уже изменились. - Решение
- Переключатель читает локализации записи и подменяет id на id соседней. Списки сравнивают локаль прямо во время рендера и сбрасываются сами. Та же ловушка без перемонтирования снова встретилась на этом самом сайте, на первом экране и в чате.
Сбой 05
Последним коммитом стал процесс клиента в Instagram
- Симптом
- Карточки архива были сделаны горизонтальными. Загружаемые картинки незаметно сменились с 3861×2574 на 1080×1920, и имена файлов об этом говорили.
- Причина
- Команда начала делать один вертикальный постер для Instagram Stories и использовать его везде. Никто этого не решал; ассеты просто изменились под дизайном.
- Решение
- Новое соотношение сторон карточки в феврале 2024, последнее изменение кода фронтенда на сегодня. Последнее, что понадобилось коду, было не фичей. Ему нужно было вписаться в то, как сотрудники работают на самом деле.
- коммитов за 20 дней разработки7–26 января 2023, за 17 разных дней
- записей архива на LV, RU, ENживой подсчёт, 30 октября 2026; с 2006 по 2026
- языка вместо 2на старом сайте были латышский и русский
- полей CMS локализованошесть типов контента
- дня архив показывал 2008-йснимки Wayback против коммита с исправлением
- месяц между последним коммитом фронтенда и самой новой записьюс февраля 2024 по 1 октября 2026
Пульс проекта
Каждый коммит в репозиториях проекта на одной линии. Чем выше столбик, тем жарче было.
- Каркас и план на Firebase, проживший месяц
- Старт разработки: 114 коммитов за 20 дней
- «Fix ui»: патч Tag Manager
- Архив научился сортировать
- Последний коммит фронтенда: пропорции постера
- CMS переезжает на другой хостинг без единого изменения фронтенда
Контентный сайт окупается тем, как долго работает без вас. Отдайте слова в руки клиента, пусть устаревание берёт на себя модель данных, и сайт будет работать ещё годы после последнего коммита. Если вашему сайту нужен разработчик на каждое изменение, это решаемая проблема.
Или спросите о нём цифровой разум