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:
@@ -0,0 +1,39 @@
|
||||
# Фаза 5. Дефы человека
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 3](../01-shell/03-defs-map.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Каталог учится описывать людей. Ни одного человека в этой фазе не появляется — только типы,
|
||||
из которых их потом соберут.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [x] `SkillDef`, `TraitDef`, `BodyAttributeDef`, `NeedDef`, `NameSetDef` в `HSchool.Content`:
|
||||
новые `DefKind`, разбор, наследование и патчи на общих правилах
|
||||
- [x] `BodyAttributeDef` двух видов: число с распределением (рост, вес) и выбор из списка с
|
||||
весами (цвет волос, цвет глаз); распределение зависит от пола и возраста
|
||||
- [x] `SkillDef.bodyLimits` — зажимы навыка по свойству тела (`min` / `max`); ссылка на
|
||||
неизвестный атрибут или его значение — ошибка загрузки, а не тихий пропуск
|
||||
- [x] `TraitDef`: вес, несовместимости, ограничения по роли и возрасту, модификаторы навыков;
|
||||
односторонняя несовместимость считается взаимной
|
||||
- [x] `NameSetDef`: мужские и женские имена, фамилии с родовыми формами, правило отчества,
|
||||
модель склонения по умолчанию или явная таблица шести падежей на запись
|
||||
- [x] Ванильное содержание `core`: навыки (предметы + физические), около десяти черт, четыре
|
||||
нужды со скоростью убывания **ноль**, славянский набор имён
|
||||
- [x] Локализация новых defs в `ru` и `en`
|
||||
- [x] `GET /api/catalog` отдаёт список наборов имён — форме создания нужен выбор
|
||||
- [x] Тесты Content: разбор каждого вида, наследование навыка, патч черты, неизвестная ссылка —
|
||||
ошибка, склонение по правилу и перекрытие таблицей
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Каталог `core` грузится, все новые defs проходят валидацию
|
||||
- Мод, добавляющий свой набор имён и пару черт, виден в каталоге
|
||||
- `dotnet test` проходит; школы по-прежнему пустые
|
||||
|
||||
## Стоп
|
||||
|
||||
Не генерировать людей. Не трогать ECS, сервер сверх выдачи каталога и клиент сверх выбора набора.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Фаза 6. Библиотека генерации
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 5](05-people-defs.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Из каталога, карты и сида получаются люди — семьями и детерминированно. Библиотека тестируется
|
||||
без мира, без сокета и без хоста, как `HSchool.Content` сейчас.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [x] Новый проект `HSchool.People` и `tests/HSchool.People.Tests`; ссылка только на
|
||||
`HSchool.Content`, ни Arch, ни ASP.NET
|
||||
- [x] Записи `Person`, `Family`, `SchoolClass`, `Roster` — простые данные, не сущности
|
||||
- [x] Ёмкость из карты: `PupilSlots` по кабинетам и `RoomDef.positions` дают, сколько нужно
|
||||
учеников и каких работников
|
||||
- [x] Генерация семьями: взрослые → дети нужных возрастов → раскладка детей по параллелям и
|
||||
взрослых по должностям
|
||||
- [x] Совмещение ролей: работник может оказаться родителем ученика той же школы
|
||||
- [x] Порядок бросков зафиксирован: тело первым, навыки после, `bodyLimits` применяются зажимом
|
||||
- [x] Склонения: модели в коде, явная таблица из def перекрывает модель
|
||||
- [x] Сид школы приходит снаружи; сид каждой семьи выводится из него
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [x] Тот же сид, карта и набор имён — ровно тот же ростер
|
||||
- [x] Тринадцатая семья не меняет, как разыграны первые двенадцать (фамилия, состав, имена).
|
||||
Класс ребёнка при этом меняется — места раздаются вперемешку по школе, иначе братья и
|
||||
сёстры всегда оказывались одноклассниками; см. [`docs/design/02-people/people.md`](../../design/02-people/people.md)
|
||||
- [x] Фамилии, родовые формы и отчества внутри семьи согласованы
|
||||
- [x] Ученик с телосложением «полное» не получает высокую ловкость
|
||||
- [x] Все ученические места заполнены, все должности закрыты
|
||||
- [x] Школа из одного кабинета и школа из одиннадцати — обе собираются
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- `HSchool.People.Tests` зелёные
|
||||
- В проекте нет упоминаний сокетов, ECS и `DateTime.Now`
|
||||
|
||||
## Стоп
|
||||
|
||||
Не класть людей в `World`. Не трогать сервер, клиент и формат сейва.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Фаза 7. Люди в школе
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 6](06-people-generator.md)
|
||||
- [Фаза 2](../01-shell/02-school-worker.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Школа создаётся с людьми, они живут в её `World` и переживают перезапуск сервера. Экран пока
|
||||
не меняется — это фаза про данные.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [x] Ванильная карта дорабатывается до одиннадцати кабинетов; подписи кабинетов становятся
|
||||
номерами помещений («204»), а не именами классов
|
||||
- [x] Компоненты Arch под слои человека; сущности собираются из записей генератора
|
||||
- [x] Класс как сущность: параллель, литера, закреплённый кабинет
|
||||
- [x] Нужды тикают вместе со школой — механика есть, скорость в `core` нулевая
|
||||
- [x] `saves/{id}.people.json`: сид, люди, семьи, классы. Пишется **только** при изменении
|
||||
состава, не по таймеру; `saves/{id}.json` остаётся маленьким и частым
|
||||
- [x] Загрузка ростера при старте школы; ростер, не сходящийся с картой, оставляет школу
|
||||
незапущенной и файл нетронутым — как сейчас с картой
|
||||
- [x] Воркер публикует неизменяемый снимок ростера, как публикует `SchoolState`
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Создать школу — все ученические места и должности заняты
|
||||
- Перезапустить сервер — те же люди с теми же именами и характеристиками
|
||||
- Файл ростера не переписывается каждые тридцать секунд
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Ни панели, ни фильтров, ни HTTP списка людей. Никакого поведения: люди существуют и стоят.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Фаза 8. Просмотр людей
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 7](07-people-in-school.md)
|
||||
- [Фаза 1](../01-shell/01-manager-shell.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Игрок видит, кто учится и работает в его школе, не теряя из виду часы, карту и события.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [x] `GET /api/schools/{id}/people`: фильтры (роль, параллель, должность, пол, диапазон
|
||||
возраста), сортировка, страница. Читает **опубликованный снимок** ростера и не трогает
|
||||
воркер — инвариант «только поток школы касается школы» остаётся целым
|
||||
- [x] `GET /api/schools/{id}/people/{personId}`: карточка через мейлбокс воркера с
|
||||
`TaskCompletionSource`, потому что нужды живые
|
||||
- [x] Панель «Люди» в оболочке менеджера: фильтры, сортируемые колонки, пейджер. Сделана
|
||||
**вкладкой рядом с картой**, а не нижним рядом — заодно с экрана ушла пустая панель
|
||||
событий из фазы 1; см. [`docs/design/02-people/people.md`](../../design/02-people/people.md)
|
||||
- [x] Строка списка — только лёгкие поля: ФИО, роль, класс или должность, возраст, пол
|
||||
- [x] Карточка: тело, навыки, черты, нужды, семья со ссылками на родных — по ссылке открывается
|
||||
карточка родственника
|
||||
- [x] Строки и подписи через `t(...)`, как всё остальное
|
||||
- [x] `docs/protocol.md` пополняется в том же коммите, что и обработчики
|
||||
- [x] Тесты API: фильтр по роли и параллели, сортировка, границы страниц, неизвестная школа,
|
||||
неизвестный человек
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Открыть школу, отфильтровать учеников пятой параллели, отсортировать по фамилии
|
||||
- Открыть карточку ученика, увидеть родителей, перейти по ссылке к матери
|
||||
- Тысяча строк не роняет и не подвешивает панель
|
||||
- `dotnet test` и клиентские `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не редактировать людей. Не нанимать и не увольнять руками. Не показывать характеристики в списке —
|
||||
только в карточке.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Фаза 9. Годовой набор
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 7](07-people-in-school.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Состав перестаёт быть слепком момента создания. Первого сентября классы переходят в следующую
|
||||
параллель, старший выпускается, приходит новый первый.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [x] Переход по игровому календарю на 1 сентября: у каждого класса параллель +1
|
||||
- [x] Выпуск **старшей имеющейся** параллели — школа из четырёх кабинетов не ждёт одиннадцатого
|
||||
класса, чтобы кого-то выпустить
|
||||
- [x] Освободившийся кабинет достаётся новому первому классу; вместимость школы не меняется —
|
||||
её меняет только стройка
|
||||
- [x] Набор первого класса тем же генератором и теми же семьями: у нового ученика может
|
||||
оказаться брат или сестра в старшей параллели
|
||||
- [x] Выпускники уходят из ростера; их родители уходят тоже, если не осталось других детей в
|
||||
школе и они в ней не работают
|
||||
- [x] Ростер переписывается один раз за переход, снимок публикуется заново — не по тику
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Перемотать год на ×4: параллели сдвинулись, прежний выпускной класс исчез, появился новый первый
|
||||
- Вместимость школы до и после перехода совпадает
|
||||
- Перезапуск сервера после перехода поднимает новый состав
|
||||
- Тест на школу без одиннадцатой параллели: выпускается старшая имеющаяся
|
||||
|
||||
## Стоп
|
||||
|
||||
Не второгодники. Не переводы между школами. Не увольнения и наём работников.
|
||||
@@ -0,0 +1,19 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 2. Люди
|
||||
|
||||
Дизайн: [`../design/people.md`](../../design/02-people/people.md).
|
||||
|
||||
Школа наполняется людьми. Ученики, работники и родители существуют, показываются и обновляются
|
||||
раз в год — но **ничего не делают**: ни расписания, ни перемещений, ни влияния характеристик.
|
||||
|
||||
Фазы идут по порядку, кроме 8 и 9: обе зависят только от 7 и могут вестись параллельно
|
||||
(клиент / симуляция).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [5. Дефы человека](05-people-defs.md) | ✅ | Навыки, черты, тело, нужды, наборы имён в каталоге |
|
||||
| [6. Библиотека генерации](06-people-generator.md) | ✅ | `HSchool.People`: семьи из карты и сида |
|
||||
| [7. Люди в школе](07-people-in-school.md) | ✅ | Сущности в `World`, ростер на диске, 11 кабинетов в `core` |
|
||||
| [8. Просмотр людей](08-people-browser.md) | ✅ | Панель со списком, фильтрами и карточкой |
|
||||
| [9. Годовой набор](09-yearly-intake.md) | ✅ | Первое сентября: переход, выпуск, набор |
|
||||
@@ -0,0 +1,44 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 2. Люди
|
||||
|
||||
- **Фазы:** 5–9
|
||||
- **Проверен на:** `bdb1253`, 2026-08-20
|
||||
- **Пути:** `src/HSchool.People`, `src/HSchool.Content/PeopleDefs.cs`,
|
||||
`src/HSchool.Simulation/RosterSpawner.cs`, `src/HSchool.Simulation/School.cs`,
|
||||
`src/HSchool.Server/Api/SchoolEndpoints.cs`, `src/HSchool.Server/Game/PersonCardReader.cs`,
|
||||
`src/HSchool.Server/Game/SchoolWorker.cs`,
|
||||
`src/HSchool.Client/src/ui/peoplePanel.ts`, `src/HSchool.Client/src/ui/personCard.ts`,
|
||||
`tests/HSchool.People.Tests`, `tests/HSchool.Content.Tests/PeopleDefTests.cs`,
|
||||
`tests/HSchool.Simulation.Tests/PeopleInSchoolTests.cs`,
|
||||
`tests/HSchool.AppHost.Tests/PeopleApiTests.cs`,
|
||||
`tests/HSchool.AppHost.Tests/SchoolSeedTests.cs`
|
||||
- **Итог:** обещания фаз 5–9 целы; починены два API-теста, дописан один на reload после набора
|
||||
|
||||
Что подтверждено:
|
||||
|
||||
- Дефы человека: разбор, наследование, патч, неизвестная ссылка, склонение, мод со своим набором.
|
||||
- Генератор: шесть тестов списка фазы, без Arch/ASP.NET/`DateTime.Now`. Неполные семьи 5–10%.
|
||||
Сид — поле школы, не `school.Id`; хостовые тесты, которым нужен состав, передают сид явно.
|
||||
- Одиннадцать кабинетов, сущности в `World`, `PersistPeople` только при смене состава.
|
||||
Штат при создании пуст — это фаза 11.
|
||||
- Список с опубликованного снимка, карточка через `TaskCompletionSource`. Фильтры, пейджер,
|
||||
семейные ссылки, всё через `t(...)`. Вкладка рядом с картой, не нижний ряд — так записано
|
||||
в фазе 8 и в `../../design/02-people/people.md`.
|
||||
- Выпуск старшей имеющейся, вместимость, семьи через поколения, reload после набора.
|
||||
|
||||
Дописано:
|
||||
|
||||
- `PeopleApiTests.ReloadAfterTheYearlyIntake_RestoresTheNewComposition` — ждёт 1 сентября и
|
||||
требует состав **после** набора, отличный от исходного (детерминизм от сида иначе скрыл бы
|
||||
потерянный файл).
|
||||
|
||||
Исправлено:
|
||||
|
||||
- `Card_IncludesFamilyAndLiveNeeds` брал `People[0]` и требовал двух родителей. Состав зависит
|
||||
от сида; на чистом клоне первый ученик иногда из неполной семьи. Теперь ищет ученика с матерью
|
||||
и проверяет диапазон.
|
||||
- `List_SortsBySurname` требовал ordinal-порядок, сервер ставит Ё на место Е. Совпадали, пока
|
||||
в `core` не было фамилий на Ё.
|
||||
Reference in New Issue
Block a user