Skip to content

Verify experiment context survives the dotCMS analytics event proxy #37018

Description

@erickgonzalez

Description

Part 1 of #36763 — prove that an experiment block set by a browser survives dotCMS's analytics proxy and lands in ClickHouse.

This is the day-one unblocker for the whole sprint. Everything else in Part 1's first sprint (schema, ingest) can only be verified with hand-seeded data unless this path is confirmed, because nothing sets context.experiment until the SDK work in Part 3 and that developer is unavailable.

The gap

Experiment events reach the analytics pipeline through core, not directly:

browser SDK  →  dotCMS core  →  CAEM  →  ClickHouse
                     ↑
            POST /api/v1/analytics/content/event
            EventAnalyticsProxyResource

The implementation plan covers the CAEM end (UserEventPayload, SaveEventRepository) and the ClickHouse end (schema), but silently assumes the middle hop passes context.experiment through untouched. That assumption is never stated, and it gates every end-to-end assertion in the sprint.

Why it should pass — and why it still needs a test

Reading EventAnalyticsProxyResource.proxyEventRequest, the handler parses the body, validates context.site_auth via SiteAuthValidator, injects site_id from the resolved site, re-serializes, and forwards to {DOT_ANALYTICS_BASE_URL}/v1/event/ingest. It does not run AnalyticsValidatorUtil. So an unrecognised experiment key in context should survive.

"Should" is doing real work in that sentence. A round-trip test converts it into a fact, and leaves behind the fixture the sprint needs as its only real producer.

⚠ The trap this test also documents

The legacy ingest path behaves differently. /api/v1/eventEventLogWebInterceptor validates against dotCMS/src/main/resources/analytics/validators/all.json, which is an allowlist on contextsite_auth, session_id, user_id, device and nothing else. An unknown key produces ValidationErrorCode.UNKNOWN_FIELD and a 400.

So any interim producer routed through /api/v1/event needs all.json updated first. The implementation plan's note that "JSON schema validators require no changes" is true for CAEM's validators and not true for core's legacy path. Recording this here so the next person does not lose a day to it.

Acceptance Criteria

Round-trip

  • A Postman case in dotcms-postman POSTs a payload containing context.experiment (id, running_id, variant) to POST /api/v1/analytics/content/event and asserts a success response
  • The experiment block is confirmed to arrive at CAEM unmodified — keys and values intact, nothing dropped or renamed
  • The three values are confirmed present in analytics.events for the ingested event
  • site_id injection still works with the experiment block present — the block does not interfere with the existing proxy behaviour

Negative and edge

  • A payload with no experiment block still succeeds and is unchanged from today's behaviour — no regression to non-experiment analytics
  • A partial experiment block is rejected with 400 by CAEM's Bean Validation, and the error surfaces through the proxy in a usable form rather than as an opaque 500

Documentation

  • The confirmed behaviour of both paths is written into the issue or the migration notes: the proxy path passes context through; the legacy /api/v1/event path allowlists it via all.json
  • The fixture is reusable as the sprint's manual producer — a documented way to generate experiment-carrying events without the SDK

Priority

High

Additional Context

Do this on day one, before the schema work is finished. If the assumption turns out to be wrong, the fix is small but it changes what the schema and ingest issues can claim as "verified", and it is much cheaper to discover in week one than at sprint review.

Open question this test informs. If a synthetic fixture is not enough, the alternative interim producer is having dotCMS inject context.experiment server-side at the proxy — it already resolves the assigned variant via isUserIncluded and the variantName parameter. That would give real end-to-end experiment data with no SDK developer, but it adds core work to this sprint and changes what Part 3 has to build. Flagging as a scoping decision, not proposing it here.

Related: the schema and ingest issues in this sprint depend on this for anything beyond hand-seeded verification.

Parent epic: #36763

Metadata

Metadata

Assignees

Type

Projects

Status
Current Sprint Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions