Граница продукта 1.0
Статус: Pre-MVP. Не выпущен. Последнее обновление: 2026-08-27.
Основание: текущий код репозитория, целевые локальные тесты и канонические спецификации. Полного журнала приёмки на реальном Cloudflare или авторизованной приёмки портфеля из четырёх сайтов не существует. Релизные гейты определяет SPEC.md §11.
Продукт: headless CMS для определения структурированного контента и работы с ним, которая может сгенерировать автономный бэкенд, принадлежащий владельцу. Graduation выдаёт нормализованную схему Prisma, миграции, пригодные для ревью, сгенерированные маршруты со знакомой семантикой моделей/запросов Prisma и опубликованный контент в репозиторий, базу данных и среду выполнения, которыми владеет владелец. Сгенерированный бэкенд читает нормализованные таблицы и не имеет зависимости от Dee Wan во время выполнения.
Cloudflare — текущая платформа. Strapi — первый адаптер миграции. Ни то, ни другое не определяет аудиторию. Импорт помогает внедрению и переносимости; это не основной тезис продукта.
Каждая возможность находится ровно в одном списке: контракт 1.0, пилот под наблюдением или недоступно. «Недоступно» — это не обещание это сделать.
Контракт 1.0 — реализовано и проверено локально
Заголовок раздела «Контракт 1.0 — реализовано и проверено локально»Работа с контентом
Заголовок раздела «Работа с контентом»- Модели контента и поля, определяемые через UI: текст, форматированный текст, число, логическое значение, выбор, дата, медиа, JSON, связь и компонент.
- Проверки ломающих изменений перед применением определения модели.
- Многоязычный контент с настраиваемыми языками и политикой отката локали (fallback).
- Неизменяемые опубликованные снимки, история версий, восстановление и публикация/снятие с публикации.
- Прямой переход черновик/публикация и настраиваемый механизм процесса согласования (approval workflow).
- Необязательный режим ревью, выключенный по умолчанию, для каждого сайта отдельно. Переключатель находится на вкладке настроек General;
PATCH /api/sites/:idотказывает в его выключении, пока контент находится в состоянии ревью, и называет эти элементы. Когда режим включён, дашборд является очередью ревью — что ожидает, что этот вызывающий может сделать дальше, чего ожидает строка, которую он не может сдвинуть, и отдельно — что было возвращено. Когда режим выключен, дашборд показывает, что недавно изменилось. Ни в одном из случаев определения workflow не переписываются, поэтому сайт, который настроил свой, получает его обратно без изменений. - Восстановление несохранённой работы для обычного редактирования контента И для компоновщика страниц (page composer). Правка записывается в локальное хранилище браузера относительно серверной базовой версии, от которой она была взята, и предлагается обратно только относительно той же базовой версии, поэтому восстановление никогда не может молча перезаписать чужое сохранение. Покрывает упавшую вкладку, перезагрузку и освобождённый процесс; встроенная в приложение защита от ухода покрывает намеренную навигацию. В компоновщике базовой версией является id текущей версии страницы, а сохраняемая работа включает НЕПРИМЕНЁННОЕ ПРЕДЛОЖЕНИЕ — единственное на этом экране, что стоило вызова провайдера и для чего продукт намеренно не записывает версию. Локально в браузере и для каждого устройства отдельно: это не серверная непрерывность черновиков между устройствами.
- Компоненты, принадлежащие сайту, с необязательной общей библиотекой. Заданный
component.site_idозначает, что компонентом владеет один сайт и на этом сайте достаточноmodel:apply; NULL означает общую библиотеку, которую читает каждый сайт, а пишет только суперадминистратор. Уникальность действует в пределах владельца, поэтому два сайта могут каждый владеть своимhero. Сайт может сделать FORK общего компонента в себя. Форк — это ПЕРЕОПРЕДЕЛЕНИЕ НА ВЕСЬ САЙТ: он не переписывает ни одной строки, и каждое поле на этом сайте, уже ссылающееся на этот slug, после этого указывает на форк. Маршрут возвращает количество ссылок, которые он перенаправил, а UI сообщает о последствии до нажатия. Обычное создание, которое попало бы на общий slug, ПОЛУЧАЕТ ОТКАЗ, пока вызывающий не подтвердит переопределение. SLUG компонента НЕИЗМЕНЯЕМ после создания — через него на компонент ссылаются все поля, вложенные компоненты и пресеты, и нигде не хранится id, поэтому переименование молча перенаправило бы или осиротило бы каждую ссылку; имя остаётся редактируемым. Предупреждения о форке и защита от удаления учитывают ссылки ИЗ ОБОИХ источников: полей моделей и определений других компонентов. На компоненты везде ссылаются ПО SLUG, поэтому собственный компонент ЗАТЕНЯЕТ общий компонент с тем же slug — видимый набор сайта имеет уникальные slug, а затенённая ссылка не учитывается для общего компонента при его удалении. Применение импортированных определений компонентов разблокировано на уровне схемы и авторизации; часть импортёра, которая их записывает, НЕ реализована, и точность переноса компонентов не продемонстрирована. - Роли на уровне сайта и права доступа, ограниченные владельцем.
- Компоновка страниц в фреймворк-нейтральный структурированный документ. Ревизии используют обычное версионирование, правила публикации и откат. Это контракт контента, а не рендерер сайта.
Основная поставка отсоединяемого бэкенда
Заголовок раздела «Основная поставка отсоединяемого бэкенда»- Аутентифицированный
GET /api/models/public-client.tsвыдаёт TypeScript-клиент без зависимостей для одного сайта: точные поля моделей, union локалей, типы запросов, оболочку ответа и методы моделей. - Сгенерированный клиент генерируется повторно вручную после изменения модели. У него нет автоматического обнаружения расхождений или версионирования артефактов.
- Graduation выдаёт типизированный бэкенд, принадлежащий владельцу, и снимок контента, опубликованного на момент генерации. Сгенерированная среда выполнения отсоединена от Dee Wan и использует собственный bearer-токен.
- Процесс повторной генерации, управляемый CMS, координируется: он забирает определения и сообщает свой результат в Dee Wan. Полномочия во время выполнения и координация сборки разделены.
Мультиарендность и идентификация
Заголовок раздела «Мультиарендность и идентификация»- Несколько сайтов в одной инсталляции с явной областью сайта. Вызывающие не могут вывести арендатора или выбрать привязку базы данных.
- Логическая изоляция в общей начальной (bootstrap) базе данных.
- Сессии Better Auth в базе данных, начальное получение прав (bootstrap claim), владение паролем, восстановление, отзыв, блокировка и ограничения запросов.
- Необязательный периметр Cloudflare Access, выключен по умолчанию.
- Существующие учётные записи могут получать гранты на уровне сайта. Приглашения недоступны.
Публичное чтение
Заголовок раздела «Публичное чтение»- Отдельный Worker для публичного чтения. Сайт определяется по
Host, никогда по ID сайта, переданному вызывающим. - Чтение опубликованных снимков, строгая или fallback-политика локалей, пагинация по курсору, фильтры по связям/тегам и очистка кеша по cache-тегам при публикации.
- Публичным моделям не нужен токен. Приватные модели используют токены чтения в области сайта и не попадают в общий кеш.
- Привязка D1 у этого Worker доступна только для чтения по правилу код-ревью. У D1 нет настройки привязки только для чтения.
Медиа и ИИ
Заголовок раздела «Медиа и ИИ»- Хранилище R2 или Cloudflare Images, с конвертацией в WebP/AVIF.
- Генерация текста, перевод и генерация изображений через серверный прокси DeepInfra. Ключи провайдера не попадают в браузер.
- Почасовая квота на сайт. Другие провайдеры инференса не поддерживаются.
Переносимость и адаптеры миграции
Заголовок раздела «Переносимость и адаптеры миграции»- Переносимый бандл сайта Dee Wan и передача контента через CSV/XLSX.
- Первый внешний адаптер: инспекция архива Strapi v4/v5, явное сопоставление разделов (partition mapping), пробный прогон (dry run), возобновление, детерминированный повторный прогон, квитанции, проблемные строки, манифесты и защищённая отмена (undo).
- Неоднозначное владение в источнике блокирует пробный прогон. Импортёр не угадывает по именам, slug или URL.
- Реальные фикстуры портфеля, лимиты развёрнутого Worker и доказательство переключения/отката остаются работой приёмки.
Эксплуатация
Заголовок раздела «Эксплуатация»-
CLI: планирование установки, apply/resume, диагностика, проверка, манифест и teardown в режиме dry run.
-
Локальный браузерный установщик для разработчика, у которого уже есть Node, checkout и терминал.
-
История развёртываний и отказ в откате после деструктивной миграции.
-
Настройка исходящих вебхуков, подписанная история доставок, ротация секрета и ручной повтор.
-
Отчёты об ошибках. Необработанные ошибки отправляются в проект Sentry Dee Wan, из них предварительно удаляются контент, значения форм, email-адреса и учётные данные. Суперадминистратор отключает их для всего развёртывания в Settings → Integrations → Error reports; переменная Worker
DEEWAN_ERROR_REPORTING=offделает то же самое.
-
Ограниченный автоматический повтор для исходящих вебхуков. Доставка, которая не удалась по причине, которая могла бы пройти позже — нет ответа,
408,429, любой5xx, — повторяется по экспоненциальному расписанию с джиттером до пяти попыток с учётомRetry-After; отказ, который подписчик повторил бы, сразу является окончательным. Каждая попытка несёт один и тот же id события, поэтому дубликат, вызванный тайм-аутом, потребитель может распознать. Ожидающие попытки не учитываются в лимите истории доставок, а повтор отправляет в точности записанные байты, подписанные ТЕКУЩИМ секретом подписчика. Только локальное покрытие; доказательств на развёрнутой системе нет. -
Форматированный текст — это HTML от доверенного автора, и РЕНДЕРЕР ОБЯЗАН ЕГО САНИТИЗИРОВАТЬ. Его сгенерированный тип —
Html, никогда неSafeHtmlи никогда не обобщённыйJson, потому что ничто в этом продукте не санитизирует и не переписывает хранимую разметку. На единственной границе записи проверяются две вещи: значение должно быть СТРОКОЙ (не строка даёт структурированный 400 с указанием поля и полученного типа, никогда не строковое[object Object]), и оно должно занимать не более 256 KiB в UTF-8, считая в байтах. Всё, что создал допущенный автор или генерация ИИ, публикуется в авторском виде, поэтому потребитель, который вставляет это в страницу без санитизации, и берёт на себя риск. -
Единый раздел Delivery (Settings → Delivery). Живой read API CMS и бэкенд, прошедший graduation, представлены как два РАЗНЫХ контракта, с различиями в маршрутах, аутентификации, оболочке ответа, развёртывании, откате и зависимости от CMS, указанными до переключения. Раздел сообщает состояния: никогда не генерировался, актуален, расходится, собирается, сбой сборки/развёртывания и отсоединён, а список ревизий сохраняет собственный отказ в откате для каждой ревизии. Только локальное покрытие; доказательств на развёрнутой системе нет.
-
Версия сгенерированного артефакта и расхождение контракта. Идентичность артефакта — это версия генератора плюс детерминированный дайджест входного контракта, никогда не временная метка, поэтому неизменённый сайт, пересобранный изменённым генератором, отображается как расходящийся, а не актуальный. Развёртывание, которое не записало версию генератора, читается как расходящееся, а не как совпадающее. Повторная генерация остаётся явной: ничего не генерируется повторно и не развёртывается само по себе.
-
Административный журнал аудита. Кто изменил модель, компонент, роль, грант, токен сайта, настройки, инфраструктуру, имя хоста, или кто выполнил развёртывание и откат — записывается в управляющем слое (control plane), с разбиением по сайтам, как намерение, записанное ДО действия, и результат, записанный после, связанные одним id операции. Действие не выполняется, если его намерение не удаётся записать; если результат не удаётся записать, намерение сохраняется, а исход читается как UNKNOWN, а не как успех. Одно чтение за собственным правом доступа
audit:read, в Settings → History. Только добавление: маршрута записи не существует. Это не телеметрия — ни счётчиков, ни агрегатов, ни дашборда.
Пилот под наблюдением — реализовано локально, внешнее доказательство неполное
Заголовок раздела «Пилот под наблюдением — реализовано локально, внешнее доказательство неполное»- D1 контента на каждый сайт. Выбранная топология — одна управляющая D1 плюс одна D1 контента на каждый сайт. Разделение схемы, маршрутизация, провижининг, распространение миграций, резервное копирование/восстановление и teardown проверены локально. Доказательств на реальном Cloudflare, по ёмкости, резервному копированию/восстановлению и изоляции четырёх сайтов нет.
- Развёртывание graduation под управлением CMS. Получение прав (claim), токен сборки, процесс сгенерированного репозитория, линия миграций, отчёт в обратную сторону и управление откатом проверены локально. Ни одно сохранённое развёртывание GitHub Actions плюс Cloudflare не доказывает весь цикл.
- Полный путь установщика. Admin Worker и UI следуют обычному пути установки.
setupтакже ЗАПИСЫВАЕТbackend/wrangler.public.jsoncв тот момент, когда учётная запись, зона и id базы данных уже определены; он никогда не перезаписывает существующий файл и ОТКАЗЫВАЕТ С УКАЗАНИЕМ ИМЕНИ вместо того, чтобы угадывать значение, которое не может вывести. Ручная подготовка по примеру — это запасной путь для этого отказа, а не обычный путь. Без этого файлаdeployОТКАЗЫВАЕТ, а не пропускает шаг: инсталляция, которая намеренно не отдаёт публичный контент, заявляет об этом через--admin-only, и тогда прогон отображается как admin-only, а не как завершённый. Нет ни молчаливого пропуска, ни отката на публичную конфигурацию другой инсталляции. Открытым остаётся доказательство на развёрнутой системе, а не файл. - Маршрутизация предпросмотра. API хранит HTTPS-origin рендерера и шаблоны маршрутов для каждой модели, а редактор открывает возвращённый отрендеренный URL. Settings → Preview читает и записывает этот контракт, сообщает, что делает кнопка Preview у ненастроенного сайта, и называет каждый отказ. Без настроенного рендерера Preview открывает JSON-ответ публичного API, и экран об этом сообщает.
- Протокол удалённых плагинов v1 (сторона ядра). Установка из HTTPS-манифеста с выбранными вручную
грантами на возможности и модели, хешированные и ротируемые токены инсталляции, disable/enable/uninstall,
одноразовый делегированный запуск, чтение контента в пределах области и закреплённая команда publish/unpublish
(
SPEC-PLUGINS.md). Команда заново проверяет полномочия делегирующего человека в момент выполнения, применяется не более одного раза на ключ идемпотентности и ревизию workflow, публикует всю группу переводов и отвечает на каждый отказ именованным окончательным кодом. Только локальное покрытие; доказательств на развёрнутой системе нет. - Резервное копирование и восстановление. Реализовано и проверено на локальном SQLite. Не проверено на реальной D1.
- Миграция Strapi для четырёх сайтов. Общий путь адаптера существует. Авторизованных архивов, контрактов потребителей, проверенных разделов, staging, доказательств переключения и отката нет.
Позже / недоступно — не реализовано или отключено
Заголовок раздела «Позже / недоступно — не реализовано или отключено»- Рендерер-эталон для продакшена, стартовая тема и полный путь поставки SEO/sitemap/редиректов.
- Установщик без терминала или зарегистрированное OAuth-приложение Cloudflare.
- GitHub App; текущее подключение репозитория использует device flow.
- Приглашения, полностью. Неактивный механизм ссылок находится за
ENABLE_INVITATIONS; отслеживаемые конфигурации оставляют его неустановленным, и все маршруты приглашений отвечают 404. Проверенной доставки почты или шага подтверждения адреса не существует. - Массовые действия, сохранённые представления и согласованные релизы контента.
- Кадрирование медиа, фокальная точка и обработка дубликатов. ПОИСК медиа и фильтрация по alt-тексту реализованы.
- Назначения на ревью, комментарии и уведомления.
- Очередь вебхуков сверх описанного выше ограниченного повтора и любая гарантия доставки сильнее, чем at-least-once.
- Непрерывная синхронизация CMS с базой данных, прошедшей graduation.
- Редактирование точных копий или заблокированных секций в компоновщике страниц.
- Шардирование базы данных на уровне моделей.
- Корпоративный SSO, MFA и passkeys.
- Запланированные публикация и снятие с публикации в ядре. Планирование — это отдельный плагин Scheduling (
plugins/scheduling/), не развёрнутый.
Правда о поставке
Заголовок раздела «Правда о поставке»У Dee Wan две поверхности поставки для разработчиков:
- Публичный API CMS работает вживую. Публикация сразу обновляет чтение его снимков и очищает кеш по cache-тегам.
- Бэкенд, прошедший graduation, — это релиз схемы и контента. Он содержит то, что было опубликовано на момент запуска генерации. Более поздние публикации в CMS попадают в него только после явного повторного graduation и повторного развёртывания.
Не описывайте graduation как живой поток. Не описывайте локальное тестовое покрытие как релиз. Первое заявление о 1.0 требует, чтобы каждый открытый внешний и финальный гейт из SPEC.md §11 прошёл на одном конкретном коммите.