Non-default campaigns gain an optional colour override (background / text /
link) in two sets — one for every theme, one for the dark theme only — and an
"urgent" flag.
- Colours ride profile.get as six trailing FlatBuffers strings on
BannerCampaign (backward-compatible). The client resolves the cascade
(dark <- dark ?? all, light <- all) per rendered theme and derives the strip
border from the background in JS (no CSS color-mix, for the old Android
WebView floor); AdBanner applies them as inline vars scoped to the strip.
- Urgent is resolved entirely server-side: while any enabled, in-window urgent
campaign exists, computeActiveSet returns only the urgent campaigns and
bannerFor skips the eligibility gate — so a system notice reaches every viewer
(paid / hint-holding / no_banner included) and preempts the ordinary feed. No
wire field; it appears on each viewer's next profile.get.
- Admin console (/_gm/banners): native colour pickers + a live light/dark
preview of the strip, and an urgent toggle. The default campaign stays plain,
enforced by the service and a DB CHECK.
Migration 00009 is additive (nullable colour columns + a bool default +
all-or-nothing / hex / default-plain CHECKs) — expand-contract, rollback-safe.
Docs: ARCHITECTURE §10, UI_DESIGN, FUNCTIONAL (+ru). Tests: ads unit (urgent
preempt + colour validation), codec + resolver unit, gateway transcode, and
integration (colour round-trip + urgent bypass against real Postgres).