Coaches need an account to keep their gymnasts and routines. Sign in with Google (PR #71) cannot work on the course server: Google only accepts http for `localhost`, and the server address given by the course (`http://it2810-xx.idi.ntnu.no/project2`) has no https. So the accounts are our own: an e-mail address and a password. The sessions are already built (access token, rotating refresh token, `me`, `logout`). This issue adds the way to prove who you are, and nothing else changes in how the session works. ### What to do - **Schema:** `Coach.passwordHash` (nullable), `Coach.googleId` nullable (so Google can come back later), `Coach.email` stored normalized (lower case) and unique. A migration that is safe for the rows that dev login made. - **API:** `register(email, password, name)` and `login(email, password)`, both returning the same `AuthPayload` as today. The Google mutation becomes `loginWithGoogle` when it is built. - **Password storage:** Argon2id with the OWASP minimum (19 MiB, 2 passes, 1 lane) from `node:crypto` (`crypto.argon2`, Node 24), stored in the PHC string format so the parameters can change; rehash at login when they do. - **Password rules (OWASP Authentication Cheat Sheet):** at least 15 characters, at most 128, no composition rules, no silent truncation. One shared file for the server and the form (like `shared/names.ts`). - **Same answer for a wrong e-mail and a wrong password** (message, error code and time: a dummy hash when there is no such coach). - **Limit the failed attempts per account:** after 5 in a row the account is locked for 5 minutes and answers like a wrong password; a success resets the count. ### Done when - [ ] A coach can register and log in with e-mail and password; the password is never stored or logged in clear text. - [ ] Wrong e-mail, wrong password and a locked account give the same `UNAUTHENTICATED` answer. - [ ] Registering an address that is taken is refused in a way that is documented (see the trade-off in the docs). - [ ] Tests: hashing (format, rehash, wrong password), register, login, the same answer for unknown e-mail, the lock after 5 failures and its end, the shared rules. - [ ] `docs/API.md`, `docs/DATA_MODEL.md` and the new `docs/AUTHENTICATION.md` match the code.