Merge branch 'phase/39-school-owners'
ci / server (push) Failing after 3m51s
ci / client (push) Successful in 18s

This commit is contained in:
Leonid Pershin
2026-08-20 09:56:13 +03:00
34 changed files with 1107 additions and 267 deletions
+22 -7
View File
@@ -76,16 +76,26 @@ people; it does not change on a living school.
```json
{
"maxSchools": 6,
"maxSchools": 2,
"maxSchoolsTotal": 16,
"defaultStartDate": "2012-03-31T06:00:00Z",
"gameMinutesPerRealSecond": 1,
"schoolWeekDays": 5,
"schools": [
{ "id": 1, "name": "Гимназия №14", "gameTime": "2012-03-31T07:35:00Z", "running": false, "speedIndex": 1, "modIds": ["core"], "seed": 1847291 }
{ "id": 1, "name": "Гимназия №14", "gameTime": "2012-03-31T07:35:00Z", "running": false, "speedIndex": 1, "modIds": ["core"], "seed": 1847291, "mine": true }
],
"others": [
{ "id": 2, "name": "Лицей", "gameTime": "2012-03-31T06:00:00Z", "running": true, "speedIndex": 1, "modIds": ["core"], "seed": 9912, "owner": "Leo" }
]
}
```
`maxSchools` is how many schools **this player** may own; `maxSchoolsTotal` is how many workers the
process runs. `schools` lists yours (`mine: true` on each card). `others` lists every other save on
the server — `owner` is the display name, or `null` when the save has no owner (any logged-in player
may delete an ownerless card). The WebSocket welcome frame still carries one byte for
`maxSchools`; it now means the same per-player limit, not the process total.
### `GET /api/schools/random-name`
`{ "name": "Лицей «Северная»" }` — a suggestion that is not already taken.
@@ -197,13 +207,15 @@ the global file, so a guest watching the school draws with the same model.
| `400` `unknown-country` | `countryId` is not a placeable `CountryDef` in those packs. |
| `400` `unknown-native-language` | `nativeLanguage` is not in that country's `nativeLanguages`. |
| `400` `invalid-portrait-settings` | `portraitSettings` failed validation (empty presets, bad age rule, out of range). |
| `409` `school-limit-reached` | `maxSchools` schools already exist. |
| `409` `school-limit-reached` | This player already owns `maxSchools` schools. |
| `409` `server-full` | The process already runs `maxSchoolsTotal` schools. |
Failures are RFC 7807 problem details with an extra `code` field — that is what the UI switches on.
### `DELETE /api/schools/{id}`
`204` when deleted, `404` when the id is unknown. Anyone watching that school over a WebSocket
`204` when deleted, `404` when the id is unknown, `403` `not-owner` when the school belongs to
another player. Ownerless saves may be deleted by any logged-in session. Anyone watching that school over a WebSocket
gets a `SchoolGone` frame.
### `GET /api/schools/{id}/people`
@@ -497,7 +509,8 @@ is off or unreachable, `connected` is false and the lists are empty.
### `GET /api/schools/{id}/dress-rules`
Student and staff dress-code pairs for the school. Unknown `{id}` is `404` `unknown-school`.
Student and staff dress-code pairs for the school. Only the owner may read this (`403` `not-owner`).
Unknown `{id}` is `404` `unknown-school`.
`form` is one of `regular`, `short`, `strict`. `color` is one of `noBright`, `whiteTopBlackBottom`,
`free`. When a `POST` has been accepted but not yet applied, `pendingStudents` and/or `pendingStaff`
@@ -515,7 +528,7 @@ not immediately.
### `POST /api/schools/{id}/dress-rules`
Queues a change for the next work morning. Either or both of `students` and `staff` may be sent;
Queues a change for the next work morning. Only the owner may post (`403` `not-owner`). Either or both of `students` and `staff` may be sent;
omitted sides keep their current rule. Unknown `{id}` is `404` `unknown-school`. Unknown `form` or
`color` is `400` `unknown-form` / `400` `unknown-color`. Response body matches `GET`.
@@ -525,7 +538,8 @@ omitted sides keep their current rule. Unknown `{id}` is `404` `unknown-school`.
### `GET /api/schools/{id}/staffing`
Money, uncovered subjects, the applicant pool and current staff. Reads the **published**
Money, uncovered subjects, the applicant pool and current staff. Only the owner may read this
(`403` `not-owner`). Reads the **published**
roster, applicant snapshot and catalog — it does not post to the worker. Unknown `{id}` is
`404` `unknown-school`. `?lang=ru|en` labels subjects and positions.
@@ -619,6 +633,7 @@ of that kind.
| Status | `code` | When |
| --- | --- | --- |
| `403` | `not-owner` | The session is not the school's owner. |
| `404` | `unknown-school` | No school with that id. |
| `404` | `unknown-applicant` | `personId` is not in the pool. |
| `409` | `already-hired` | That person is already staff. |