Skip to content

feat: Serenity Data Insights topics + prompts endpoints | LLMO-6418#2885

Merged
calvarezg merged 4 commits into
mainfrom
feat/brand-presence-promtps
Jul 22, 2026
Merged

feat: Serenity Data Insights topics + prompts endpoints | LLMO-6418#2885
calvarezg merged 4 commits into
mainfrom
feat/brand-presence-promtps

Conversation

@calvarezg

Copy link
Copy Markdown
Contributor

Summary

Adds two Serenity (Semrush-backed) brand-presence endpoints for the Data Insights table: a per-topic table and a per-prompt drill-down. Backend only — the SR UI wiring (project-elmo-ui) follows in a separate PR.

Both endpoints are built from the single PROMPTS_BY_TOPIC element (78864493) rather than the wiki's 3-element per-topic fan-out: 141adc88 (citations) currently returns 500, 0564b061 lacks a position field, and the live Brand Presence MFE also builds its view from 78864493 alone (verified via live probe + network capture, 2026-07-21).

Endpoints

  • GET /v2/orgs/:spaceCatId/brands/:brandId/serenity/brand-presence/topics — per-topic aggregates (promptCount, brand mentions/citations, avg visibility/position/sentiment) with each topic's prompts embedded, for the eager Data Insights table. Brand sub-workspace scoped; optional region/date; returns the full topic list.
  • GET /v2/orgs/:spaceCatId/brands/:brandId/serenity/brand-presence/topics/:topicId/prompts — per-prompt drill-down, scoped via CBF_topic (the topic NAME — Semrush topics have no UUID), with server-side pagination.

Notes / gaps (flagged, not silently guessed)

  • sourceCount / share-of-voice aren't available from 78864493 (dedicated elements unusable) — left unset (optional in the UI contract).
  • Averages exclude the element's sentinels: position: -1 (unranked) and sentiment: null are not averaged; a topic with no ranked/sentiment-bearing prompt yields null.
  • New POC endpoint code is fenced with c8 ignore per the sibling convention; unit tests are still included.

Test plan

  • topic-prompts + topics-insights definition unit tests (28 cases): payload shape, CBF_topic scoping, sentinel handling, aggregation, volume-sorted embedding.
  • OpenAPI contract test extended (serenity-api.test.js): both new operations validate against their response schemas (24 passing).
  • npm run docs:lint + docs:build clean; route/capability suites pass (3189).
  • Transform + aggregation verified against a real 633-prompt element response (196 topics; drill-down counts match the live probe).
  • End-to-end verification against a properly-provisioned Semrush brand — dev's only wired brand has a sub-workspace == org-parent collision, so this will be verified against prod data.

API spec checklist

  • API specification updated (api.yaml, serenity-api.yaml, schemas.yaml); representative request/response shapes are exercised by the contract-test fixtures.
  • Endpoints are implemented (no "Not implemented yet" / 501 stubs).

Related Issues

https://jira.corp.adobe.com/browse/LLMO-6418

…points (LLMO-6418)

Add two Serenity/Semrush brand-presence endpoints backing the Data Insights table:
- GET .../serenity/brand-presence/topics — per-topic aggregates + each topic's embedded prompts
- GET .../serenity/brand-presence/topics/:topicId/prompts — per-prompt drill-down (paged)

Both are built from the single PROMPTS_BY_TOPIC element (78864493) — grouped by topic
(server-side aggregation) / scoped via CBF_topic — rather than the wiki's 3-element
fan-out (141adc88 currently 500s, 0564b061 lacks position; the live MFE also uses only
78864493). Adds unit tests for both definitions plus OpenAPI + contract-test coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@calvarezg calvarezg self-assigned this Jul 22, 2026
…eHandlers expectation

The route-segregation test asserts the exact dynamic-route set; register the two
new brand-presence routes so it matches getRouteHandlers output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

This PR will trigger a minor release when merged.

…points (LLMO-6418)

- Sort the topic drill-down (getTopicPrompts) by volume desc so it matches the
  order of the same topic's prompts embedded in getTopics (was raw element order).
