Сайт, которым клиент управляет сам: шесть Google-таблиц вместо админки
Кейс сайта детского медиа-кэмпа ТЕЛЕМОРЕ: переезд боевого домена без секунды простоя, контент в шести Google-таблицах вместо CMS, отчёты о турах и раздел новостей, пререндер мета-тегов для SPA и отдельная история про боевую базу участников, которую нельзя было подключать к сайту.
Как туроператор детских медиа-туров ушёл с конструктора на собственную площадку, получил сайт, который ведёт сам, — и почему главным инженерным решением оказалась не архитектура, а отказ подключать одну таблицу.
Живой сайт: telemore.ru
Аудио-обзор кейса
Разговорный подкаст по материалам проекта — если удобнее слушать, чем читать.
Клиент и точка старта
ТЕЛЕМОРЕ — туроператор медиа-туров для подростков 11–17 лет. Две недели на Красной Поляне: съёмки, блогинг, сцена, звёздные гости. Не лагерь с кружком журналистики, а продукт со своей геймификацией — телекоинами, звёздным рейтингом и приложением тура в Telegram.
Сайт при этом жил на конструкторе. Каждая правка цены и каждая новая фотография шли через подрядчика: написать, дождаться, проверить. Продукт менялся быстрее, чем страница про него.

Задача формулировалась в три пункта:
- Собрать сайт, который продаёт туры, а не просто рассказывает о них.
- Перевезти боевой домен без потери трафика и заявок.
- Отдать клиенту инструмент, которым он управляет сам.
Переезд домена без секунды простоя
Обычный порядок переезда — сначала переключить DNS, потом выпускать сертификат — даёт окно в несколько минут или часов, когда сайт открывается с предупреждением о небезопасном соединении. Для сайта, куда родители заходят решать про ребёнка, такое окно недопустимо: доверие теряется мгновенно и навсегда.
Поэтому порядок был обратный.
flowchart TB
A["Сертификат выпущен заранее<br/>(проверка по DNS, не по HTTP)"] --> B["Сервер готов и отвечает<br/>по будущему адресу"]
B --> C["Переключение A-записи домена"]
C --> D["MX и проверочные записи<br/>не тронуты"]
C --> E["Старые адреса → постоянные<br/>перенаправления на новые разделы"]
D --> F["Почта и рассылка<br/>работают без паузы"]
E --> G["Позиции в поиске сохранены,<br/>посетители попадают куда шли"]
Сертификат выпустили до переключения — через проверку по DNS, а не по HTTP: она не требует, чтобы домен уже указывал на новый сервер. Почтовые записи и подтверждения владения доменом не трогали, поэтому рассылка и привязки к сервисам не заметили переезда вовсе.
Отдельная работа — старые адреса. До этого они отдавали копию главной страницы под своими URL: человек из поиска попадал не туда, куда шёл, а поисковик видел дубликаты. Настроили постоянные перенаправления на подходящие разделы нового сайта.
Прежний сайт сохранён целиком отдельной архивной копией: 186 файлов, полностью автономных — ничего не тянется со сторонних серверов. Если завтра конструктор закроет аккаунт, история проекта останется.
Простоя при переезде — ноль секунд.
Почему шесть Google-таблиц, а не CMS
Самое частое возражение: «почему не поставили нормальную админку». Отвечаю честно — потому что админка здесь проиграла бы таблицам по всем пунктам, которые важны клиенту.
| Раздел | Что клиент меняет сам |
|---|---|
| Туры и цены | цена, даты, обложка, описание, отметка «мест нет» |
| Новости | заголовок, текст, видео, автор с фотографией |
| Отзывы | текстовые и видео |
| Команда | имя, роль, опыт, фото |
| Работы участников | ролики с обложками |
| Дни рождения | блок именинников на главной |
Сайт читает таблицу как CSV по публичной ссылке. Правка появляется после обновления страницы — пересборка не нужна.
Вот как эти таблицы выглядят изнутри — обычные листы, которые клиент открывает с телефона.
Три причины выбора. Первая: клиент уже умеет работать в таблицах — учить нечему, инструкция помещается в одну строку. Вторая: нет базы, которую нужно бэкапить, и панели, которую взломают через полгода. Третья: таблицей можно управлять с телефона в дороге, между сменами, не открывая ноутбук.
Одна деталь, без которой всё это не работало бы на практике: ссылку с Google Диска в колонке с фотографией сайт сам приводит к прямому адресу. Иначе клиент вставлял бы обычную ссылку «поделиться», видел битую картинку и не понимал почему.
Что если таблица недоступна. Если Google не отвечает или лист пуст, сайт берёт данные из репозитория и рисует страницу как обычно. Единственная точка отказа в такой схеме — внешний сервис, и она закрыта резервом.
flowchart LR
A["Клиент правит<br/>Google-таблицу"] --> B["Сайт читает CSV<br/>по публичной ссылке"]
B -->|"данные получены"| C["Страница собирается<br/>из таблицы"]
B -->|"нет ответа или пусто"| D["Резервные данные<br/>из репозитория"]
D --> C
C --> E["Обновление страницы —<br/>правка видна"]

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

