Документация проекта

Документация проекта «К2 Репетиторство» (k2-tutoring-oc)

Project id: 45 · Slug: k2-tutoring-oc · Название: K2-tutoring-oc

Дата съёма: 2026-09-04 (живой аудит через codedocs MCP, прогон oc2/К2, сессия docs)

Охват: полная структура (doc_tree), 15 таблиц (схемы + счётчики), 9 правил автоматизации, 3 формы, 5 дашбордов, публичный контур (curl), грабли (dev-report §24/§42/§43/§58, error.md E82/E83)

Связанные артефакты: карта ../K2-tutoring-automation-map-oc2.md, приёмка ../oc2-wave-acceptance.md (вердикт К2 — ЧАСТИЧНАЯ)

1. Дерево объектов (doc_tree)

23 узла, все плоские (parentId=null, depth=0, archivedAt=null):

Тип

Узлы

dataTable (15)

1602 Счета · 1603 Позиции счёта · 1604 Платежи · 1605 Кредит-ноты · 1606 Ученики · 1607 Планы абонементов · 1608 Абонементы · 1609 Занятия · 1610 Посещения · 1614 Курсы (секции) · 1615 Параметры · 1616 Заявки · 1617 Успеваемость · 1618 Заявки на перенос · 1619 Преподаватели

dashboard (5)

1611 Дебиторка · 1612 Абонементы · 1613 Занятия · 1623 D1 Успеваемость и посещаемость · 1624 D2 Оплаты и абонементы

form (3)

1620 Записаться на пробное (published, portalExposed) · 1621 Заявка на перенос занятия · 1622 Поставить оценку

document (0)

— нет ни одного документа/шаблона (см. §6)

Опубликовано узлов: 1614 (isPublished:true) и 1620 (isPublished:true, portalExposed:true).

2. Таблицы: схемы и счётчики

Счётчики — через datatable_aggregate (countBy по status; для таблиц без статуса — countNonEmpty по первой колонке), без выгрузки строк.

ID

Таблица

Slug

Purpose

Колонок

Записей (оценка)

Распределение статусов

1602

Счета

invoice

core_invoice

21

7

sent 5, paid 1, partial 1

1603

Позиции счёта

invoice-line

core_invoice_line

13

~6

— (нет status)

1604

Платежи

payment

core_payment

7

~2

1605

Кредит-ноты

credit-note

core_credit_note

7

0

1606

Ученики

customer

core_customer

20

~7

1607

Планы абонементов

membership-plan

core_membership_plan

6

~3

1608

Абонементы

membership

core_membership

29

7

active 4, past_due 2, expired 1

1609

Занятия

class-session

core_class_session

14

12

scheduled 6, completed 6

1610

Посещения

enrollment

core_enrollment

6

24

attended 12, enrolled 7, no_show 5

1614

Курсы (секции)

kursy-sektsii

6

~4

1615

Параметры

parametry

3

~3

1616

Заявки

zayavki

13

8

new 3, trial_done 2, assigned 1, student 1, rejected 1

1617

Успеваемость

uspevaemost

5

~13

1618

Заявки на перенос

zayavki-na-perenos

7

~2

— (status-колонка rs_status: new_rs, agreed, done_rs, rejected_rs)

1619

Преподаватели

prepodavateli

3

~3

Ключевые колонки по таблицам:

1602 Счета (core_invoice)

number (sequence), customer →1606, company →(несвязан), issue_date, due_date, period_start, tax_jurisdiction, rollups total/amount_paid/amount_credited/tax_total, формулы total_gross, outstanding, aging; status (draft,sent,partial,paid,void); student_email, reminder_date, reminder_sent, pause_date, amount (₽).

1603 Позиции счёта (core_invoice_line)

invoice →1602, product →(несвязан), qty, unit_price, формулы line_total, tax_rate (TAX_RATE+LOOKUP), tax_amount, line_total_gross, subscription →1608.

1604 Платежи (core_payment)

invoice →1602, amount, kind, method, формула effect (±amount), paid_at, reference.

1605 Кредит-ноты (core_credit_note)

пустая; number (sequence), invoice →1602, amount, effect=0-{amount}, reason, issued_at.

1606 Ученики (core_customer)

name, контакты (email/phone/parent_*), externalUser (externalPerson — личный кабинет), source, rollups ar_balance, active_memberships, кейсовые: course →1614, absent_streak, last_absence_push, streak_alerted, loyalty_points, marketing_opt_in, owner (person).

1607 Планы абонементов (core_membership_plan)

name, price, billing_cycle, benefits, active.

1608 Абонементы (core_membership) — самая насыщенная (29 колонок)

