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
+39
View File
@@ -0,0 +1,39 @@
# Фаза 10. Предметы и мебель
## Зависимости
- [Фаза 5](../02-people/05-people-defs.md)
- [Фаза 7](../02-people/07-people-in-school.md)
## Зачем
Каталог учится описывать предметы, кабинет перестаёт быть таблицей слотов, а должность учителя
становится одной на всех. Людей это ещё не двигает: школа собирается как прежде.
## Задачи
- [x] `SubjectDef` в `HSchool.Content`: развиваемые навыки с долями, диапазон параллелей;
ссылка на неизвестный навык — ошибка загрузки
- [x] Ванильные предметы в `core`: начальные классы (1–4, всё понемногу) и предметники по
существующим навыкам, включая физкультуру
- [x] `PositionDef PETeacher` упраздняется; `Classroom`, `ComputerLab` и `GymHall` больше не
открывают учительскую должность
- [x] Кабинет-`Homeroom` описывается числом мест, а не таблицей именованных слотов; вместимость
по-прежнему считается по мебели
- [x] Слоты остаются у столовой, медкабинета, кабинета директора и библиотеки
- [x] Редактор карты показывает у кабинета одно поле «мест», у прочих комнат — прежние слоты
- [x] Ванильная карта переписана под новую форму, вместимость параллелей не изменилась
- [x] `GET /api/catalog` отдаёт предметы — они понадобятся форме назначения
- [x] Стартовая дата по умолчанию — суббота 31 марта 2012
- [x] Снимок карты и `docs/protocol.md` правятся в том же коммите, если меняется раскладка узла
## Критерий готовности
- Каталог `core` грузится, предметы проходят валидацию, тест на полноту локалей зелёный
- Школа на ванильной карте даёт те же одиннадцать классов и ту же вместимость, что и до фазы
- Редактор карты не показывает у кабинета ни доски, ни стула учителя
- `dotnet test` и клиентские `npm test` / `build` проходят
## Стоп
Не трогать наём. Генератор пока закрывает должности сам — школа опустеет в следующей фазе.
+44
View File
@@ -0,0 +1,44 @@
# Фаза 11. Пустая школа и пул соискателей
## Зависимости
- [Фаза 10](10-subjects.md)
- [Фаза 6](../02-people/06-people-generator.md)
## Зачем
Школа открывается без единого сотрудника, а рядом появляется пул людей, готовых наняться.
Нанимать пока нечем — это фаза про данные.
## Задачи
- [x] `RosterGenerator` больше не закрывает должности: новая школа получает учеников, родителей
и ноль сотрудников
- [x] Пул соискателей в `HSchool.People`: список полноценных `Person`, детерминированный от сида
школы и номера недели
- [x] Соискателем может стать родитель ученика — тот же человек, без второй сущности
- [x] Базовый запрос по зарплате считается из навыков соискателя; шкала — в данных, не в коде
- [x] Еженедельное обновление: часть уходит, часть остаётся с теми же именами и запросом,
приходят новые. Полная замена запрещена
- [x] Пул живёт в `saves/{id}.people.json` рядом с ростером и пишется по тем же правилам —
при изменении состава, не по таймеру
- [x] Воркер публикует пул вместе со снимком ростера
## Тесты, без которых фаза не закрыта
- [x] Тот же сид и та же неделя — тот же пул
- [x] После обновления часть людей та же самая, с теми же навыками и тем же запросом
- [x] Пул не пустеет и не растёт бесконечно за пятьдесят недель
- [x] Запрос по зарплате у сильного кандидата выше, чем у слабого
- [x] Новая школа не имеет ни одного сотрудника, но все ученические места заняты
- [x] Соискатель не попадает в ростер школы, пока не нанят
## Критерий готовности
- Создать школу — в списке людей есть ученики и родители, работников нет
- Перезапуск сервера поднимает тот же пул
- `dotnet test` проходит
## Стоп
Ни найма, ни денег, ни назначения предметов. Пул только существует и обновляется.
@@ -0,0 +1,43 @@
# Фаза 12. Наём, предметы и предел бюджета
## Зависимости
- [Фаза 11](11-applicants.md)
## Зачем
Игрок нанимает людей и раздаёт предметы, а выделенная сумма ограничивает, сколько он может себе
позволить. Экрана ещё нет — всё через API.
## Задачи
- [x] Выделяемая на месяц сумма — в `SimulationOptions`, с умолчанием
- [x] Фонд оплаты школы: у каждого цена часа × недельная нагрузка, но не меньше одной ставки.
Нагрузка берётся из учебного плана и делится между учителями предмета
- [x] Наём: соискатель уходит из пула, становится работником, попадает в ростер. Родитель
остаётся родителем — новой сущности не заводится
- [x] Назначение предмета нанятому и снятие предмета
- [x] Предел проверяется **в момент действия**: наём или назначение, выводящее фонд за
выделенную сумму, отклоняется с внятным кодом ошибки, а не откладывается до конца месяца
- [x] Покрытие предметов: какие предметы преподаются в существующих параллелях и не имеют ни
одного учителя
- [x] `GET /api/schools/{id}/staffing` — деньги, покрытие, пул и штат; читает опубликованный
снимок, воркер не трогает
- [x] Наём и назначение идут в воркер через мейлбокс с `TaskCompletionSource`, как create и delete
- [x] Состав пишется на диск при изменении, снимок публикуется заново
- [x] `docs/protocol.md` пополняется в том же коммите, что и обработчики
## Критерий готовности
- Нанять двоих на 3 000 и 7 000 при выделенных 10 000 — третий наём отклонён
- Снять предмет — фонд уменьшился, наём снова возможен
- Назначение, не влезающее в предел, отклонено, и в ответе видно почему
- Перезапуск сервера поднимает школу с тем же штатом и теми же назначениями
- Тесты API: наём, повторный наём того же человека, отклонение по пределу, неизвестная школа,
неизвестный соискатель
- `dotnet test` проходит
## Стоп
Не увольнять. Не платить зарплату по месяцам — предел проверяется, деньги не движутся.
Не расписание.
@@ -0,0 +1,36 @@
# Фаза 13. Раздел «Управление»
## Зависимости
- [Фаза 12](12-hiring-budget.md)
- [Фаза 8](../02-people/08-people-browser.md)
## Зачем
Игрок собирает школу руками: видит деньги, перебирает соискателей, нанимает и раздаёт предметы.
## Задачи
- [x] Под часами появляются два верхних раздела: «Обзор» и «Управление». В «Обзоре» — всё, что
есть сейчас; часы и дата видны в обоих
- [x] Строка денег: выделено, расписано, свободно
- [x] Список непокрытых предметов — что школа не может преподавать
- [x] Список соискателей: имя, запрашиваемая ставка, сильные навыки; выбор показывает карточку
человека справа — ту же, что в «Людях»
- [x] Кнопка найма; отказ по пределу показывается текстом, а не молчанием
- [x] Список штата: кто нанят, какие предметы ведёт, сколько стоит
- [x] Назначение и снятие предмета с карточки нанятого
- [x] Строки через `t(...)`, обе локали
## Критерий готовности
- Создать школу, открыть «Управление», нанять учителя, назначить ему математику
- Дойти до предела — попытка нанять ещё одного объясняет, что денег нет
- Снять предмет и убедиться, что свободных денег стало больше
- Перейти в «Обзор» → «Люди» и увидеть нанятого в общем списке с ролью работника
- Нанять родителя ученика и увидеть у него обе роли на одной карточке
- `dotnet test` и клиентские `npm test` / `build` проходят
## Стоп
Не увольнять из интерфейса. Не показывать расписание и нагрузку по часам — только предметы.
+18
View File
@@ -0,0 +1,18 @@
Индекс срезов: [`../README.md`](../README.md).
## Срез 3. Штат
Дизайн: [`../design/staffing.md`](../../design/03-staffing/staffing.md).
Первый срез, где игрок принимает решения. Школа открывается пустой: надо нанять людей из пула
соискателей, раздать им предметы и уложиться в выделенную на месяц сумму. Уроков по-прежнему нет —
предмет это запись в нагрузке, а не событие в кабинете.
Фазы идут строго по порядку: каждая опирается на данные предыдущей.
| Фаза | Статус | Зачем |
| --- | --- | --- |
| [10. Предметы и мебель](10-subjects.md) | ✅ | `SubjectDef`, одна учительская должность, кабинет как число мест |
| [11. Пустая школа и пул](11-applicants.md) | ✅ | Школа без сотрудников, соискатели с запросом по зарплате |
| [12. Наём и бюджет](12-hiring-budget.md) | ✅ | Наём, назначение предметов, предел фонда оплаты |
| [13. Раздел «Управление»](13-management-tab.md) | ✅ | Деньги, соискатели, штат и назначения на экране |
+44
View File
@@ -0,0 +1,44 @@
# Журнал ревью
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
## Срез 3. Штат
- **Фазы:** 1013
- **Проверен на:** `bdb1253`, 2026-08-20
- **Пути:** `src/HSchool.People/Staffing.cs`, `src/HSchool.People/ApplicantPool.cs`,
`src/HSchool.Content/SubjectDef` и `defs/staffing`, `src/HSchool.Server/Api/SchoolEndpoints.cs`
(staffing/hire/subjects), `src/HSchool.Server/mods/core/defs/{subjects,positions,rooms,staffing,traits}`,
`src/HSchool.Client/src/ui/managementPanel.ts`, `src/HSchool.Client/src/net/api.ts`,
`tests/HSchool.People.Tests/{StaffingTests,ApplicantPoolTests}.cs`,
`tests/HSchool.AppHost.Tests/StaffingApiTests.cs`,
`src/HSchool.Client/src/ui/managementPanel.test.ts`
- **Итог:** обещания фаз 10–13 целы; дописаны 3 теста; `docs/protocol.md` дополнен `?lang=`
Что подтверждено:
- `PETeacher` нет; кабинеты без учительской должности; места через `defaultSeats`.
Неизвестный навык в предмете роняет каталог. Стартовая дата 31 марта 2012.
- Пул: детерминизм по сиду и неделе, частичное обновление, устойчивый размер, «сильный просит
больше», пустой штат, соискатель вне ростера до найма. Пул 32.
- Фонд оплаты, деление часов, пол ставки, покрытие. `GET /staffing` читает снимок, наём и
назначение — `GameCommand` с `TaskCompletionSource`. `MaxWeeklyHours` не запрещает назначение,
а оставляет предмет непокрытым. `PrimarySchool` на ванили требует трёх учителей (`teachersShort`).
- Экран: деньги, непокрытые, пул, штат, назначение с карточки, отказ по пределу текстом,
всё через `t(...)`.
- Полностью укомплектованная школа влезает в 100 000 впритык (запас 5–13%). Нанять пул целиком
без назначений предела достигает. Раскладка «каждому все предметы» — самая дешёвая, не
«укомплектованная школа».
Дописано:
- `StaffingApiTests.AssigningPastTheCap_IsRejectedWithTheNumbers` — фаза 12 требовала API-тест
на отказ по пределу; единственное место было написано через `if (over.StatusCode == Conflict)`
и проходило при любом исходе.
- `ApplicantPoolTests.ConfidentTraits_AskForMoreAndQuietOnesForLess`
- В `AssignAndUnassign_HonourTheCap_AndReloadKeepsAssignments` — тот же пул с теми же ставками
после перезапуска.
Исправлено:
- `docs/protocol.md` не упоминал `?lang=` у hire/subjects, хотя клиент его шлёт.