-- Trusted reverse-proxy depth for client-IP extraction (#2453).
--
-- X-Forwarded-For grows left-to-right: each proxy APPENDS the peer it
-- received the request from. For client -> CDN -> own-proxy -> Minstrel the
-- app sees XFF = [client, CDN] with RemoteAddr = own-proxy. So the real
-- client sits at XFF[len - hops], where hops counts the proxies you trust:
--
--   0  no proxy in front — use the socket peer, ignore XFF entirely
--   1  one reverse proxy (nginx / Caddy / Traefik terminating TLS)
--   2  a CDN in front of your own proxy (Cloudflare -> nginx -> Minstrel)
--
-- Default 1: a publicly reachable Minstrel needs a TLS terminator in front of
-- it, and recording that terminator's own address for every session makes the
-- active-sessions surface (#370) useless — created_ip and last_ip would both
-- be the proxy, so the "address changed" signal could never fire.
--
-- The cost, stated on the admin card rather than buried: hops >= 1 DECLARES
-- that a proxy exists. If one doesn't, a client can forge X-Forwarded-For and
-- choose what its own session row shows, which defeats exactly the compromise
-- detection #370 exists for. That is inherent to the trusted-hop model, which
-- is why 0 is a first-class setting and not a hidden escape hatch.
--
-- Upper bound 10 guards a typo turning into "trust the whole header"; no real
-- deployment chains ten proxies.
CREATE TABLE network_settings (
    id                 boolean PRIMARY KEY DEFAULT true,
    trusted_proxy_hops int NOT NULL DEFAULT 1,
    CONSTRAINT network_settings_singleton CHECK (id = true),
    CONSTRAINT network_settings_hops_range
        CHECK (trusted_proxy_hops >= 0 AND trusted_proxy_hops <= 10)
);

INSERT INTO network_settings (id) VALUES (true) ON CONFLICT (id) DO NOTHING;
