The buffer-backed xdb.Searcher is not safe for concurrent use, so
parallel audit appends could race on Search and corrupt internal state.
Serialize v4 and v6 lookups behind separate mutexes so concurrent
callers fall through one at a time.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add an IPRegionResolver wrapping the ip2region xdb library and attach it
to AuditService so each appended event records both the raw IP and a
resolved region in a new ops.audit_logs.ip_region column. Loopback and
private addresses short-circuit to local labels; missing xdb data or
lookup errors degrade silently so auditing keeps working without it.
The ops console audit view shows the region beneath the IP. Bundle the
v4/v6 xdb data under internal/ops/app/ipregiondata so the resolver works
out of the box, with config paths/env overrides for swapping in updated
data sets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>