member →1606, plan →1607, lookups plan_price/plan_cycle/last_invoice_outstanding/last_invoice_due_date, формулы bill_amount, days_past_due, mrr, period_days, converted_next_run; previous_membership →1608 (само_link для смены тарифа); status (trial,active,past_due,cancelled,expired); гейт-колонки due_control_date, paid_flag, pause_date.

1609 Занятия (core_class_session)

title, instructor (person), tutor →1619 (карточка), course →1614, start/end (datetime), capacity, enrolled_count (rollup), seats_left (formula), status (scheduled,in_progress,completed,cancelled), instructor_email; поведение exclusive_scheduling (explicit): resource=tutor, interval=startend (после рефакта §58: TEXT-ресурс отклонялся scheduling_bad_resource_type, заведён справочник 1619).

1610 Посещения (core_enrollment)

session →1609, member →1606, status (enrolled,attended,no_show,cancelled), pair_key (text, UNIQUE — антидубль), instructor_email.

1614 Курсы (секции) — published

name, age_range, subject, schedule_note, instructor_name, instructor_email. Справочник для course в 1606/1609/1616 и для формы 1620.

1615 Параметры

key, value_num, value_txt (KV-хранилище; значения: допуск дней на оплату 7, пауза 5 и т.п. — 3 записи).

1616 Заявки — вход публичной формы

child_name, child_age (3–18), course →1614, parent_name/email/phone, trial_date, attended, enrolled_flag, params_days_to_pay (снимок), status (new→assigned→trial_done→{student|rejected}, workflow enabled); дедуп-контур (§58): dedup_key (formula CONCAT + unique — НЕ гейтит INSERT) + dedup_guard (TEXT unique + правило 295 — рабочий пост-фактум-гейт).

1617 Успеваемость

student →1606, session →1609, grade (select), comment, grade_date.

1618 Заявки на перенос

session →1609, student →1606, new_date, new_start_time, new_end_time, reason, rs_status (new_rs,agreed,done_rs,rejected_rs).

1619 Преподаватели

name, email, phone — справочник-ресурс для exclusive_scheduling (1609) и писем.

3. Автоматизации (9 правил на 5 таблицах)

Все enabled:true. События/действия — из automation_get_meta.

ID

Таблица

Правило

Триггер

Действия

295

1616

Заявка → гейт дедупа

event create, cond dedup_guard isEmpty

