Deferred security/correctness items captured during review of #48. Full patches + decision notes in PR body of #48. - [ ] **HIGH — Rate limiting on login endpoint** — `internal/server/server.go:186`, `internal/auth/auth.go:64`. Per-IP token bucket via `golang.org/x/time/rate`. - [ ] **HIGH — Unbounded SELECT in `system_history.go Query()`** — `internal/collectors/system_history.go:212`. Move dedup/merge into SQL `GROUP BY`. - [ ] **MEDIUM — Password echoed to terminal in user-cli** — `scripts/user-cli.go:42`. Use `golang.org/x/term.ReadPassword`. - [ ] **MEDIUM — `StartBroadcastLoop` ticker never stopped** — `internal/server/ws.go:145`. Accept `context.Context`, defer `ticker.Stop()`. - [ ] **LOW — WebSocket read pump has no read deadline** — `internal/server/ws.go:130`. Set read deadline + reset in pong handler.
Deferred security/correctness items captured during review of #48. Full patches + decision notes in PR body of #48.
internal/server/server.go:186,internal/auth/auth.go:64. Per-IP token bucket viagolang.org/x/time/rate.system_history.go Query()—internal/collectors/system_history.go:212. Move dedup/merge into SQLGROUP BY.scripts/user-cli.go:42. Usegolang.org/x/term.ReadPassword.StartBroadcastLoopticker never stopped —internal/server/ws.go:145. Acceptcontext.Context, deferticker.Stop().internal/server/ws.go:130. Set read deadline + reset in pong handler.