Serve the tracking-codes tab and ingest the visitor beacon

FeatureMediaService
Ya
20 Agosti 2026, 01:24 UTC
Mwandishi
Kamo
Ahadi ya
d9a664b

MediaService already backs the other marketing tabs, so it takes both halves of tracking codes: the authenticated CRUD and stats surface at /api/media/marketing/tracking, and the public ingest worker behind APIService's edge. The ingest handler does nothing but validate and enqueue. Everything real — the code lookup, the geo lookup, the user-agent parse, the four writes — happens on a bounded executor off the request thread, and the response is a 202 with an empty body regardless of outcome, because a marketing page must never wait on analytics and a public caller must never learn what went wrong. The rejection policy is AbortPolicy, not CallerRunsPolicy: caller-runs would push the database work back onto the HTTP thread, which is the exact thing this shape exists to prevent. A full queue drops the hit and counts it. Every client-supplied string is clipped to its column width before it is persisted. Hibernate does not enforce @Column(length) at runtime, so on a public endpoint an over-length Referer or Accept-Language is SQLSTATE 22001 and takes the whole beacon down with it — trivially triggerable by anyone. A visit is new when the link row was last seen more than 30 minutes ago, matching the analytics install's own window so the two never disagree about "visits". Bots are parsed, dropped, and counted against nothing. Scope is resolved server-side and re-validated: "managed" needs either cross-member right and always includes the caller, "all" needs VIEW_ALL_MEMBER_TRACKING and reads by organization so no IN clause can ever be handed an empty collection. An unauthorized scope downgrades to "own" rather than erroring, and the response echoes the scope actually applied so the client can move its selector instead of lying about what the member is looking at. Responses are records with String ids and numeric counters. MediaService has no wire-level Long->String rule, so a raw Long in a Map would ship a JS-lossy number with nothing to catch it; TrackingCodeDtoWireTest pins both halves of that. The conversion consumer's durable filter is marketing.visitor.* and is fixed forever — a durable keeps the filter it was created with, and widening it later yields a permanent SUB-90011 on a consumer that still looks healthy. It bumps a counter only when the conditional stamp actually affected a row. A nightly reconcile recomputes all six counters from rows this service owns, so a dropped increment heals itself.

Mabadiliko yote

Je, unaona nini kuhusu usafiri?

Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.

Kuwa Huru MileleMtazamo wa bei