ab58062565
- accounts.flagged_high_rate_at baked into the R1 baseline (no prod data; the contour schema is wiped after merge); jet regenerated — the regen also picks up the previously missing game_drafts/game_hidden models. - account.Store: FlagHighRate (set-once), ClearHighRateFlag, the flag in GetByID/ListUsers and a ListFlaggedHighRate review queue. - New internal/ratewatch: ingests the gateway rejection reports, keeps a bounded in-memory episode window for the console and applies the conservative auto-flag (1000 rejected / 10 min, BACKEND_HIGHRATE_FLAG_*). - POST /api/v1/internal/ratelimit/report (network-trusted, like sessions/resolve). - Admin console: Throttled page (episodes + flagged accounts), a high-rate badge in the user list, the marker + operator clear action on the user card. - Tests: ratewatch unit suite, report-route handler test, renderer cases, integration coverage for the store round-trip and the console flow.
38 lines
1.6 KiB
Go Template
38 lines
1.6 KiB
Go Template
{{define "content" -}}
|
|
<h1>Users</h1>
|
|
{{with .Data}}
|
|
<nav class="subnav">
|
|
<a href="/_gm/users"{{if not .Robots}} class="active"{{end}}>People</a> ·
|
|
<a href="/_gm/users?kind=robots"{{if .Robots}} class="active"{{end}}>Robots</a>
|
|
</nav>
|
|
<form class="form" method="get" action="/_gm/users">
|
|
{{if .Robots}}<input type="hidden" name="kind" value="robots">{{end}}
|
|
<input name="name" value="{{.NameMask}}" placeholder="display name mask (* ?)">
|
|
<input name="ext" value="{{.ExternalIDMask}}" placeholder="external id mask (* ?)">
|
|
<button type="submit">Filter</button>
|
|
</form>
|
|
<table class="list">
|
|
<thead><tr><th>Account</th><th>Display name</th><th>Kind</th><th>Lang</th><th>Created</th><th title="per-move think time across all games">Move min</th><th>avg</th><th>max</th></tr></thead>
|
|
<tbody>
|
|
{{range .Items}}
|
|
<tr>
|
|
<td><a href="/_gm/users/{{.ID}}">{{.ID}}</a></td>
|
|
<td>{{.DisplayName}}{{if .Guest}} <span class="pill">guest</span>{{end}}{{if .FlaggedHighRate}} <span class="pill">high-rate</span>{{end}}</td>
|
|
<td>{{.Kind}}</td>
|
|
<td>{{.Language}}</td>
|
|
<td>{{.CreatedAt}}</td>
|
|
{{if .HasMoveStats}}<td>{{.MoveMin}}</td><td>{{.MoveAvg}}</td><td>{{.MoveMax}}</td>{{else}}<td colspan="3"><span class="note">—</span></td>{{end}}
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="8"><span class="note">no users</span></td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
<nav class="pager">
|
|
{{if .Pager.HasPrev}}<a href="/_gm/users?{{.FilterQuery}}&page={{.Pager.PrevPage}}">« prev</a>{{end}}
|
|
<span>page {{.Pager.Page}} · {{.Pager.Total}} total</span>
|
|
{{if .Pager.HasNext}}<a href="/_gm/users?{{.FilterQuery}}&page={{.Pager.NextPage}}">next »</a>{{end}}
|
|
</nav>
|
|
{{end}}
|
|
{{- end}}
|