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>