panel: clearer L1 rate-limit display and status badges
test / test (push) Has been cancelled
release / prepare (push) Has been cancelled
release / build (amd64, ubuntu-latest) (push) Has been cancelled
release / build (arm64, ubuntu-24.04-arm) (push) Has been cancelled
release / merge (push) Has been cancelled

Show the level-1 backstop as its own line and code-row, use st badges for
active/inactive domain and app limits, and fold the polish into 1.2.4.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-12 23:37:12 +03:00
parent 6671bd3393
commit 584f8cbc1c
4 changed files with 35 additions and 25 deletions
+6 -2
View File
@@ -7,8 +7,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
## [1.2.4] - 2026-08-12
Level-2 rate-limit semantics inverted after 1.2.3, plus a small DNS field
height fix. Upgrading is a tag bump; no migration.
Level-2 rate-limit semantics inverted after 1.2.3, with clearer L1 display and
status badges. Upgrading is a tag bump; no migration.
### Changed
@@ -20,6 +20,10 @@ height fix. Upgrading is a tag bump; no migration.
level-1 backstop on domain/application forms and Settings, rejects maxima
above level 1, and requires an application override to exceed the domain
maximum. Operator guide and architecture updated.
- panel: level-1 backstop is shown as a dedicated line (`N messages / Ws`) and
in message-limit labels; Settings uses a code-row for the L1 value. Domain
and application rate-limit status uses the shared `st` badge (`active` /
`inactive — level 1 only`). Trusted-IP override copy is a single paragraph.
### Fixed
+20 -18
View File
@@ -316,7 +316,7 @@
.panel-toggle in panel.css. -->
<div class="actions">
<input class="panel-toggle t-edit" id="edit-{{.ID}}" type="checkbox">
<label class="toggle for-edit" for="edit-{{.ID}}">Edit{{if .HasLimit}} (limit active){{end}}</label>
<label class="toggle for-edit" for="edit-{{.ID}}">Edit{{if .HasLimit}} <span class="st st-ok">limit</span>{{end}}</label>
<form class="inline" method="post" action="/applications/{{.ID}}/password"
data-confirm="Regenerate the password for {{.Login}}? The current password stops working immediately.">
<button type="submit">New password</button>
@@ -344,21 +344,21 @@
</form>
</div>
<div class="check-col">
<p class="check-col-title">Optional trusted-IP override</p>
<p class="muted">Listed client IPs get a higher ceiling than the
domain limit (still capped by level&nbsp;1:
{{$.L1Messages}} / {{$.L1Window}}s —
<a href="/settings">Settings</a>).
{{if $.DomainHasRL}}Domain ceiling: {{$.DomainRLMaxNum}}.{{else}}No domain ceiling (level&nbsp;1 only for other IPs).{{end}}</p>
<p class="check-col-title">Optional trusted-IP override
{{if .HasLimit}}<span class="st st-ok">active</span>{{else}}<span class="st st-unknown">inactive</span>{{end}}</p>
<p class="muted">These IPs get a higher ceiling than the domain
(≤ level&nbsp;1) and skip the domain check; everyone else uses
{{if $.DomainHasRL}}the domain ceiling ({{$.DomainRLMaxNum}}){{else}}level&nbsp;1 only{{end}}.</p>
<p>Level&nbsp;1 backstop:
<strong>{{$.L1Messages}}</strong> messages /
<strong>{{$.L1Window}}</strong>s
<a href="/settings#rate-limits">Settings</a>.</p>
<form id="rl-{{.ID}}" method="post" action="/applications/{{.ID}}/ratelimit">
<label>Trusted client IPs (required; one per line or comma-separated)</label>
<textarea name="allowed_ips" rows="2" placeholder="203.0.113.10">{{.IPsText}}</textarea>
<p class="muted">Only these IPs use the application ceiling and
skip the domain limit. Other IPs stay under the domain (or
level&nbsp;1).</p>
<div class="field-pair">
<div>
<label>Message limit</label>
<label>Message limit (max {{$.L1Messages}})</label>
<input name="max_messages" type="number" min="1" max="{{$.L1Messages}}"
value="{{.MaxText}}" placeholder="{{$.L1Messages}}">
</div>
@@ -420,17 +420,19 @@
</div>
<div class="check-col">
<p class="check-col-title">Optional level-2 sending rate limit</p>
<p class="muted">Applies to every client IP on this domain. Status:
{{if .DomainHasRL}}<strong>active</strong>{{else}}inactive (level&nbsp;1 only){{end}}.
Level&nbsp;1 backstop: {{.L1Messages}} messages / {{.L1Window}}s
(<a href="/settings">Settings</a>). Leave the message limit empty to
use level&nbsp;1 only.</p>
<p class="check-col-title">Optional level-2 sending rate limit
{{if .DomainHasRL}}<span class="st st-ok">active</span>{{else}}<span class="st st-unknown">inactive — level 1 only</span>{{end}}</p>
<p class="muted">Applies to every client IP on this domain. Leave the
message limit empty to use level&nbsp;1 only.</p>
<p>Level&nbsp;1 backstop (from <code>.env</code>):
<strong>{{.L1Messages}}</strong> messages /
<strong>{{.L1Window}}</strong>s
— see <a href="/settings#rate-limits">Settings</a>.</p>
<form method="post" action="/domains/{{.Domain.ID}}/ratelimit">
<div class="field-pair">
<div>
<label for="d_max">Message limit</label>
<label for="d_max">Message limit (max {{.L1Messages}})</label>
<input id="d_max" name="max_messages" type="number" min="1" max="{{.L1Messages}}"
value="{{.DomainRLMax}}" placeholder="{{.L1Messages}}">
</div>
+3 -3
View File
@@ -110,9 +110,9 @@ this one stays signed in.</p>
each domain's page.</p>
<label>Level 1 — per client IP (Postfix)</label>
<p><strong>{{.L1Messages}}</strong> messages per <strong>{{.L1Window}}</strong>
seconds (<code>RATE_LIMIT_MESSAGES_PER_IP</code> /
<code>RATE_LIMIT_WINDOW_SECONDS</code>). Hard ceiling for every connecting IP;
<p class="code-row"><span class="code">{{.L1Messages}} messages / {{.L1Window}} seconds</span></p>
<p class="muted"><code>RATE_LIMIT_MESSAGES_PER_IP</code> /
<code>RATE_LIMIT_WINDOW_SECONDS</code>. Hard ceiling for every connecting IP;
the panel cannot raise a domain or application limit above this.</p>
<label>Level 2 — domain</label>
+6 -2
View File
@@ -244,8 +244,11 @@ func TestDomainDetailPageHasPairedCards(t *testing.T) {
if strings.Contains(src, `id="d_ips"`) {
t.Error("domain rate limit must not ask for client IPs")
}
if !strings.Contains(src, "level&nbsp;1") {
t.Error("domain rate limit should mention the level-1 backstop")
if !strings.Contains(src, "{{.L1Messages}}") && !strings.Contains(src, "{{$.L1Messages}}") {
t.Error("domain rate limit should show the L1 message count")
}
if !strings.Contains(src, "Level&nbsp;1 backstop") {
t.Error("domain rate limit should show a Level 1 backstop line")
}
if !strings.Contains(src, "Trusted client IPs") {
t.Error("application override should ask for trusted client IPs")
@@ -268,6 +271,7 @@ func TestSettingsPageDocumentsRateLimits(t *testing.T) {
"RATE_LIMIT_MESSAGES_PER_IP",
"Level 2 — domain",
"trusted IPs",
"{{.L1Messages}} messages / {{.L1Window}} seconds",
} {
if !strings.Contains(src, want) {
t.Errorf("settings rate limits card missing %q", want)