dotCMS / dotCMS/core

Analytics: Environment Filtering — dotCMS core: environment identity, collector plumbing, and config endpoint

Open
#37,408 0 comments 0 reactions 1 assignee View on GitHub

@jcastro-dotcms is already working on this.

Since Sep 8, 2026.

dotCMS : Analytics Team : Falcon Type : New Functionality
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Summary

dotCMS core learns its own environment identity and the set of sibling environments from infra-provided configuration, forwards environment on every ingest call the auto-injected collector makes, and exposes a small config endpoint that the Angular dashboard uses to populate its environment selector — entirely config-driven, with no environment name ever hardcoded.

Parent epic: #37349
Spike: #37107
Depends on: the infra sub-task's env var contract (can be developed against local/stubbed env vars without waiting for the full customer rollout); the CAEM ingest sub-task's environment param (for the collector's forwarded value to actually land somewhere).

Background

Self-identity: DOT_ANALYTICS_ENVIRONMENT — a new env var sourced via the Kubernetes downward API from the dotcms.cloud/environment label, same fieldRef pattern already used for DOT_ANALYTICS_TENANT/PROJECT. Auto-derived, no manual per-customer entry. This is the value sent to CAEM at ingest time.

Sibling discovery: no existing mechanism resolves this (k8s labels only describe themselves; no infra registry exists). Decision: a second, Platform-curated env var:

DOT_ANALYTICS_AVAILABLE_ENVIRONMENTS=prod::Production Site,prod-2::APAC Site,qa

key::Label per entry, label optional (falls back to the bare key). Two vars, not merged into one — DOT_ANALYTICS_ENVIRONMENT is mechanically guaranteed correct (Kubernetes populates it from the pod's own manifest); folding it into the hand-curated list would reintroduce copy-paste drift. Parsing is forgiving, never fatal: a malformed entry falls back to using the raw text as both key and label, logged at WARN, never a startup failure or a 500.

New lightweight config endpoint (under the existing EventAnalyticsProxyResource/analytics resource area), returning a ready-to-render contract — the frontend does zero string-matching or environment-naming logic:

{
  "current": "prod-2",
  "available": [
    { "key": "prod",   "label": "Production Site" },
    { "key": "prod-2", "label": "APAC Site" },
    { "key": "qa",     "label": "qa" }
  ]
}

No currentLabel field — the label shown for the current entry is a fixed, locally-defined UI string ("Current env") that Angular substitutes in wherever item.key === current; Angular never computes which key is current or invents a display name for it.

Backed by a small composer that:

  • Parses both env vars per the rules above.
  • Guarantees current is always a member of available — if Platform's curated list and the pod's own derived value ever disagree (e.g. a freshly-provisioned environment whose siblings' lists haven't been updated yet), the response still includes current in available (falling back to the bare key) rather than omitting an instance from its own dropdown, and logs a WARN so the drift gets fixed.
  • Uses the same current value as the one sent as the environment ingest param — one single place in dotCMS-core computes "what environment am I," never two that could disagree.

Collector plumbing: the auto-injected collector script (gated by the existing DOT_FEATURE_FLAG_CONTENT_ANALYTICS_AUTO_INJECT feature flag) needs to bake in DOT_ANALYTICS_ENVIRONMENT the same way it already bakes in tenant/project context, so every browser-fired ingest call carries &environment=<self>. Open item, flagged in the spike, not yet resolved: the exact injection code path wasn't traced to a specific file/line — confirmed the mechanism exists, needs a short investigation at the start of implementation, not a blocker to starting this ticket.

Ordering note — two pairs that look like they need careful sequencing but don't, both built to degrade gracefully:

  • Infra env vars vs. this ticket's collector code: if the env var exists before the code reads it, it's unused; if the code deploys before the env var exists, it should just skip sending &environment= — identical to today's behavior.
  • This ticket's &environment= vs. CAEM's ingest API: an unrecognized param is silently ignored by Spring MVC either direction.

Minor, non-blocking follow-up: CAEM's existing internal-only GET /v1/report/environments (EnvironmentsRepository) lists distinct (tenant, project) pairs and could later add environment to its SELECT DISTINCT — not required for this epic, noted for whoever picks it up.

Scope

  • Read DOT_ANALYTICS_ENVIRONMENT and DOT_ANALYTICS_AVAILABLE_ENVIRONMENTS in dotCMS core.
  • Build the composer: parsing (forgiving-never-fatal), the current-in-available guarantee + WARN on drift, single source of truth for "current."
  • New config endpoint returning {current, available:[{key,label}]}.
  • Wire the auto-injected collector to send &environment=<self> on every ingest call, once the injection point is located.

Out of scope

  • Provisioning the env vars themselves on customer infrastructure (Servers/infrastructure sub-task).
  • The Angular selector UI (Dashboard sub-task) — this ticket only ships the endpoint it will call.
  • EventAnalyticsProxyHelper changes for the query side — confirmed unnecessary in the spike (it forwards params transparently already).

Dependencies

Can be developed and unit-tested against local/stubbed env var values without waiting for the infra rollout. Needs the CAEM ingest sub-task's environment param to exist for the collector's forwarded value to have any effect end-to-end. The Dashboard sub-task depends on this ticket's config endpoint contract being stable before it can wire up the selector.

Acceptance Criteria

  • Config endpoint returns current + available, with current always present in available even under curated-list drift, and a WARN logged when that drift happens
  • No environment name is ever hardcoded anywhere in this code path
  • Auto-injected collector sends &environment=<self> on every ingest call once the feature flag is on
  • Malformed DOT_ANALYTICS_AVAILABLE_ENVIRONMENTS entries degrade gracefully (WARN, fallback to raw text), never a startup failure
  • Omitting either env var reproduces today's behavior (no environment sent, endpoint still returns a sane single-entry response for the current instance)

Next step

Run /speckit-specify against this issue to produce the formal spec (exact endpoint path, composer logic, collector injection point) before implementation.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.