- Drop the c8-ignore on topic-prompts.js and topics-insights.js — both are fully
  unit-tested (100% stmts/branches/funcs/lines); remove a dead promptCount ternary
  and add a non-string/whitespace topic test to keep branch coverage at 100%.
- Skip blank/whitespace-only topics in aggregation (consistent with the drill-down
  controller rejecting an empty topicId).
- Fix stale "topics.js" doc references (the code lives in topics-insights.js).
- Document that per-topic promptCount reflects the returned population and can only
  lag the drill-down's totalCount if the workspace exceeds the element's row cap.

Waived (consistent with sibling serenity element endpoints, noted in PR): controller
methods remain c8-ignored (POC glue); /topics intentionally embeds prompts for the
eager table; visibility 0 is a real value included in the mean while position/sentiment
sentinels are excluded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @calvarezg,

Verdict: Approve - clean, well-structured addition of two new read endpoints that follow all established patterns.
Complexity: HIGH - large diff (1300+ lines across 16 files); API surface + FACS classification touched.
Changes: Adds two Serenity brand-presence Data Insights endpoints (per-topic table and per-prompt drill-down) backed by the PROMPTS_BY_TOPIC element, with full OpenAPI specs, FACS/capability wiring, and definition-layer unit tests (16 files).

Note: CI integration test (it-postgres) is still pending - verify it passes before merge.

Non-blocking (4): minor issues and suggestions
  • nit: The region-resolution block in listTopics and listTopicPrompts is identical (lines 646-661 and 729-744 of the controller diff) - consider extracting into a shared helper to reduce duplication as more brand-presence endpoints land. - src/controllers/elements.js
  • suggestion: decodeURIComponent in listTopicPrompts (line 705) is defensive against double-encoding but enrichPathInfo already decodes. If it ever encounters a topic name containing a literal %2F (URL-encoded slash), the extra decode will corrupt it. Consider removing and trusting the middleware. - src/controllers/elements.js
  • nit: The prompts array is embedded in every topic row in the listTopics response, which means the full per-prompt dataset is returned twice when a client fetches topics then drills down. For large workspaces this could be substantial payload. The OpenAPI spec already marks it optional in spirit (not in required), so a future ?embed=prompts query param could let the UI opt in. - docs/openapi/schemas.yaml
  • nit: Number(row?.volume) || 0 in transformTopicPromptsResponse (line 967) coerces volume: 0 correctly (to 0), but would also coerce volume: NaN to 0 silently. The upstream element contract makes this unlikely but the sibling toNumberOrNull function handles the NaN case explicitly - consider consistency. - src/support/elements/definitions/topic-prompts.js

Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 8m 42s | Cost: $2.67 | Commit: 4b00d8ca5675d425b927bc4389b0f34f69a75794
If this code review was useful, please react with 👍. Otherwise, react with 👎.

@MysticatBot MysticatBot added ai-reviewed Reviewed by AI complexity:high AI-assessed PR complexity: HIGH labels Jul 22, 2026
@calvarezg
calvarezg merged commit 720e9f0 into main Jul 22, 2026
19 checks passed
@calvarezg
calvarezg deleted the feat/brand-presence-promtps branch July 22, 2026 14:11
solaris007 pushed a commit that referenced this pull request Jul 22, 2026
# [1.680.0](v1.679.1...v1.680.0) (2026-07-22)

### Bug Fixes

* **llmo:** 404 brand-claims when the S3 object is missing ([#2887](#2887)) ([9004c4b](9004c4b))

### Features

* bind Semrush markets to SpaceCat Site entities (LLMO-6405) ([#2888](#2888)) ([f4f891d](f4f891d))
* Serenity Data Insights topics + prompts endpoints | LLMO-6418 ([#2885](#2885)) ([720e9f0](720e9f0))
@solaris007

Copy link
Copy Markdown
Member

🎉 This PR is included in version 1.680.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed Reviewed by AI complexity:high AI-assessed PR complexity: HIGH released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants