Merge branch 'phase/38-session'

# Conflicts:
#	docs/phases/README.md
#	tests/HSchool.AppHost.Tests/PortraitApiTests.cs
This commit is contained in:
Leonid Pershin
2026-08-20 07:25:12 +03:00
25 changed files with 1003 additions and 27 deletions
+39
View File
@@ -25,9 +25,48 @@ closes connections whose hello carries a different version with `1002 ProtocolEr
## HTTP API
Most routes require a signed session cookie set by `POST /api/session`. Without it the server
returns `401`. Public exceptions: `GET /health` and the three `/api/session` routes.
Game dates are ISO-8601 UTC instants. The in-game calendar has no time zone — UTC is only used so
the wire format is unambiguous, and the client formats it back in UTC.
### `POST /api/session`
Alpha login. Body:
```json
{ "password": "alpha", "userName": "Leo" }
```
Success (`200`) sets an HttpOnly cookie (`SameSite=Lax`, `Path=/`) and returns:
```json
{ "userName": "Leo" }
```
The name is normalized like a school name (trim, no control characters, 140 chars). Occupancy is
case-insensitive: `Leo` and `leo` are the same person; the first spelling is kept in
`saves/users.json`.
| Status | `code` | When |
| --- | --- | --- |
| `401` | `bad-password` | Wrong alpha password |
| `400` | `invalid-name` | Name fails normalization |
| `409` | `name-online` | A live WebSocket already uses that name |
### `GET /api/session`
Returns `{ "userName": "Leo" }` when the cookie is valid, otherwise `401`.
### `DELETE /api/session`
Clears the session cookie. `204`.
The WebSocket at `/ws/game` uses the same cookie on upgrade. Without a valid cookie the server
closes the connection with a policy violation and never sends Welcome. Hello is unchanged
(version + locale only).
### `GET /api/schools`
Everything the main menu needs in one request. `schoolWeekDays` is 57 working days counted