set_fields: dedup_guard = CONCAT({parent_email},"

292

1616

Пробное → зачисление: ученик

event update (changed: status,attended), cond status=trial_done, attended=true, enrolled_flag empty

set_fields enrolled_flag; create_row 1606 (перенос child/parent/contact/course, сброс счётчиков)

293

1606

Ученик → абонемент, счёт и письмо

event create, cond parent_email isNotEmpty, runOnAutomation

create_row 1608 (plan=фикс. uuid, due_control_date +12д, status active); create_row 1602 (amount 4500 ₽, due +7д, reminder +4д, pause +12д, status sent); send_email родителю «Зачисление в группу»

287

1608

Выставить счета по абонементам

schedule 0 2 * * *, each_row, cond next_billing_date ≤ $today, manualRunnable

issue_recurring_invoice (invoice 1602, line 1603, billable active, sent, termsDays 14)

288

1608

Сменить тариф

manual (row), cond last_invoice_outstanding ≤ 0

create_row 1608 (новый план, previous_membership, carried_value-формула пропорции); set_fields old → status=cancelled

289

1608

Сменить тариф — пересчитать дату

event create, cond carried_value > 0, runOnAutomation

set_fields next_billing_date = {converted_next_run}

291

1608

Просрочка → приостановка абонемента

schedule 0 10 * * *, each_row, cond due_control_date ≤ $today, paid_flag false, status=active, pause_date empty

set_fields status=past_due + pause_date=TODAY; send_email «Абонемент приостановлен»

290

1610

Пропуск → счётчик и письмо преподавателю

event create/update (changed: status), cond status=no_show, runOnAutomation

update_related_rows (member → absent_streak+1, last_absence_push=TODAY); send_email преподавателю (instructor_email)

294

1602

Счёт → напоминание об оплате

schedule 0 9 * * *, each_row, cond reminder_date=$today, reminder_sent false, amount>0

send_email родителю (bodyHtml с {{col.due_date}}/{{col.amount}}); set_fields reminder_sent

Цепочка сквозняка: форма 1620 → 1616 (295 дедуп → 292) → 1606 (293) → 1608+1602+письмо (287 биллинг, 291 просрочка, 294 напоминание; 290 пропуски).

4. Формы

ID

Форма

Цель

Поля

Статус

1620

Записаться на пробное

1616 Заявки

child_name*, child_age* (3–18), course* (ref), parent_name*, parent_email*, parent_phone*

published, portalExposed:true, submitAccess=everyone

1621

Заявка на перенос занятия

1618

session*, student*, new_date*, new_start_time*, new_end_time*, reason

не опубликована, submitAccess не задан

1622

Поставить оценку

1617

student*, session*, grade* (select), comment, grade_date*

не опубликована

5. Дашборды

ID

Дашборд

Панели (binding)

Статус

1611

Дебиторка

К оплате (sum outstanding, 1602) · Просрочка (bar по aging) · По статусу (hBar)

не опубликован

1612

Абонементы

MRR (sum mrr, 1608) · Всего участников · По статусу (bar) · MRR по плану

не опубликован

1613

Занятия

Всего занятий · По статусу (bar) · Записано по занятиям (sum enrolled_count)

не опубликован

1623

D1 Успеваемость и посещаемость

Учеников (1606) · Явки по статусам (pivot, 1610) · Оценки (chart, 1617) + slicers status/grade

не опубликован

1624

D2 Оплаты и абонементы

Начислено ₽ (1602) · Счета по статусам (pivot) · Начисления по неделям (grain week) + slicers

не опубликован

6. Документы-шаблоны и проверка токенов

В doc_tree нет ни одного узла типа document — в проекте отсутствуют документы/шаблоны писем-документов. Проверка тел на литеральные токены {{col.*}} (известный дефект генератора, блокер волны W-1/D-1) — N/A: проверять нечего. Токены {{col.*}} в телах писем живут в actions правил (290/291/293/294) и являются штатными шаблонами автоматизаций, а не дефектом.

7. Публичный контур (curl, 2026-09-04)

Адрес

Проверка

Статус

https://smb.farhome.ru/public/k2-tutoring-oc/zapisatsya-na-probnoe

форма записи 1620

200 — живой

https://smb.farhome.ru/public/k2-tutoring-oc/kursy-sektsii

таблица 1614 (published)

200 — живой

https://smb.farhome.ru/public/k2-tutoring-oc/postavit-otsenku

неопубликованная форма 1622

404 — корректная приватность

https://smb.farhome.ru/public/k2-tutoring-oc/<несуществующий>

контроль

404

307 не наблюдалось. Приватность неопубликованных объектов подтверждена (404). Проектные настройки: isPublished:true, baseCurrency:RUB, timezone:Europe/Moscow, portalAllowedOrigins:[], externalDirectory:[].

8. Грабли проекта (из dev-report.md / error.md)

§58 (К2, сессия-2): unique на formula-колонке НЕ гейтит INSERT — публичная форма не может быть отклонена уникальностью. Рабочий обход, собран на К2: TEXT dedup_guard unique + правило 295. Дубль детерминируется пустым guard → Wave 2 не сделан: авто-режект «guard пуст + статус Новая → Отклонена» (см. §9).

§58, второе: exclusive_scheduling с TEXT-ресурсом отклоняется scheduling_bad_resource_type — resource обязан быть reference (справочник 1619).

§58, третье: set_fields fields в действии — только массив {columnId,value|formula|picked}; dict-форма проходит валидатор, но падает в рантайме s is not iterable.

§24 (приёмка К2, runs 564–566): update_related_rows пишет дату без времени и не трогает парную end; billing_ar autoTransitionpast_due→active при пустом outstanding (E43); анонимная отправка портала не штампует submitted_by (E44).

§42: для scheduled_reminder документированы только daily + $tomorrow; N-дневные/monthly токены (П5-4, monthly-отчёт П6-3) — требует живой проверки.

§43: живой коннектор оплаты (ЮKassa) не сверен с картой — П5-2/§9 ❌ остаётся (E15).

E82: «Группа» смоделирована reference на core_class_session (П1-3) — одна таблица на две сущности; вопрос дизайна открыт.

E83: косметика карты (допущение «часы» нигде; §5-2 не называет место проверки условия; параметры 7/5 без пометки «оценка автора»).

9. Открытые вопросы

1.

a.

авто-режект заявок с пустым dedup_guard (правило Wave 2) — не реализовано; сейчас дубль остаётся в таблице с пустым guard;

b.

SMTP-доставка писем правил 290/291/293/294 не доказана для К2 (живые доставка-доказательства есть только для К4, runs 868/869);

c.

браузерный сабмит публичной формы 1620 не проверялся (API-сабмиты — да);

d.

monthly-тики расписаний (N-дневные/monthly токены, §42) не проверены.

2.

Несвязанные reference-колонки модульного ядра: invoice.company, invoice_line.product, class_session.location/service имеют пустой referenceDocumentId (битые ссылочные колонки core-модулей). Для К2 не используются в автоматах, но видны в UI.

3.

Коннектор платежей: в письмах «оплата по ссылке (приём платежей вне платформы до подтверждения коннектора)» — П5-2 остаётся ❌/👤 до живой сверки (E15/§43).

4.

E82: уточнить модель «Группа» (справочник курсов vs отдельная таблица) — переносится на доработку.

5.

Дашборды 1623/1624 и формы 1621/1622 не опубликованы и без submitAccess — если родительский сабмит переносов/оценок задуман, нужен запуск публикации (сейчас 404).

6.

Счётчики записей — агрегатная оценка (countNonEmpty по первой колонке для таблиц без статуса); точный total платформой не отдаётся.

10. Публичный доступ

Документация опубликована на платформе: documentId 1746, «Документация проекта», slug dokumentatsiya-proekta, isPublished:true.

Публичный URL: https://smb.farhome.ru/public/k2-tutoring-oc/dokumentatsiya-proekta — curl 200 (проверено 2026-09-04).

publicUrl не null, publicUrlBlocked отсутствует (не заблокирован); тело проверено через doc_get_content (ключ markdown, 14195 симв., совпадает с локальным файлом).

Настройки проекта: isPublished:true (RUB, Europe/Moscow) — патч не требовался.

Иные живые публичные адреса проекта: форма 1620 …/zapisatsya-na-probnoe (200), справочник 1614 …/kursy-sektsii (200); неопубликованные объекты — 404.

Чистка (2026-09-04)

Указание владельца платформы: архивировать пустые и неиспользуемые таблицы проекта (slug k2-tutoring-oc, id 45). Канал — scripts/mcp.py (codedocs MCP); project_use перед каждым батчем записей. Формы/правила/дашборды не трогали (граница задачи).

Живая пустота (datatable_get_rows limit=1 по всем 15 таблицам): пуста только 1605 Кредит-ноты (0 строк); остальные 14 — непустые (n≥1).

Живая проверка использования (формы form_get_meta; правила automation_get_meta по всем 15 таблицам; дашборды dashboard_get_meta — panel bindings; link-колонки — referenceDocumentId и rollup.childDocumentId во всех 15 схемах; публичный контур — isPublished в doc_tree):

формы: 1620→1616, 1621→1618, 1622→1617;

правила (триггер-таблицы): 294→1602, 293→1606, 287/288/289/291→1608, 290→1610, 295/292→1616; create_row-мишени: 1606, 1608, 1602 (287 также пишет 1603);

дашборды: 1611/1624→1602, 1612→1608, 1613→1609, 1623→1606/1610/1617;

схемы: 1602←(1603.invoice, 1604.invoice, 1605.invoice); rollups 1602 amount_paid→childDocumentId 1604, amount_credited→childDocumentId 1605; 1606←5 ссылок; 1607←1608.plan; 1608←1603.subscription+самолинк; 1609←1610/1617/1618; 1614←1606/1609/1616+1620; 1619←1609.tutor (+ресурс exclusive_scheduling);

публично: 1614 (таблица), 1620 (форма), 1746 (документация).

Архивировано: 1615 Параметры — непустая (~3 KV-записи), но использование = НОЛЬ по всем контурам (правила 293/294 хардкодят +7/+12 дней вместо чтения из KV; снапшот params_days_to_pay в 1616 значение не подтягивает из 1615; ссылок/дашбордов/форм/публички нет) → архив с данными, doc_archive {"documentId":1615}archivedIds:[1615] (каскада нет, childCount=0).

Сохранено с причинами:

1605 Кредит-ноты — пуста, но используется: rollup-колонка 1602 amount_credited (childDocumentId=1605) — звено цепочки AR outstanding = total − amount_paid − amount_credited; архив сломал бы формулу дебиторки → не трогать (пустая, но используемая).

1604 Платежи — непустая, используется rollup 1602 amount_paid → не трогать.

1609 Занятия — непустая, используется (ссылки 1610/1617/1618, дашборд 1613, механизм exclusive_scheduling с ресурсом tutor→1619, грабли §58) → не трогать.

1602, 1603, 1606, 1607, 1608, 1610, 1614, 1616, 1617, 1618, 1619 — непустые и используются ≥1 объектом.

Итог дерева: узлов было 24 → стало 23 (живых dataTable 15→14; дашборды 5, формы 3, документ 1 — без изменений). Соседние проекты не затрагивались.

Перепубликация документации: тело существующего документа через doc_upsert не обновляется (известное ограничение: «ок» без записи тела) — обход: архив 1746 + пересоздание. См. §10 (ниже, обновлён после пересоздания).