Multi-user web surface. Two layered middlewares: Auth.Middleware (Dex
session required) wraps registrationGate, which resolves the authenticated
subject -> tapir user_id once per request via the new web.Identity port and
stashes it. A subject with no tapir user is redirected to GET /register
(display name + accept-terms); POST /register calls RegisterUser then
redirects to /. /register is inside the auth guard but exempt from the gate
(/auth/* and /healthz too).
Current-user seam: CurrentUserID(r) (string, bool) returns the resolved id
from the request context. The list/detail/action handlers now scope by it,
replacing the single configured App.UserID (removed). App gains an Identity
field; *store.Store satisfies both Store and Identity. cmd/tapir wires
Identity: st and drops UserID.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>