# Состояние Обновлено 15.10.2026. Статусы значат следующее: **работает** — есть в коде, покрыто тестами и доступно на polochka.app; **в коде** — реализовано и покрыто тестами, но на hosted-установке выключено или не проверено; **нет** — не реализовано. Где настройка шаблона `deploy/hosted` (`hosted.env.example`, `compose.yml`) и polochka.app расходятся, в строке указано и то и другое. | Область | Статус | Примечание | |---|---|---| | Вход по паролю, аккаунты от оператора | работает | Логины с паролем создаёт только оператор; открытая регистрация — по коду из письма (строка ниже) | | Первый администратор своей установки | в коде | `npm run admin -- account bootstrap <почта>`: аккаунт с подтверждённой почтой, администратор компании и одноразовая ссылка `/welcome#…` на час, без SMTP ([SIGN_IN_PROVIDERS](specs/SIGN_IN_PROVIDERS.md) § 11, миграция 074). Та же команда с `--no-admin` впускает человека, потерявшего способы входа | | Вход и регистрация по коду из письма | работает | Нужен SMTP (`MAIL_MODE=smtp`). Режим «по приглашению» (`EMAIL_SIGNUP=invite`, по умолчанию в шаблоне `deploy/hosted`): код только для привязанных аккаунтов и адресов из списка. На polochka.app регистрация открыта (`EMAIL_SIGNUP=open`) с потолком 50 новых полок в сутки и 3 с одного IP; письма — Yandex Cloud Postbox. Какие адреса могут открыть полку — строка «Почтовые домены новых полок». Верный код подтверждает адрес (`email_verified_at`) в любом режиме почты, локальный `MAIL_MODE=local` тоже | | Публичные страницы: главная, «Для компаний», тарифы, вход и регистрация | работает | С 0.7.3–0.7.4 одна шапка (`widgets/site-header`) и светлый фон; главная с макетом продукта в первом экране; пустая полка показывает три карточки «с чего начать». Вид на телефоне (390 px) проверен 02.10.2026 по снимкам боевого сайта: переполнения по ширине нет | | Полка: папки, поиск, переименование, перенос | работает | | | Письма автору о ссылке на проверке | работает | [LINK_REVIEW_LETTERS](specs/LINK_REVIEW_LETTERS.md). Автор получает письмо, что ссылку проверяют, и письмо, когда её одобрили; у владельца на работе видно, с какого времени; экран получателя сам откроет работу после одобрения. Причины проверки в письме нет. Миграция 053 | | Счётчик открытий ссылки | работает | [LINK_OPENS](specs/LINK_OPENS.md). Автор видит в панели ссылки, сколько раз её открыли и когда в последний раз, без сведений о читателе; себя не считает. Миграция 052 | | Удаление работы навсегда | работает | [WORK_DELETION](specs/WORK_DELETION.md). «Удалить навсегда» в корзине стирает все версии объектов, текст поиска и обложку, возвращает место, закрывает ссылки; строки остаются надгробиями. Отказывает, если на работу есть жалоба или решение модерации либо она в Ленте или библиотеке шаблонов. Миграция 051 | | Видео в проектах | работает | [PROJECT_VIDEO](specs/PROJECT_VIDEO.md). MP4 и WebM в проекте: до 200 МБ на файл и 400 МБ на проект сверху к 48 МБ страниц. Загрузка потоком в S3 (`PUT /api/v1/projects/:uploadId/media/:index`), просмотр с `Range`. Включается оператором для полки (`tenants.video_enabled`, миграция 050), потому что видео не проходит фильтр | | Проекты: связанные страницы одной работой | работает | [PROJECTS](specs/PROJECTS.md). Папка документов, HTML-экранов и картинок — одна работа: до 400 файлов и 48 МБ, дерево страниц, markdown с разрешёнными ссылками, ссылки внутри проекта, ссылка получателю. `POST /api/v1/projects` и CLI `polka-publish-project.mjs`. Нужен домен просмотра. Агент по MCP получает токен для CLI сам (`polka_project_upload`, 30 минут, только загрузка проектов). Страницы с React, Babel или Tailwind с CDN и с module-скриптами открываются собранными с 0.14.0 (`pagesNotBuilt` в ответе называет те, что не собрались). Один текстовый файл проекта правится патчем (`polka_revise` с `edits` и `path`), несколько файлов и картинки — `polka_change_files`, остальные хранилище копирует само. `polka-pull.mjs` скачивает версию в папку, повторная публикация папки сохраняет следующую версию и отправляет только изменённые файлы. На polochka.app с 26.09.2026 (миграции 043 и 046) | | Поиск по тексту работ | работает | [CONTENT_SEARCH](specs/CONTENT_SEARCH.md). Миграция 041 (`artifact_search`). На полке и в `polka_list`: по названию и тексту последней версии (видимый текст страницы, JSX пакета, текст, ссылка), префиксы слов, фрагмент с найденными словами. Уже сохранённые работы — `npm run admin -- backfill search`. На polochka.app с 26.09.2026, старые работы проиндексированы. В коде: индекс по полкам, сохранённый вектор названия и тип последней версии на работе (миграция 075), счётчики по типам тем же запросом, что и страница; запрос из одних стоп-слов по тексту ничего не находит | | Версии: неизменяемые, SHA-256, CAS | работает | | | Сравнение версий (построчный diff исходника) | работает | Во вкладке «Версии»: две версии, добавленные и удалённые строки, неизменённые свёрнуты. Читает те же маршруты владельца, что «Скачать оригинал»; у пакета — главная страница и список изменённых файлов. Считается в Web Worker: не больше 50 000 строк на сторону, дальше 2 500 отличий — замена целиком, показ до 2 000 изменённых строк. Изображения и двоичные файлы не сравниваются. | | Превью ссылок (Open Graph) | работает | Сервер добавляет `og:*` и `twitter:*` в оболочку приложения, адреса из `APP_ORIGIN`. `/s` — одна общая карточка «Полка — вам отправили страницу»: токен в `#`, краулер его не видит, и название работы в превью не попадает. Остальные страницы — карточка Полки. Картинки 1200×630: `docs/assets/og/*.svg` → `node scripts/render-og-images.mjs`. В Telegram/Slack ещё не проверено | | Корзина и восстановление | работает | В интерфейсе и через MCP (`manage`); приёмка настоящими Claude Code и Codex 09.10.2026 ([AGENT_MANAGE_ACCEPTANCE](dev/AGENT_MANAGE_ACCEPTANCE.md)) | | Загрузка файла: HTML, текст, PNG/JPEG/WebP до 5 МБ | работает | | | Markdown, CSV и JSON — работы из одного файла | в коде | [SINGLE_FILE_FORMATS](specs/SINGLE_FILE_FORMATS.md), часть #46. С компьютера, `polka_publish`/`POST /api/v1/publish` с `kind: "file"` и `polka-publish.mjs`. Markdown — свёрстанный документ, CSV — таблица (до 2 000 строк), JSON — код; страница только с домена просмотра, без него — текст файла. Поиск, фильтр, контекст агента, перенос полки | | PDF — работа из одного файла | в коде | Unreleased, [SINGLE_FILE_FORMATS](specs/SINGLE_FILE_FORMATS.md#pdf), часть 2 #46. С компьютера, `kind: "file"` с `base64` и `polka-publish.mjs`; до 5 МБ, без пароля, pdf.js должен открыть файл (иначе 422). Показ — pdf.js с домена просмотра, страницы по мере прокрутки, скрипты и формы PDF не выполняются; без домена просмотра — карточка «Скачать PDF» для владельца, ссылка не выпускается. Текст pdf.js — в поиск, фильтр, модели-ревьюеру, обложку («Документ») и агенту (`source.pdf` и `source.txt`); ссылки PDF проверяются на фишинг как ссылки страницы. Ссылки внутри PDF не кликабельны, комментарии — на всю работу | | «Вставить код» (HTML/JSX) | работает | | | Ссылки: срок 1/7/30 дней, отзыв, жалобы | работает | Ссылка привязана к версии | | Статичный просмотр HTML в песочнице | работает | CSP без скриптов и сети | | Статичный просмотр с домена просмотра, внешние ссылки через «Вы уходите с Полки» | работает | С настроенным viewer страница отдаётся только с него (`/static/:token`), домен приложения пользовательский HTML не отдаёт; ссылки ведут на подписанную страницу `/away`. | | Интерактивный просмотр на отдельном домене | работает | `HTML_LIVE_MODE=production`, polochka.page | | React runtime `react-runtime-v1` | работает | 10 библиотек и Tailwind v4, без сети | | Плагин Полки для Claude Code и Codex | работает | Исходники плагина — в этом репозитории: `.claude-plugin/`, `.codex-plugin/`, `.agents/plugins/`, `.mcp.json`, `skills/*` ([connect-agents](connect-agents.md#плагин-полки-для-claude-code-и-codex)). Ставится из лёгкого репозитория [artkruglov/polka-plugin](https://github.com/artkruglov/polka-plugin) (с 27.09.2026), его собирает `scripts/plugin-repo.mjs`. 25.09.2026 установка с GitHub проверена в пустом профиле Claude Code: сервер `plugin:polka:polka` и скиллы `polka`, `polka-organize` видны | | Главная полка: «Подключите агента» | работает | Вместо поля ссылки — блок с переключателем Claude / Claude Code / Codex / Другой MCP-клиент; с подключённым агентом — одна строка. Unreleased (миграция 077, [ONBOARDING_V2](specs/ONBOARDING_V2.md#решения-владельца-15102026)): блок видят только полки младше 30 дней или с меньше чем 3 работами; «Скрыть» хранится в аккаунте и действует во всех браузерах; после «Разрешить» на странице согласия полка в другой вкладке узнаёт о подключении сразу, опрос раз в 8 с остаётся запасным | | Кто сохранил работу | в коде | Unreleased: `Artifact.savedBy` из журнала `revision.saved` — «Сохранил Codex» на карточке, «Сохранил Codex» / «Сохранили вы» в «О работе» для последней версии | | Пример за 10 секунд на `/start` | работает | Статичная страница «Пример: итоги недели». Unreleased: при `liveMode=production` (polochka.page) — интерактивный пример с переключателем недель (профиль `limited`) | | MCP для Claude Code и Codex | работает | Одной командой через OAuth: Codex CLI 0.153.4 проверен на polochka.app 23.09.2026 (вход и вызов `polka_context`); Claude Code — команда добавлена, вход не проверен. По токену — для остальных клиентов | | Коннектор Claude.ai / ChatGPT (OAuth 2.1, `polka_publish`) | работает | Покрыт интеграционными тестами. Claude.ai: сохранение и ссылка проверены 22.09.2026; отзыв подключения и ChatGPT ещё не проверены ([приёмка](MCP_CONNECTOR.md#приёмка-после-выкладки)). На странице согласия для своей полки по умолчанию отмечены все разрешения, включая `sign_in` (решение владельца 25.09.2026); для полки отдела — только чтение и сохранение (16.10.2026); любое можно изменить | | HTTP API `POST /api/v1/publish` и CLI | работает | Копия CLI из репозитория требует `POLKA_ENDPOINT` или `--endpoint` | | Обнаружение агентом: `/llms.txt`, `/openapi.json`, `/.well-known/agent-skills`, скилл `polka` | работает | [connect-agents](connect-agents.md#агенту-без-подсказок-llmstxt-openapi-скилл). Скилл отдельно: `npx skills add artkruglov/polka-plugin` | | Библиотеки шаблонов: роли, приглашения, журнал | работает | Приглашённому уходит письмо со ссылкой (не больше 20 в сутки от администратора и 3 на адрес); ссылку можно и скопировать | | «Лента»: 14 интерактивных материалов Редакции | работает | Каталог курирует оператор; авторских публикаций нет. Полка отдела может предложить работу, оператор решает (в коде, [DISCOVER_V2](specs/DISCOVER_V2.md) 5а) | | Импорт по URL (standalone HTML, Gist через API) | в коде, эксперимент | `URL_IMPORT_ENABLED`, выключен по умолчанию и на polochka.app; в веб-интерфейсе поля для ссылки нет (строка «Импорт ссылок Claude/ChatGPT»). Gist — через `api.github.com`, `GITHUB_TOKEN` необязателен | | Рендерер: снимки SPA-сайтов, ChatGPT share, одна попытка Claude | в коде | `RENDERED_IMPORT_ENABLED`, выключен. Отдельный сервис [apps/renderer](../apps/renderer) ([развёртывание](../deploy/renderer/README.md), [spec](specs/URL_IMPORT_SUPPORT.md#рендерер)). Проверен локально на настоящих ссылках 24.09.2026; на polochka.app не развёрнут. Fly.io — после правки политики и уведомления РКН о трансграничной передаче | | Обложки-снимки визуальных работ | в коде | [SHELF_COVERS](specs/SHELF_COVERS.md): `COVER_SNAPSHOTS_ENABLED`. На polochka.app с 12.10.2026 временно выключены: при переезде в зону `ru-central1-d` VM рендерера удалена ради квоты (снимок диска сохранён, #33). Работали с 10.10.2026, рендерер на отдельной VM в Yandex Cloud `ru-central1` (страницы не покидают Россию), по внутреннему адресу и TLS с собственным сертификатом; песочница Chromium включена ([deploy/renderer](../deploy/renderer/README.md#yandex-cloud)). Снимок тестовой страницы с прода — 1,4 с. Импорт SPA по ссылке через этот рендерер не включён (`RENDERED_IMPORT_ENABLED=false`) | | «Сохранить как ссылку» | в коде | [SAVED_LINKS](specs/SAVED_LINKS.md): работа-закладка для того, что нельзя скопировать; MCP `polka_save_link` | | Импорт ссылок Claude/ChatGPT | эксперимент, в интерфейсе нет | С 25.09.2026 веб-интерфейс не предлагает сохранение по ссылке: поле на полке, карточка ссылки AI-сервиса на «Сохранить», подсказки про расширение и закладку убраны. Сервер (`apps/server/url-import`, рендерер) и MCP (`polka_import_url`, `polka_save_link`) не менялись. См. [FAQ](faq.md#почему-нельзя-вставить-ссылку-на-артефакт-claude-или-chatgpt) | | Расширение браузера «На Полку» | в коде, не публикуется | Решение владельца 12.10.2026: расширение не нужно, в Chrome Web Store не публикуем. Код готов ([extensions/chrome](../extensions/chrome/README.md)): кнопка на странице артефакта Claude, OAuth с PKCE. В Chrome Web Store не опубликовано, вручную на своём аккаунте Claude не проверено; интерфейс Полки его не предлагает. Серверная часть (имя расширения на странице согласия, приём `Origin` расширения в HTTP API) выложена на polochka.app 24.09.2026 | | Закладка «На Полку» | есть, без ссылок из интерфейса | `/bookmarklet` и `/bring/receive` открываются по прямому адресу, код в [extensions/bookmarklet](../extensions/bookmarklet/src/main.ts): читает артефакт в браузере пользователя без расширения и передаёт во вкладку Полки через `postMessage`. Покрыто тестом на синтетических страницах в Chrome (`tests/bookmarklet.test.ts`); на настоящем claude.ai и в Safari/Firefox не проверялось | | Перенос полки в свою установку | работает | [SHELF_TRANSFER](specs/SHELF_TRANSFER.md), 0.9.0. Выгрузка всей личной полки со всеми версиями и корзиной: `GET /api/v1/export` и `polka-export.mjs` (права `read` и `source:read`), раздел «Настройки» → «Перенести полку». Импорт — команда оператора `npm run admin -- shelf import`: версии с номерами и датами, папки, принятая версия, ответственный, карточка, корзина; повторный запуск продолжает с места; принятие и уход в корзину пишутся в журнал с исходным временем (снимок полки на дату). Не переносятся ссылки и комментарии; работа с заблокированной версией пропускается. На polochka.app с 03.10.2026 (0.9.0). Проверено 06.10.2026 на настоящей полке: выгрузка с polochka.app (52 работы, 97 версий, 276 файлов, 515 МБ с видео; повтор ничего не скачал) и импорт на другую установку за 41 с — все работы, номера, даты и суммы версий, папки, корзина и карточка совпали, 464 файла прочитаны с верными SHA-256. Фильтр содержимого новой установки изолировал 2 тестовые страницы проверки egress (`malicious_code`): импорт идёт обычным путём сохранения | | Точки расширения: вход и учёт сотрудников | в коде | 0.15.0, миграция 072, [EXTENSIONS](specs/EXTENSIONS.md#вход-и-учёт-сотрудников-sso-scim). Отключение оператором и каталогом — разные причины, ни одна не снимает другую. SAML и SCIM на них — в коммерческой редакции; в облаке расширений нет | | Точки расширения: чтение версий, журнал, печать в PDF | в коде | 0.10.0, [EXTENSIONS](specs/EXTENSIONS.md): `context.content` (версия и файлы потоком с проверкой; изолированное модератором не отдаётся), `context.auditFeed` (журнал по курсору, без пропусков), `POST /pdf` рендерера. Пользуется коммерческая редакция (выгрузка принятых версий в S3 и WebDAV). В облаке расширений нет | | Стенд «агент под ограничениями» | в коде, без прогона агента | [deploy/agent-stand](../deploy/agent-stand/README.md): ВМ Lima без папок Mac, `srt` + Codex, два сервисных доступа с токенами задач, обходы через bash, журнал агентов, замер отзыва. 16.10.2026 проверены ВМ, песочница, туннель, обходы (все отказаны), журнал и отзыв (первый отказ через 17 мс); шаги с самим агентом ждут входа в Codex | | Стенд «Контур»: окружение для чужих агентов | в коде, без прогона агента | [deploy/contour-stand](../deploy/contour-stand/README.md): ВМ Lima, Docker + gVisor, Keycloak (право поручать), OpenBao (секреты), LiteLLM (ключ с бюджетом на задачу), Squid (выход только по профилю, git-токен подставляет прокси), Gitea с защищённым `main`, диспетчер профиль → задача → песочница → журнал с `task_id`. 19.10.2026: `checks.sh` — 26 из 26, отзыв задачи 64 / 82 / 90 мс (процесс, ключ, сеть); прогон с самим агентом ждёт ключа модели. Рой (`swarm.mjs`): пакеты процессов, маркет навыков с digest, NATS, OPA, шлюз действий, системы учёта только с API, подпись принятой версии, новый процесс по описанию с теневым прогоном; `checks.sh` — 39 из 39, `swarm-demo.sh` проходит на скриптах навыков | | Финансовый стенд «Хвосты квартала» | в коде, без прогона агента | [deploy/finance-stand](../deploy/finance-stand/README.md) в той же ВМ, что и «Контур»: синтетическая фирма (2 банка, 30 контрагентов, 40 заложенных хвостов и эталон бухгалтера), банк A в схеме T-API, банк B в формате «Клиент-банк → 1С», ЭДО, учёт по образцу OData 1С (запись только черновиком), почта, симулятор контрагентов. Адаптер выписки T-API проверен на данных публичной песочницы Т-Бизнеса; живая проверка контракта ждёт решения о корне Минцифры. Рой подключает стенд через `extensions.json` (свои навыки, пакеты, маршруты действий, границы в `policy/ext`). M2: журнал обязательств на событиях (правила «дано / когда / тогда»), сверка `fin.match` через рой (песочница, проверки, политика, Полка), аудит на выгрузках компании в отдельном журнале. 19.10.2026 в ВМ: 140 обязательств, 40 хвостов — 40 из 40 совпали с эталоном, пересборка из журнала совпала с живой картиной; спецификации — 21 из 21 на пяти синтетических фирмах. M3: запросы первички поставщикам, напоминания должникам, разбор ответов, акты сверки с подписью только роли `signer`; `finance-demo.sh` с пустой ВМ. За две недели симулятора из 40 хвостов осталось 21: 5 из них — оплата поставщикам (вторая версия), 3 — исключения для человека, остальные — молчащие контрагенты. Письмо с инъекцией и письмо о «новых реквизитах» ничего не закрыли. `checks.sh` со всеми блоками — 52 из 52 (5 проб финансового стенда изнутри песочницы и 8 проверок снаружи). M5: аудит на выгрузках компании — списки 1С в Excel, реестры Диадока и СБИС, «Клиент-банк» в Windows и DOS, паспорт выгрузки с итогами банка, разметка бухгалтером даёт точность и полноту. 20.10.2026 на синтетических выгрузках «как у бухгалтера» в ВМ: 40 хвостов из 40; спецификации — 31 из 31. M6: УПД из почты — XML по формату ФНС из `.mbox` и `.eml`; сканы без модели не читаются и называются в паспорте. 20.10.2026 в ВМ: 28 писем, 26 УПД в сверку, 41 хвост — эталонные 40 и счёт, УПД которого пришёл только сканом; спецификации — 32 из 32. M7: прямые подключения только на чтение — T-API, OData 1С, ящик документов по IMAP — кладут данные в папку компании в виде выгрузок. 20.10.2026 в ВМ на демо-компании с настоящим dovecot: тот же 41 хвост, что по ручным выгрузкам; `checks.sh` — 53 из 53; спецификации — 35 из 35. Исключения решаются на Полке: каждое открытое — отдельная работа с основанием и безопасным решением, приёмка записывает решение в журнал, в границах ИБ `fin.decision` — только человек. Расписание шагов по пакетам (сверка каждый день в 09:00, запросы в 09:30, напоминания по понедельникам, письма по приходу) включается `fin.sh schedule on`; по умолчанию выключено, чтобы показ и проверки шли по своему календарю. Коннекторы к ЭДО и другим банкам ждут первой пилотной компании. На настоящих выгрузках форматы ещё не проверены. Шаги пока выполняют скрипты навыков: агент с моделью ждёт ключа | | Проверка песочницы агента | в коде | `scripts/polka-sandbox-check.mjs` ([AGENT_SANDBOX](specs/AGENT_SANDBOX.md)): каждая проверка в паре «без песочницы — через песочницу», сломанная песочница или инструмент дают «не проверено». 16.10.2026 на Ubuntu 24.04: `srt` с настройками стенда блокирует всё проверенное; песочница Codex не запрещает чтение файлов | | Сессии агентов | работает | 0.11.0–0.11.1, приёмка на polochka.app 07.10.2026 на пяти реальных сессиях, [AGENT_SESSIONS](specs/AGENT_SESSIONS.md): сессии Claude Code и Codex с секретами, скрытыми на компьютере (`polka-sessions.mjs`, хук плагина при `POLKA_SESSIONS=on`), страницы «Сессии», «Секреты», «Расход», MCP `polka_sessions`. Своя квота: на polochka.app включается оператором для отдельных полок (`AGENT_SESSION_QUOTA_BYTES=0`). С 0.12.0 — в коде чтение компанией (общий ключ отпечатков, `context.sessions`, `policies.sessionDelete`, `managed-settings`); 0.12.1 — хук управляемых настроек проверен на Claude Code 2.1.294, журнал отправки `~/.polka/sessions-hook.log`; 0.13.0 — досылка после закрытого терминала и `/clear`, `timeout: 10` у управляемого хука; в Unreleased — шаблон команды без значений флагов (`mysql -u `), сервер чистит так же шаблоны старых версий скрипта; значения `*SECRET*`, `*PASSWORD*`, `*TOKEN*`, `*API_KEY*` скрываются всегда; пароли `mysql -p…`, `sshpass -p`, `curl -u`. Шаблоны, уже сохранённые на серверах, не переписаны. Шаблоны команд, сохранённые до повторной очистки на сервере, переписывает `npm run admin -- sessions scrub-templates`; аргументы инструментов скрываются раскодированными (`PASSWORD="…"` внутри JSON, heredoc); отказ в загрузке расшифровки не удаляет сохранённую; страница расшифровки читает её потоком; объединение полок переносит сессии | | Удаление аккаунта | работает (кнопка и оператор) | По обращению владельца — команда оператора `account-erase` ([hosted](../deploy/hosted/README.md#удаление-аккаунта)): доступ закрывается сразу, затем обработчик очистки удаляет все версии объектов полки, пишет внешний журнал стираний (`polka-erasure-ledger`) и стирает метаданные. На polochka.app с 28.09.2026, приёмка на синтетическом аккаунте: полка пуста в хранилище, строки стёрты, в журнале отзыв и итог. Кнопка «Удалить аккаунт» («Настройки» → «Удалить полку») есть в коде с 0.8.0, вместе со службой очистки `account-purge` и страницей статуса `/account-deleted`; на polochka.app включена с 02.10.2026 после приёмки на синтетическом аккаунте (заявка → доступ закрыт → служба очистки за 50 с: версия объекта удалена, префикс пуст, журнал стираний принял отзыв и итог; прежняя сессия и вход по паролю после заявки дают 401). Удаление по обращению через оператора остаётся. Восстановление из дампа применяет журнал (шаг 5 процедуры); проверено 28.09.2026 на отдельной VM: аккаунт, удалённый после дампа, после восстановления снова стёрт | | Лицензия: открытое ядро и коммерческая редакция | работает | Открытое ядро под [AGPL-3.0](../LICENSE) (до v0.1.0-rc.5 включительно — Apache-2.0); облако polochka.app работает на нём. Коммерческая редакция для организаций — закрытое расширение `@polka/enterprise` по договору и с ключом лицензии, подключается через [точки расширения](specs/EXTENSIONS.md); сейчас в ней контроль ссылок. Коммерческая лицензия на ядро — по договору ([COMMERCIAL.md](../COMMERCIAL.md)), вклад — по [CLA](../CLA.md). Ссылка на исходный код — в подвале каждой страницы, у получателя, в `/llms.txt` и `/connect` (`SOURCE_URL`). | | Страница «Для компаний» и заявка | работает | `/enterprise`: ценность для компаний, варианты развёртывания, вопросы и форма заявки. `POST /api/enterprise-requests` (Origin, 5 в час с IP, honeypot) сохраняет заявку в `enterprise_requests` (миграция 033, удаляется через год) и шлёт письмо на `OPERATOR_EMAIL`. SSO и автоматическая проверка содержимого на странице помечены «в разработке». | | Политика и соглашение | работает | Страницы `/privacy` и `/terms` из [docs/legal](legal/privacy.md). Заполнены и вычитаны по 152-ФЗ, 149-ФЗ и ГК 23.09.2026 (протокол вычитки — в приватном архиве оператора, `docs/reviews/2026-09-23-legal`); юрист не подписал; за оператором — уведомление РКН, почта вне Gmail, адрес для обращений, runbook удаления. Это документы polochka.app: другая установка их не показывает — `/privacy` и `/terms` ведут на `PRIVACY_URL`/`TERMS_URL` владельца или говорят, что документы публикует он (`OPERATOR_NAME`, `OPERATOR_CONTACT`) | | Резервное копирование | работает | `pg_dump` каждый час (на polochka.app с 12.10.2026, раньше раз в сутки) и versioned-бакет. Восстановление проверено 28.09.2026 на отдельной VM с настоящим дампом polochka.app: база, все 172 объекта (SHA-256), приложение и выдача файлов по API; около 15 минут от пустой VM. 11.10.2026 по этой процедуре polochka.app поднята в зоне `ru-central1-d` после отключения питания в зоне a. С 0.17.0 — восстановление на любую минуту последних 7 дней (архив WAL и ежедневный базовый бэкап, профиль `pitr`, RPO около минуты) и копия работ в бакете под object lock, недоступном ключу приложения (профиль `mirror`, возврат пропавших версий — `objects-restore`); на polochka.app оба профиля с 14.10.2026. Восстановление на минуту проверено 15.10.2026 на данных polochka.app `pitr-drill.sh` (временный том без сети на той же VM, за 10 секунд, все версии до цели на месте); [hosted](../deploy/hosted/README.md#восстановление-на-момент-времени) | | Метрики продукта | работает | Свои события на сервере (миграции 034–035): посещения публичных страниц, регистрации, подключения агентов, сохранения, ссылки, открытия ссылок, заметки, заявки, показы и нажатия подсказки у получателя ([spec](specs/RECIPIENT_CONVERSION.md)), дни активности. Без cookies, сторонних скриптов и IP; аккаунт — только HMAC. Отчёт: `/ops/metrics`, `GET /api/ops/metrics`, `npm run admin -- metrics summary` ([hosted](../deploy/hosted/README.md#метрики-продукта)). Сырые события — 13 месяцев | | Мониторинг и алерты | работает | Статус оператора `/api/ops/status` (БД, обслуживание, свежесть бэкапа — порог `BACKUP_INTERVAL_SECONDS` плюс 2 часа, архив журнала с профилем `pitr` — отметка `wal/heartbeat` не старше 15 минут и базовый бэкап, диск) и скрипт внешней проверки `npm run ops:uptime` с алертами в Telegram или webhook при смене набора упавших проверок ([hosted](../deploy/hosted/README.md#мониторинг)). Для polochka.app с 28.09.2026 — функция Yandex Cloud каждые 5 минут, письмо оператору через Postbox ([uptime-function](../deploy/uptime-function/README.md)). С 0.17.0, на polochka.app с 14.10.2026, — метрики Prometheus `/api/ops/metrics/prometheus` (запросы по шаблону маршрута и коду, пул БД, цикл событий, память, очередь воркеров, очередь вебхуков), строка лога на запрос и `x-request-id`, задержка цикла событий без периода замера, мягкая остановка с дожиданием работы после коммита и самоперезапуск при зависшем цикле событий или пуле БД ([hosted](../deploy/hosted/README.md#остановка-и-самовосстановление)) | | Своя установка — не облако | в коде | [SELF_HOST_BASE_SPEC](specs/SELF_HOST_BASE_SPEC.md#своя-установка--не-облако). Если `APP_ORIGIN` не `https://polochka.app`: `/connect`, `/llms.txt` и веб дают прямые команды `claude mcp add …`/`codex mcp add …` с адресом установки и скиллы `npx skills add `, плагин облака не предлагают; `/privacy` и `/terms` — документы владельца установки, не облака. `ACCOUNT_TRUST=company` снимает правила новых аккаунтов ([ABUSE_PROTECTION](specs/ABUSE_PROTECTION.md#своя-установка-компании)); по умолчанию и в шаблоне `deploy/hosted` — `public` | | Своя установка без сборки | в коде | Workflow `release-images` публикует на тег `v*` образы `ghcr.io/artkruglov/polka` и `polka-backup` (amd64 и arm64, provenance и SBOM); выпускаются с v0.17.0, пакеты публичные. На чистой VM по [гайду для компании](company-launch.md) путь ещё не проходили. `deploy/hosted/install.sh` ставит на VM без Node.js и git: проверка Docker и DNS, файлы версии из образа, `hosted.env` через `hosted-setup.mjs` в контейнере, `up -d`. `npm run admin -- ops doctor` — проверка установки ✓/✗ с подсказками ([deploy/hosted](../deploy/hosted/README.md#быстрый-путь)). PostgreSQL: `shared_buffers=256MB`, `pg_stat_statements`, журнал запросов дольше 500 мс, таймауты ролей (`role-settings.sql`); Caddy сжимает zstd/gzip и отвечает 413 на тело больше лимита маршрута; `hosted.env` пишется в кавычках, когда значение с `$`, `#` или пробелами | | Обновление и откат самостоятельной установки | есть инструкция | [deploy/hosted](../deploy/hosted/README.md#обновление) (обновление, откат, дамп перед миграцией) и [deploy/BASE.md](../deploy/BASE.md#upgrading). Второй домен просмотра и зачем он нужен — [deploy/hosted](../deploy/hosted/README.md#интерактивный-viewer) | | Временные полки: ссылка от агента и обслуживание | работает | [SIGN_IN_PROVIDERS](specs/SIGN_IN_PROVIDERS.md) § 8–10. Вход по ссылке от агента перепроверяет ссылку и подключение под блокировкой полки. Без конвейера удаления обслуживание записывает удаление простаивающей полки в `provisional_erasures` (миграция 076) и доводит его до конца следующим прогоном после сбоя. Полка, которую не удаётся стереть, считается в `provisionalErasuresFailed` и не останавливает остальные шаги прогона; перед удалением строк аккаунт перепроверяется под блокировкой (всё ещё закрыт и не закреплён) | | Вход через Яндекс ID, VK ID и свой OIDC | работает (Яндекс ID), в коде (VK ID, OIDC) | [SIGN_IN_PROVIDERS](specs/SIGN_IN_PROVIDERS.md). Миграция 032 (`account_identities`). Кнопки видны, когда задан клиент поставщика; привязка и отвязка в «Способах входа». На polochka.app Яндекс ID работает с 24.09.2026; приложение VK ещё не зарегистрировано | | Вход через Google | в коде | 0.3.0, миграция 039, [SIGN_IN_PROVIDERS](specs/SIGN_IN_PROVIDERS.md) («Google»), настройка — [ops/google-oauth-setup.md](ops/google-oauth-setup.md). Без `GOOGLE_CLIENT_ID` кнопки нет. `GOOGLE_SIGNUP=on` по умолчанию в коде; в шаблоне `deploy/hosted` — `link-only`: Google только входит в полку, к которой его привязали, и не открывает новую. На polochka.app клиент Google не задан, кнопки нет | | Почтовые домены новых полок | работает | `EMAIL_SIGNUP_DOMAINS`: `any`, `ru-only` или список доменов. **Шаблон `deploy/hosted`:** `ru-only` — новую полку по коду открывают только адреса российских почтовых сервисов и домена установки. **polochka.app:** с 26.09.2026 `any` — любой адрес (решение владельца). Существующие аккаунты входят с любого адреса (`EMAIL_LOGIN_DOMAINS=any`), закрепить временную полку можно тем же адресом, что открыл бы новую | | Доступ компании по домену / своему IdP | в коде | `ORG_DOMAINS`, `OIDC_ORG_LIBRARY`: вход через поставщика с подтверждённой почтой домена добавляет в библиотеку шаблонов (reader/curator). Настраивает оператор; самостоятельной настройки администратором библиотеки нет | | Полки отделов | работает | [TEAM_SHELVES](specs/TEAM_SHELVES.md), этапы 1–5: миграции 042, 044, 045, 047 и 048 (`tenant_members`, журнал, `company_admin`, стирание строк полок отделов при удалении аккаунта, `shares.created_by`), роли и `lockShelf`, выбор полки заголовком `X-Polka-Shelf` (у GET ещё `?shelf=`), `npm run admin -- company admin`. В вебе: переключатель полок, создание полки администратором компании, участники и роли, журнал, сохранение, список, поиск, папки, корзина и просмотр работ на полке отдела с проверкой ролей. Агенты подключаются к выбранной полке («Разрешить», токен на странице «Агенты»), роль проверяется на каждом действии, уход с полки отзывает её подключения. Повторный `lockShelf` в одной транзакции перечитывает строки без блокировки, список участников не блокирует полку. Страница администратора компании `/settings/company`: все полки отделов, «Стать администратором», уход сотрудника одним действием. Ссылки с полки отдела (5а) и комментарии к ним (5б), в том числе через агента куратора. Приглашение ссылкой для тех, кто ещё не входил (миграция 067: администратор и куратор, срок до 7 дней, 1–50 человек, отзыв). Публикации в «Ленту» с полки отдела напрямую нет: куратор предлагает версию, решает оператор (`npm run admin -- feed proposals`, миграция 068, [DISCOVER_V2](specs/DISCOVER_V2.md) 5а). Организации для облака (миграция 070, `TEAM_SHELVES_SCOPE=organisation`): администратор компании видит и ведёт только полки своей организации, сразу добавить на полку можно только сотрудника организации (почта на её домене или уже на её полке), остальных — ссылкой; ответ не выдаёт, есть ли такой аккаунт; почту видно только у адресов на доменах организации. Команды `npm run admin -- company org` и `company admin <логин|почта> --org`. `TEAM_SHELVES=off` и `TEAM_SHELVES_SCOPE=installation` по умолчанию (своя установка = одна компания, как раньше); в шаблоне `deploy/hosted` — `TEAM_SHELVES=on` и тоже `installation` (`compose.yml` до 0.15.1 подставлял `organisation`); на polochka.app с 12.10.2026 `TEAM_SHELVES=on` в режиме организаций, администратора компании назначает оператор по письму на hello@polochka.app | | Журнал агентов полки отдела | в коде | `GET /api/shelves/:id/agent-audit` для администратора полки: действия агентов, события сервисных доступов, приёмка — с сервисным доступом, номером задачи и ответственным; чтения версий сервисными доступами (`revision.read`). Экрана нет ([TEAM_SHELVES](specs/TEAM_SHELVES.md#журнал-агентов-16102026)) | | Доступ агентов к принятому | в коде (частично) | [AGENT_ACCESS_AND_MEMORY](specs/AGENT_ACCESS_AND_MEMORY.md), миграции 054–063. `GET /api/v1/works` (`query`, `since`, `cursor`, `shelfIds`), ранжирование поиска (заголовок выше текста), `GET /api/v1/events` (лента над `audit_outbox`), карточка полки в `polka_context`, принятая версия и ответственный (меню работы «Принятая версия»), режим ссылки `pinned`/`follows`, service accounts и task-токены (`SERVICE_ACCOUNTS=off` по умолчанию, на polochka.app `on`; экран «Сервисные доступы» в диалоге участников полки отдела для куратора), поиск по полкам отделов, разрешённым токену. Снимок полки на дату (`GET /api/v1/snapshot`, [SHELF_SNAPSHOT](specs/SHELF_SNAPSHOT.md), 0.6.0), с 08.10.2026 — MCP `polka_snapshot` и экран «Полка на дату» (`/snapshot`). **В облаке с 12.10.2026:** всё перечисленное, в том числе полки отделов, сервисные доступы (`SERVICE_ACCOUNTS=on`) и поиск по полкам; они ограничены организацией через участие в полках. Нет: право токена `curate`; вебхуки — отдельной строкой ниже; работу с другой полки токен только находит, открывает её токеном той полки | | Вебхуки | работает | [WEBHOOKS](specs/WEBHOOKS.md), миграция 071, с 12.10.2026. `WEBHOOKS=off` по умолчанию; в шаблоне `deploy/hosted` и на polochka.app — `on` (решение владельца 12.10.2026, с ближайшей выкладки). Владелец личной полки («Настройки») или администратор полки отдела добавляет HTTPS-адреса и события (события ленты плюс `share.enabled`, `share.revoked`, `comment.created`); POST с телом события ленты и подписью `Polka-Signature` (HMAC-SHA256), повторы 8 раз за ~45 часов; не больше 2 попыток одновременно на адрес, пауза адреса после 3 ошибок подряд, очередь до 1000; журнал доставок, выключение после 3 суток ошибок с письмом, а на полке отдела — когда добавивший перестал быть администратором. Защита от SSRF: только https:443, DNS проверяется перед каждой попыткой, непубличные адреса и перенаправления запрещены. Удаляются при удалении аккаунта; восстановление из дампа их выключает (шаг 5б, вместе с приглашениями на полки), владелец включает снова | | SAML и SCIM | в коммерческой редакции | С 0.15.0 ядра и 0.9.0 коммерческой редакции: вход через SAML 2.0 с привязкой групп к полкам отделов и режимом «только SSO», SCIM 2.0 (пользователи и группы) для Okta, Entra ID и Keycloak. В ядре только точки расширения ([EXTENSIONS](specs/EXTENSIONS.md#вход-и-учёт-сотрудников-sso-scim)); на polochka.app не включено — облако работает на открытом ядре | | Модерация: жалобы, закрытие ссылки, блокировка аккаунта | работает | Скрипты оператора `scripts/moderation.ts` ([hosted](../deploy/hosted/README.md#модерация)), без веб-интерфейса. На polochka.app ими разбирается очередь задержанных ссылок | | Защита от злоупотреблений: доверие к аккаунту, лимиты новых аккаунтов, проверка ссылок, автопауза по жалобам | работает | [ABUSE_PROTECTION](specs/ABUSE_PROTECTION.md), пункты 1–7. Миграция 029. `SHARE_MODERATION` (в коде по умолчанию `flagged`, в `deploy/hosted` и на polochka.app — `auto`), новый аккаунт — до 5 открытых ссылок по 7 дней и не больше 10 новых ссылок в сутки (`NEW_ACCOUNT_DAILY_LINKS`), 3 разных жалобщика за 7 дней ставят ссылку на паузу. Получатель ожидающей ссылки видит экран «на проверке», над обычной страницей — предупреждение и «Пожаловаться» | | Письма оператору с действиями в один клик | работает | `OPERATOR_EMAIL` + `MAIL_MODE=smtp`: письмо о каждой ожидающей ссылке, подозрительной странице, жалобе и паузе; кнопки ведут на `/moderation#…` (подпись HMAC, 7 дней, открытие ничего не меняет, действие — POST). Без адреса — скрипты `admin moderation queue`/`approve`/`unpause`/`trust`. На polochka.app адрес задан | | Фильтр запрещённого содержимого и автоматическая модерация | работает | [CONTENT_FILTER](specs/CONTENT_FILTER.md). Миграция 031. Правила по 14 категориям (списки в `apps/server/content-filter/lists`, линейный проход, тесты точности на честных текстах), сигналы вредоносного кода, две модели после сохранения (Yandex AI Studio во всех ролях, NeuralDeep — необязательный вариант до поручения на обработку; у каждой роли своя точка, лимит запросов, 429 → запасная, фиксированный тариф) (блокировка только при согласии двух, CSAM модели — скрыть до проверки), `SHARE_MODERATION=auto` вместо ручного одобрения (ссылка, ждущая модель, открывается сама после её чистого ответа; `moderation.ts recheck`), состояние `blocked` с изоляцией и удалением по сроку категории, стоп-лист SHA-256, журнал `moderation_events` (3 года), `takedown`/`legal-hold`/`handed-over`, антиспам. Лента проверена правилами: 14 из 14 чисто. На polochka.app с 24.09.2026: модели Yandex AI Studio, `CONTENT_FILTER_MODE=strict`, автоблокировка (`CONTENT_FILTER_AUTOBLOCK`) пока выключена — задержанное разбирает оператор | | Признаки фишинга при сохранении | работает | Только с каналом вне страницы (передать код, перевести деньги, написать в Telegram) или похожим доменом; поля секретов, бренд и срочность лишь добавляют к счёту. В том же проходе parse5, что и классификатор, и по строкам скриптов. Одобрение оператора переходит на следующие версии с теми же признаками; `moderation.ts recheck --fraud`. Список — `apps/server/phishing-signals.ts`. Ссылку не удаляет: только задерживает или сообщает оператору | | Заметки владельца вместо комментариев получателей | работает | `COMMENTS_MODE=owner-notes` (по умолчанию в `deploy/hosted` и на polochka.app): пишет только владелец и его агент (`polka_note`), получатели читают; `off` выключает обсуждения | | Комментарии и реакции на тексте работы | в коде | [COMMENTS](specs/COMMENTS.md), этап 3. Миграция 030. Обсуждение у каждой ссылки, лента и панель на телефоне, подсветка во фрейме (оверлей только по гранту оболочки; в статичном просмотре — nonce), письма с отключением, агентские `polka_comments`, `polka_resolve_comment`, правки патчем в `polka_revise` и `POST /api/v1/works/:id/edits`, модерация. Без домена просмотра (одна установка на одном домене) подсветки нет — только комментарии ко всей работе. На polochka.app комментарии получателей не включены (там `owner-notes`) | | Приём тел запросов: токен до тела, бюджет памяти | в коде | `apps/server/admission.ts`: `/mcp`, HTTP API и расшифровки сессий проверяют токен по заголовкам и без него отвечают 401, не читая тело; все тела в памяти — не больше `BODY_BYTES_IN_FLIGHT_MB` (256 МиБ), сверх — 503 `busy` с `Retry-After: 5`. Запрос с проверенным до тела токеном резервирует объявленный размер; любой другой (с cookie, на несуществующий маршрут) считается по пришедшим байтам: такие вместе — не больше четверти бюджета, с одного адреса — не больше шестнадцатой, поэтому медленные отправители с большим `Content-Length` не занимают бюджет загрузок. Замер: 20 анонимных расшифровок по 64 МиБ — +1 МБ памяти вместо +1854 МБ | | Пул воркеров-читателей страниц | в коде | `apps/server/worker-pool.ts`: проверка больших страниц, обложки и Markdown проектов идут в `HTML_WORKERS` загруженных воркерах (по умолчанию 2) вместо нового воркера на каждую страницу; очередь — `HTML_WORKER_QUEUE` (64), сверх — 503 `busy`. Замер: публикация 85 КБ при 10 параллельных — 67,6 запроса/с вместо 10,5; четыре страницы по 4,5 МБ — +156 МБ памяти вместо +619 МБ; проект из 100 страниц по 20 КБ сохраняется за 1,1 с вместо 26,3 с | | Учёт вызовов агентов | в коде | `/api/v1/*` и `/mcp`: `last_seen_at` подключения пишется не чаще раза в минуту на процесс, счётчик чтений (`agent_read_days`) копится в памяти и пишется раз в 10 с (и при остановке сервера; пачка, которую база не приняла из-за сбоя связи, возвращается в память, не больше 10 000 счётчиков), JSON-схемы инструментов MCP строятся один раз. Проверка доступа не кэшируется. Лимит частоты по-прежнему в базе, общий для всех процессов. Замер: `GET /api/v1/works` — 4 запроса к базе вместо 6; `tools/list` — 1387 ответов/с вместо 591 | | Публикации авторов, профили, веб-интерфейс модерации | нет | | | Сверка изображений с базами хешей CSAM (PhotoDNA и т. п.) | нет | В России недоступны; см. «Ограничения» в [CONTENT_FILTER](specs/CONTENT_FILTER.md) | | Telegram-бот | нет | См. [roadmap](roadmap.md) | ## Проверки - `npm test` запускает интеграционные тесты на временных PostgreSQL и S3, `npm test -- --live` — наборы с включённым viewer. `npm run verify` запускает это вместе с проверкой прав ролей БД, лицензий зависимостей, секретов в истории и сборкой Docker-образов. Те же шаги GitHub Actions выполняет на каждый pull request; `main` защищена и принимает изменения только с зелёными проверками. - `npm run dev:web` — интерфейс через Vite с горячей перезагрузкой поверх `npm run dev` ([local-development](local-development.md#интерфейс-с-горячей-перезагрузкой)). Проверено 10.10.2026: вход, сохранение работы и правка компонента без перезагрузки страницы. - Быстрый запуск из [README](../README.md) проверен 22.09.2026 на чистом клоне: `npm ci` → `local:setup` → `infra:up` → `db:migrate` → `storage:bootstrap-local` → `admin account create` → `build` → `dev`. После этого сработали `/api/health`, главная страница и вход созданным аккаунтом.