queue-table: Outbound › Queue as the drawn table, Inbound › Queue built

Owner, 2026-10-18: "Фиаско, что очередь не была сделана. Как мы это
допустили? Исправляем!" The mockups out-queue and in-queue (design 629de5e,
guards 8525e8e).

- postfix: postqueue -j gives each message's size and each recipient's
  delay_reason (src/postqueue/showq_json.c, format_json(): "delay_reason"
  only when LEN(why) > 0); QueueListing reads it with the page's 5 s,
  QueueMessages keeps the notifier's 30 s.
- view: one Queue page type for both directions (queue.go), one polled box
  (queue_body.html): a row per recipient, oldest first, cut at 200 with a
  foot; the head "N messages · size", "Refreshes on its own" while empty;
  Last reply is the delay reason, or where the message is (active, hold,
  incoming) before there was one. Inbound has no Details: an inbound
  message has no page of its own.
- handlers: one read of the queue, split by the recipient's domain against
  the inbound domains; an outbound recipient is linked to its send-log row
  (store.SendLogRefsByQueueID, through idx_send_log_queue_id, plan pinned in
  TestSendLogQueriesUseTheirIndexes), matched without regard to case, else
  the message's first row. Both pages are the global role's; the inbound
  one 404s with the relay off. Routes /inbound/queue (+ /fragment), menu,
  touch menu and sibling strip.
- Overview: Queues · Both empty · outbound and inbound with the relay on.
- Help: the queue topic rewritten, an Inbound queue topic (word for word with
  the mockup; domain administrators do not see it, as with the lists).
- TestUnbuiltScreensAreOnTheRoadmap and its rule in development.md: an
  exempted screen must be named in roadmap.md; queue-table leaves the
  roadmap; guide, architecture, panel-redesign.md updated.

Tests: go vet; go test ./internal/web/... ./internal/store ./internal/postfix
./internal/notify pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-18 23:17:14 +03:00
co-authored by Claude Opus 5.5
parent 8525e8ee8d
commit 6db3704711
34 changed files with 893 additions and 246 deletions
+15 -10
View File
@@ -47,6 +47,7 @@ var pageFixtures = map[string]func() any{
"in-domain": func() any { return inDomainFixture() },
"in-domain-delete": func() any { return inDomainDeleteFixture() },
"in-log": func() any { return inLogFixture() },
"in-queue": func() any { return inQueueFixture() },
"in-filter-lists": func() any { return inFilterListsFixture() },
"out-log": func() any { return outLogFixture() },
@@ -395,16 +396,20 @@ func inDomainFixture() *InDomain {
return p
}
// outQueueFixture is the queue as Postfix prints it for the mockup's one waiting
// message, greylisted by the receiving server, and the retry policy it shows.
func outQueueFixture() *OutQueue {
listing := "-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------\n" +
"4XcB7k2Jm9z1 3174 Sun Sep 21 13:58:07 alerts@example.org\n" +
"(host mx1.example.org[192.0.2.10] said: 451 4.7.1 Greylisted, try again in 5 minutes (in reply to RCPT TO command))\n" +
" noc@example.org\n" +
"\n" +
"-- 3 Kbytes in 1 Request.\n"
return NewOutQueue(admin(), listing, "").WithRetryPolicy("5 minutes", "about 1 hour 7 minutes", "5 days", false)
// outQueueFixture is the mockup's Outbound queue: one message waiting, its one
// recipient greylisted by the receiving server, and the retry policy it shows.
func outQueueFixture() *Queue {
entries := []QueueEntry{{
ID: "4XcB7k2Jm9z1", Queue: "deferred", Arrival: time.Date(2026, 9, 21, 13, 58, 7, 0, time.Local), Size: 3174,
Sender: "alerts@example.org", Recipient: "noc@example.org",
Reason: "451 4.7.1 Greylisted, try again in 5 minutes", Href: "/outbound/log/41",
}}
return NewOutQueue(admin(), entries, "").WithRetryPolicy("5 minutes", "about 1 hour 7 minutes", "5 days", false)
}
// inQueueFixture is the mockup's Inbound queue: nothing waiting.
func inQueueFixture() *Queue {
return NewInQueue(admin(), nil, "").WithRetryPolicy("5 minutes", "about 1 hour 7 minutes", "5 days", false)
}
// systemLogFixture is the mockup's System log: nine lines of mail.log, as the