Документация проекта
Документация проекта «К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-колонка |
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=start–end (после рефакта §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 | set_fields: |
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 | 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 |
291 | 1608 | Просрочка → приостановка абонемента | schedule | 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 | 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, |
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 — живой |
таблица 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. Открытые вопросы
авто-режект заявок с пустым dedup_guard (правило Wave 2) — не реализовано; сейчас дубль остаётся в таблице с пустым guard;
SMTP-доставка писем правил 290/291/293/294 не доказана для К2 (живые доставка-доказательства есть только для К4, runs 868/869);
браузерный сабмит публичной формы 1620 не проверялся (API-сабмиты — да);
monthly-тики расписаний (N-дневные/monthly токены, §42) не проверены.
Несвязанные reference-колонки модульного ядра: invoice.company, invoice_line.product, class_session.location/service имеют пустой referenceDocumentId (битые ссылочные колонки core-модулей). Для К2 не используются в автоматах, но видны в UI.
Коннектор платежей: в письмах «оплата по ссылке (приём платежей вне платформы до подтверждения коннектора)» — П5-2 остаётся ❌/👤 до живой сверки (E15/§43).
E82: уточнить модель «Группа» (справочник курсов vs отдельная таблица) — переносится на доработку.
Дашборды 1623/1624 и формы 1621/1622 не опубликованы и без submitAccess — если родительский сабмит переносов/оценок задуман, нужен запуск публикации (сейчас 404).
Счётчики записей — агрегатная оценка (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 (ниже, обновлён после пересоздания).