Внутри отчёта — пронумерованные моменты смены с живыми кадрами, а не стоковые обещания.

Telemore NEWS — раздел в тёмной теме со своей вёрсткой: лента, внутренние страницы записей, автор с аватаркой. Видео вставляется обычной ссылкой с Kinescope, YouTube, VK или Rutube — клиенту не нужно знать, чем они отличаются.

Блог, страницы продюсеров и отдельные страницы туров — с прогревом и кросс-ссылками между разделами: из новости можно уйти в тур, из отчёта — в ближайшую смену.
Инженерные решения, о которых стоит рассказать
Три анимации на одном элементе. У иллюстраций в шапках три независимых движения: появление снизу, бесконечное покачивание и параллакс при прокрутке. Все трое хотят менять transform, и последнее переписывает предыдущие. Развели по слоям: обёртка отвечает за позицию и параллакс, вложенная картинка — за покачивание, а появление сделано через отдельное свойство translate, которое применяется независимо от трансформаций.
Параллакс, который не дёргается. Смещение пишется в CSS-переменную из обработчика на requestAnimationFrame с пассивным слушателем и перестаёт считаться, когда шапка ушла дальше полутора экранов. Прокрутка остаётся плавной на слабых телефонах.
Пререндер мета-тегов. Одностраничное приложение отдаёт краулерам пустую разметку — ссылка в мессенджере выглядела бы как голый адрес. На сборке генерируются статические страницы с уникальными og-тегами, поэтому ссылка на тур или отчёт в Telegram и VK показывает правильные заголовок, описание и картинку.
Медиа в облаке. Файлы лежат в Google Cloud Storage, nginx проксирует их как /media/* — тот же приём, что и у этого блога. Видео сжимается для веба и грузится лениво, только когда карточка подходит к экрану.
Все анимации уважают системную настройку «уменьшить движение» — при ней движение выключается полностью.
Заявка приходит туда, где команда и так сидит. Форма с сайта и лид-магнит отправляют заявку в Telegram-группу отдельной темой: имя, телефон, выбранная смена, возраст ребёнка и источник — форма это была или бот. Никакой CRM, куда надо заходить: менеджер видит заявку в том же приложении, где переписывается с родителями.

Телефоны на скриншоте скрыты по той же причине, по которой ниже мы не подключили к сайту базу участников.
Таблица, которую нельзя было подключать
Самое важное решение в проекте оказалось не техническим.
Для блока «Дни рождения» клиент прислал ссылку на таблицу. В ней была боевая база: 179 участников с фамилиями, датами рождения, телефонами, Telegram-аккаунтами и почтами. Таблица была открыта по ссылке — скачивалась без авторизации кем угодно.
Сайт читает таблицы анонимно. Подключить эту — значит сделать контакты детей общедоступными: любой посетитель, открывший исходный код страницы, получил бы ссылку на полный список.
flowchart TB
A["Прислана таблица<br/>для блока «Дни рождения»"] --> B{"Что внутри?"}
B --> C["179 участников:<br/>фамилии, телефоны,<br/>почты, Telegram"]
C --> D["Подключить как есть?"]
D -->|"нет"| E["Отдельная таблица-витрина:<br/>имя, день и месяц,<br/>тур, отряд"]
E --> F["Боевая база остаётся закрытой,<br/>клиент правит витрину,<br/>сайт читает витрину"]
C --> G["В отчёте отдельно:<br/>проверьте доступ<br/>к основной базе"]
Вместо подключения собрали отдельную таблицу-витрину: имя, день и месяц рождения, тур, отряд. Без фамилий, года рождения и контактов. Боевая база остаётся закрытой, клиент правит витрину, сайт читает витрину. В отчёте о работах отдельным пунктом попросили проверить настройки доступа к основной базе — она была открыта задолго до нас и продолжила бы утекать без всякого сайта.
Похожая развилка была с фотографиями звёздных гостей: на присланных кадрах гость снят вместе с участниками, и кто из них кто — по снимку не определить. Подписать карточку именем наугад, когда в кадре несовершеннолетние, нельзя. Работу остановили и уточнили у заказчика — это дольше, но единственно правильно.
Правило, которое я вынес из проекта: если данные попадают в публичный источник, вопрос не «удобно ли», а «что увидит посторонний». Витрина вместо базы — дешёвое решение, которое снимает риск целиком.
Что получил клиент, кроме сайта
Отчёт о работах — отдельная страница простым языком: что сделано, чем можно управлять самому, какие данные нужны от клиента и какие вопросы к нему остались. Показывается заказчику как есть, без пересказа менеджером.

Документацию для следующего разработчика: устройство деплоя, работа с таблицами, форматы медиа, предупреждения на будущее — вплоть до отдельного абзаца «не подключайте сюда боевую базу участников».

Правила проекта в репозитории — всё, на чём обожглись по дороге: обходной путь при протухшем токене облака, необходимость менять имя файла при замене картинки из-за годового кеша, конфликты анимаций. Следующий человек не потратит на это свои два дня.
Презентация проекта
Цифры
| Показатель | Значение |
|---|---|
| Секунд простоя при переезде домена | 0 |
| Google-таблиц под управлением клиента | 6 |
| Разделов и типов страниц | 9 |
| Карточек гостей на живых кадрах | 13 |
| Опубликованных отчётов о турах | 4 |
| Файлов в архивной копии старого сайта | 186 |
Стек. Vite, React, TypeScript, CSS без фреймворков (собственные токены, палитра в oklch). Данные — Google Sheets как источник контента и статические файлы как резерв. Инфраструктура — nginx на VDS, Let's Encrypt с проверкой по DNS, Google Cloud Storage для медиа. Плюс пререндер мета-тегов на сборке, Яндекс.Метрика и лид-форма с уведомлениями в Telegram.
Что стоит забрать себе
Считайте не стоимость разработки, а стоимость правки. Сайт на конструкторе выглядел дешевле ровно до того момента, когда цену тура нужно поменять в сезон трижды. Каждая правка через подрядчика — это не только счёт, но и задержка в дни, пока страница врёт клиенту.
Инструмент управления выбирают под человека, а не под моду. Таблица — «несерьёзно» для разработчика и идеально для клиента, который в ней и так живёт. Хорошая админка, которой не пользуются, хуже плохой таблицы, которой пользуются каждый день.
Резерв важнее красоты. Внешний источник данных обязан иметь запасной вариант: сайт не должен ломаться из-за чужого сервиса.
Про данные решайте до, а не после. Один вопрос «что увидит посторонний» сэкономил проекту репутационную катастрофу — и стоил одного дополнительного листа в таблице.
Как ваш сайт выглядит для человека, который видит его впервые, — бот разберёт по пунктам: что мешает и где теряется внимание.
👁 Разобрать мой сайт глазами клиентаБесплатно, в Telegram-боте @uspeshnyybot
Следующий шаг: если ваш сайт тоже правится через подрядчика и каждая мелочь стоит переписки — напишите мне в Telegram, посмотрим, что из этого можно отдать вам в руки уже сейчас.
Читайте также
- Telemore в Telegram: как превратить смену медиа-тура в игру — продуктовая часть того же клиента: баллы, ачивки и рейтинг участников.
- Медиа сайта в Google Cloud Storage за Cloudflare — как устроена та же схема раздачи файлов, только для блога.
- Лендинг, который работает вместо менеджера — что происходит с заявками, когда сайт собран как инструмент продаж.












Комментарии
Войдите через Telegram, чтобы оставить комментарий:
Пока нет комментариев. Будьте первым.