Andrey Epifancev b1c61ae769 openspec: архив aurora-1883-closed-vsp и aurora-1896-cell-formulas
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 18:49:51 +04:00

10 KiB
Raw Blame History

cell-formula Specification

Purpose

Формулы ячеек листов бюджетных форм (FORM_1, FORM_2, FORM_4) и отчётов проектов (FORM_3): как формула сохраняется вместе со значением, кто и как её видит, когда она перестаёт показываться и когда удаляется.

Термины: ячейка — (владелец, лист, line_id, column), где владелец — бюджетная форма (budget_form.id) или отчёт проекта (rf_project_report.id); line_id и column — те же, что в cell_updated и PATCH …/cell. Формула — выражение без ведущего «=», например 100+50.

Requirements

Requirement: Формула сохраняется вместе со значением ячейки

Запись ячейки с полем formula (WS cell_updated — data.formula; REST PATCH /form/{id}/sheet/{sheet}/cell, …/cells, PATCH /projects/{id}/report/{year}/{type}/cell, …/cells — поле formula элемента) SHALL сохранять формулу этой ячейки в той же транзакции, что и значение: выражение, значение (value записи), автора (текущий пользователь) и время записи. Предыдущая формула ячейки SHALL заменяться. Формула SHALL сохраняться только если запись значения прошла (те же проверки прав и принадлежности строки, что у значения); при отказе в записи значения формула SHALL NOT сохраняться.

Scenario: Сохранение формулы

  • WHEN администратор пишет в ячейку FORM_2/AHR plan.q1 значение 150 с формулой 100+50
  • THEN чтение формул листа возвращает для этой ячейки выражение 100+50, значение 150, автора — этого администратора и время записи

Scenario: Отказ в праве на ячейку

  • WHEN исполнитель без права на колонку (окно закрыто или чужая оргединица) пишет значение с формулой
  • THEN запрос отклоняется так же, как без формулы (403)
  • AND формула ячейки не появляется и прежняя формула не меняется

Requirement: Ввод без формулы удаляет формулу ячейки

Запись значения ячейки без поля formula (или с formula: null) через любой из путей записи выше SHALL удалять формулу этой ячейки, если она была. Это касается и массовой записи …/cells: для каждого элемента без формулы формула его ячейки удаляется.

Scenario: Перезапись числом

  • WHEN у ячейки есть формула 100+50, и пользователь записывает в неё значение 200 без формулы
  • THEN чтение формул листа не возвращает формулы этой ячейки

Requirement: Проверка выражения

Сервер SHALL принимать выражение длиной от 1 до 500 символов, состоящее только из цифр, пробелов и символов + - * / % ( ) , .; ведущий «=» и пробелы по краям SHALL отбрасываться при нормализации. Сервер SHALL NOT вычислять выражение. Формула с непустым выражением SHALL требовать числовое value. При нарушении сервер SHALL отвечать 422 с кодом ошибки по префиксу invalid_formula:, и значение ячейки в этом запросе SHALL NOT записываться.

Scenario: Недопустимое выражение

  • WHEN пользователь пишет значение 150 с формулой drop table
  • THEN ответ — 422 invalid_formula
  • AND значение ячейки осталось прежним, формула не сохранилась

Scenario: Нормализация

  • WHEN пользователь пишет формулу =100+50
  • THEN сохраняется выражение 100+50

Requirement: Чтение формул листа

Сервер SHALL отдавать все формулы листа: GET /api/v1/form/{form_id}/sheet/{sheet}/formulas и GET /api/v1/projects/{project_id}/report/{year}/{report_type}/formulas. Каждая запись SHALL содержать line_id, column, expression, value, updated_by (id, full_name) и updated_at. Доступ SHALL проверяться так же, как у GET листа (форма) или отчёта (проект): нет доступа к форме или формы нет — 404 «Форма не найдена»; отчёт проекта не найден или нет доступа — та же ошибка, что у PATCH этого отчёта (400 «Отчёт не найден»).

Scenario: Формулы видны другому пользователю

  • WHEN пользователь А сохранил формулу, а пользователь Б с доступом к форме запрашивает формулы листа
  • THEN Б получает формулу А с её автором и временем

Requirement: Рассылка формулы по WebSocket

Рассылка cell_updated всем подключённым к листу SHALL содержать в data поле formula — нормализованное сохранённое выражение или null, если формулы у ячейки после записи нет, — и при наличии формулы поле formula_meta с updated_by (id, full_name) и updated_at. Значение data.formula в рассылке SHALL задавать сервер, а не пересылать входящее значение клиента.

Scenario: Второй пользователь видит формулу без перезагрузки

  • WHEN пользователь А вводит в ячейку =100+50
  • THEN пользователь Б, открывший тот же лист, получает cell_updated с data.formula = "100+50" и автором А
  • AND в ячейке у Б отображается 150 с маркером формулы

Scenario: Перезапись снимает маркер у всех

  • WHEN пользователь Б записывает в ту же ячейку число 200
  • THEN все подключённые клиенты получают cell_updated с data.formula = null, и маркер формулы пропадает

Requirement: Отображение формулы

Фронт SHALL показывать у ячейки маркер формулы fx и подсказку с выражением, ФИО автора и датой-временем, только если для ячейки есть формула и её value совпадает с текущим значением ячейки с точностью 1e-9. Редактор ячейки SHALL открываться с текстом = + выражение при том же условии совпадения. Если значения не совпадают (значение изменилось не через ввод, например синхронизацией), маркер SHALL NOT показываться, и редактор открывается со значением.

Scenario: Формула устарела после пересчёта

  • WHEN у ячейки есть формула со значением 150, а текущее значение ячейки стало 170
  • THEN маркер формулы не показывается, редактор открывается со значением 170

Requirement: Формулы не хранятся в браузере

Фронт SHALL NOT читать и писать формулы в localStorage. При первом запуске новой версии ключи formula_* SHALL удаляться из localStorage.

Scenario: Формула с другого компьютера

  • WHEN автор сохранил формулу и открыл лист на другом компьютере
  • THEN он видит маркер формулы и открывает редактор с =выражением

Requirement: Формулы удаляются вместе с владельцем и строкой

Формулы SHALL удаляться при удалении строки, к которой относится ячейка (строка бюджета, запись сателлита аренды/коммунальных/охраны, запись отчёта ОС OTCH9F, строка отчёта проекта), при окончательном удалении бюджетной формы и при удалении отчёта проекта — независимо от того, какая функция удаляет строку.

Scenario: Удаление строки

  • WHEN у строки листа есть формулы, и строку удаляют
  • THEN чтение формул листа не возвращает формул этой строки