diff --git a/internal/web/view/fixtures_test.go b/internal/web/view/fixtures_test.go new file mode 100644 index 0000000..f9bbcd9 --- /dev/null +++ b/internal/web/view/fixtures_test.go @@ -0,0 +1,17 @@ +package view + +// pageFixtures is the data each redesigned page is rendered with by the guard +// tests (guard_panel_test.go): one entry per page that has left +// legacy_pages.txt, keyed by the page's engine name. The guards render the page +// through Engine.Render with this value and hold the result to the design +// contract — its class vocabulary, its page structure and the component +// skeleton recorded for the mockup of the same name in +// docs/assets/panel-redesign/panel/outlines.json. +// +// A fixture therefore has to fill the page the way its mockup is filled: the +// same boxes, the same number of records. It is also what the evidence +// screenshots are compared against, so use plausible values, not "foo". +// +// This file belongs to the implementation, not to the guards: the step that +// restyles a page adds its fixture here in the same commit. +var pageFixtures = map[string]func() any{} diff --git a/internal/web/view/legacy_pages.txt b/internal/web/view/legacy_pages.txt new file mode 100644 index 0000000..7abcad0 --- /dev/null +++ b/internal/web/view/legacy_pages.txt @@ -0,0 +1,36 @@ +# The redesign ratchet (docs/plans/panel-redesign.md § Against resurrected pages). +# +# One entry per line: what is still pre-2.0 and therefore not yet held to the +# design contract by the guard tests. This list ONLY SHRINKS — CI fails a +# commit whose list is not a subset of its parent's (.github/scripts/design-first.sh). +# Finishing a piece of work means deleting its line in the same commit; from +# then on the guards hold that piece for good. +# +# @kit the component kit is not complete (stage 0): panel.css, +# components.html, components.go, layout.html, GET /server/components +# @routes the pre-2.0 route table is still in place (stage 1) +# a page of the view engine that is still the old template +@kit +@routes +backup +dashboard +deliveries +delivery +dmarc +dmarc_domain +dmarc_report +domain_delete +domain_detail +help +inbound +inbound_delete +inbound_domain +login +mail_queue +settings +setup +status +system_log +user_delete +user_form +users diff --git a/internal/web/web.go b/internal/web/web.go index 9972a6f..951bd75 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -147,6 +147,17 @@ func (s *Server) Start() error { // Handler returns the panel's HTTP handler (router). func (s *Server) Handler() http.Handler { + mux, authed := s.muxes() + mux.Handle("/", s.auth.RequireAuth(authed)) + return s.secure(mux) +} + +// muxes registers every route: the public ones, and the ones behind a session. +// Both muxes are flat — one pattern per route, nothing mounted as a sub-router — +// and building them only takes method values, it never calls into s.auth or +// s.handlers: the route guard test (guard_routes_test.go) runs this on a bare +// Server and asks each mux which pattern answers a path. +func (s *Server) muxes() (public, authed *http.ServeMux) { mux := http.NewServeMux() h := s.handlers @@ -157,7 +168,7 @@ func (s *Server) Handler() http.Handler { mux.HandleFunc("/login", s.auth.HandleLogin) mux.HandleFunc("/logout", s.auth.HandleLogout) - authed := http.NewServeMux() + authed = http.NewServeMux() authed.HandleFunc("GET /{$}", redirectHome) authed.HandleFunc("GET /help", h.HandleHelp) @@ -224,8 +235,7 @@ func (s *Server) Handler() http.Handler { authed.HandleFunc("GET /system-log", h.HandleSystemLog) authed.HandleFunc("GET /system-log/body", h.HandleSystemLogBody) - mux.Handle("/", s.auth.RequireAuth(authed)) - return s.secure(mux) + return mux, authed } // redirectSettings sends legacy /account bookmarks to /settings (308 preserves POST).