Remove off-queue.md and add new design documentation files including README.md, defs.md, near-term.md, projects.md, runtime.md, people.md, staffing.md, and schedule.md to outline the structure and agreements for the game's design phases.

This commit is contained in:
Leonid Pershin
2026-08-20 12:26:13 +03:00
parent 12cc36b4dd
commit a37a5eb82d
101 changed files with 1015 additions and 921 deletions
@@ -0,0 +1,33 @@
# Фаза 14. Каркас дня и каникулы
## Зависимости
- [Фаза 10](../03-staffing/10-subjects.md)
## Зачем
Школа получает учебный календарь: во сколько звонок, сколько уроков, какие дни рабочие и когда
каникулы. Расписания ещё нет — есть время, в которое его можно будет положить.
## Задачи
- [x] Каркас дня в `core` дефом: начало первого урока, число уроков, длина урока, длины перемен
и какая из них большая
- [x] Длина учебной недели — в `SimulationOptions`, пять дней по умолчанию
- [x] Каникулы дефами: осенние, зимние, весенние, лето — диапазонами дат внутри учебного года
- [x] Запрос «какой сейчас слот»: номер урока или перемена, или «вне учебного дня» — по игровому
времени, выходным и каникулам
- [x] Требование к типу помещения у `SubjectDef`: физкультура в спортзале, информатика в
компьютерном классе; без требования — кабинет класса
- [x] `GET /api/catalog` отдаёт каркас дня — он понадобится сетке расписания
## Критерий готовности
- В субботу, в каникулы и в 23:00 запрос слота отвечает «занятий нет»
- В 10:20 буднего учебного дня отвечает конкретным номером урока
- Смена длины недели в настройках делает субботу рабочей
- `dotnet test` проходит
## Стоп
Ни одного урока не ставится. Ни планировщика, ни экрана.
@@ -0,0 +1,41 @@
# Фаза 15. Планировщик
## Зависимости
- [Фаза 14](14-school-calendar.md)
- [Фаза 12](../03-staffing/12-hiring-budget.md)
## Зачем
Из учебного плана, назначений и карты получается таблица уроков. Библиотека проверяется тестами,
без мира и без хоста, как генератор людей.
## Задачи
- [x] Новый проект рядом с `HSchool.People`: зависит только на `HSchool.Content`, без Arch и
ASP.NET; отдаёт простую таблицу уроков
- [x] Раскладка часов учебного плана по слотам недели для каждого класса
- [x] Кабинет урока: требование предмета, иначе кабинет класса
- [x] Четыре запрета соблюдаются: учитель, класс и кабинет не заняты дважды, класс влезает в кабинет
- [x] Непокрытые часы не ставятся, а возвращаются отдельным списком — их покажет «Управление»
- [x] Закреплённые игроком уроки принимаются на вход и переживают перестроение; остальное
раскладывается вокруг них
- [x] Детерминированность: те же штат, назначения и карта дают ту же таблицу
## Тесты, без которых фаза не закрыта
- [x] Один спортзал на одиннадцать классов — физкультура разъезжается по слотам, а не дублируется
- [x] Учитель с двумя предметами не стоит в двух местах в одном слоте
- [x] Класс на 16 не попадает в кабинет на 12
- [x] Предмет без учителя даёт дыру и запись в непокрытых
- [x] Закреплённый урок остаётся на месте после найма ещё одного учителя
- [x] Те же входы — та же таблица
## Критерий готовности
- Тесты библиотеки зелёные
- В проекте нет упоминаний сокетов, ECS и `DateTime.Now`
## Стоп
Не трогать сервер, сейв и клиент. Таблица пока никуда не уезжает.
@@ -0,0 +1,38 @@
# Фаза 16. Расписание в школе
## Зависимости
- [Фаза 15](15-timetable-planner.md)
## Зачем
Расписание живёт в школе, переживает перезапуск и отвечает на вопрос «кто где сейчас». Экрана
ещё нет.
## Задачи
- [x] Расписание пересобирается при найме, увольнении и изменении назначений — **не по тику**
- [x] Хранится в сейве рядом с составом; пишется при изменении, не по таймеру. Закреплённые
игроком уроки сохраняются вместе с ним
- [x] Воркер публикует расписание снимком, как ростер
- [x] «Кто где сейчас» **вычисляется** из расписания и часов, а не хранится вторым состоянием
- [x] Команда закрепления и снятия закрепления урока — через мейлбокс воркера
- [x] `GET /api/schools/{id}/timetable` — расписание класса и расписание человека; читает
опубликованный снимок
- [x] Снимок карты отдаёт по узлу, что там сейчас идёт и у кого; протокол и `docs/protocol.md`
правятся тем же коммитом, версия бумпится
- [x] Панель локации получает данные для «Сейчас» и «Персонажей»
## Критерий готовности
- Нанять учителя математики — в расписании появились уроки математики
- Снять назначение — уроки исчезли, предмет стал непокрытым
- Передвинуть урок, нанять ещё одного человека — передвинутый остался на месте
- Перемотать время на ×4 через звонок — «кто где сейчас» меняется вместе с уроком
- В каникулы и в выходной никто нигде не находится
- Перезапуск сервера поднимает то же расписание с теми же закреплениями
- `dotnet test` проходит
## Стоп
Не рисовать расписание на экране. Не перемещать людей по карте.
@@ -0,0 +1,34 @@
# Фаза 17. Расписание на экране
## Зависимости
- [Фаза 16](16-timetable-in-school.md)
- [Фаза 13](../03-staffing/13-management-tab.md)
## Зачем
Школа перестаёт быть списком имён: видно, что происходит в комнатах прямо сейчас и как выглядит
неделя класса и учителя.
## Задачи
- [x] В дереве карты рядом с комнатой — что и у кого там сейчас: `Кабинет 204 (Математика · 5Б)`.
Свободная комната остаётся без скобок
- [x] Панель локации: «Сейчас» — урок и класс, «Персонажи» — учитель и ученики этого класса
- [x] В «Управлении» — расписание класса: сетка «день × урок», выбор параллели
- [x] В карточке человека — его личное расписание, рядом с навыками и семьёй
- [x] Правка урока из сетки: перенос и смена кабинета, видимая отметка «закреплено» и снятие
- [x] Отказ планировщика (некуда поставить, кабинет занят) объясняется текстом, а не молчанием
- [x] Строки через `t(...)`, обе локали
## Критерий готовности
- Открыть школу в учебное время и увидеть в дереве занятые кабинеты, а в каникулы — пустые
- Открыть расписание 5Б, найти окно на месте непокрытого предмета
- Открыть учителя и увидеть те же уроки с его стороны
- Передвинуть урок и убедиться, что он не разъехался после найма
- `dotnet test` и клиентские `npm test` / `build` проходят
## Стоп
Не общая сетка на всю школу. Не оценки и не посещаемость. Не анимация перемещений.
+16
View File
@@ -0,0 +1,16 @@
Индекс срезов: [`../README.md`](../README.md).
## Срез 4. Расписание
Дизайн: [`../design/schedule.md`](../../design/04-schedule/schedule.md).
Часы учебного плана раскладываются по дням и кабинетам. Школа начинает жить по времени: видно,
что идёт в комнате прямо сейчас. Люди при этом по-прежнему **не ходят** — они находятся там, где
их застало расписание.
| Фаза | Статус | Зачем |
| --- | --- | --- |
| [14. Каркас дня и каникулы](14-school-calendar.md) | ✅ | Звонки, длина недели, каникулы |
| [15. Планировщик](15-timetable-planner.md) | ✅ | Раскладка часов по слотам, четыре запрета |
| [16. Расписание в школе](16-timetable-in-school.md) | ✅ | Сейв, снимок, «кто где сейчас» |
| [17. Расписание на экране](17-timetable-screen.md) | ✅ | Скобки в дереве, сетка класса, расписание учителя |
+40
View File
@@ -0,0 +1,40 @@
# Журнал ревью
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
## Срез 4. Расписание
- **Фазы:** 1417
- **Проверен на:** `bdb1253`, 2026-08-20
- **Пути:** `src/HSchool.Schedule`, `src/HSchool.Content` (каркас дня, каникулы, `SubjectDef.room`),
`src/HSchool.Simulation/SchoolTimetables.cs`, `src/HSchool.Server/Api/TimetableEndpoints.cs`,
`src/HSchool.Server/Game/SchoolWorker.cs` (пин, перестроение),
`src/HSchool.Client/src/ui/timetableGrid.ts`, `src/HSchool.Client/src/ui/gameScreen.ts`,
`tests/HSchool.Schedule.Tests`, `tests/HSchool.Content.Tests/CalendarTests.cs`,
`tests/HSchool.Content.Tests/LunchBreakTests.cs`,
`tests/HSchool.AppHost.Tests/TimetableApiTests.cs`,
`src/HSchool.Client/src/ui/timetableGrid.test.ts`
- **Итог:** обещания фаз 14–17 целы; дописан тест на коды отказа пина; две строки дизайна
помечены как отменённые срезом 5
Что подтверждено:
- Календарь: суббота, каникулы и ночь — «вне учебного дня»; 10:20 вторника — третий урок;
шестидневка; зима через 1 января. Физкультура в спортзале. Обеденные смены в каркасе дня
(младшие после 3-го, старшие после 4-го).
- Планировщик: четыре запрета, класс не влезает в меньший кабинет, без Arch/ASP.NET/`DateTime.Now`.
- Перестроение только при `PeopleChanged` + `TimetableDirty`, не по тику. `GET /timetable`
читает снимок, пин — `TaskCompletionSource`. `Reload_RestoresLockedLessons`.
- Сетка, закрепление, тексты отказа (`pin-rejected` / `no-teacher` / `unknown-lesson`),
скобки в дереве из присутствия, личное расписание в карточке. Всё через `t(...)`.
- Занятость узла в протоколе v7 живёт в кадре `Presence`, не в снимке карты — фаза 19.
Дописано:
- `TimetableApiTests.PinAndUnpinRefusals_CarryTheDocumentedCodes``no-teacher`, `unknown-class`,
`unknown-subject`, `unknown-room`, `unknown-lesson`, `invalid-query`.
Исправлено:
- В `../../design/04-schedule/schedule.md` «панель локации из расписания» и «люди находятся по расписанию» помечены
как отменённые срезом 5.