Skip to content

External dashboards API: deferred follow-ups from #2200 + #2201 deep-reviews #2236

@alex-fedotyev

Description

@alex-fedotyev

Tracking the deferred follow-ups from the deep-review on #2201 (containers + tabs) and #2200 (heatmap external API).

From plan-06b9fd33 (containers + tabs, post-#2201 merge)

These were intentionally deferred during #2201 because they reshape behavior in ways that need a separate decision.

  • LIST projection includes containers, P1 payload risk at scale. Origin: deep-review on feat(external-api): round-trip dashboard containers, tabs, and tile container/tab refs #2201, 2026-05-06 (cite packages/api/src/routers/external-api/v2/dashboards.ts:1398): "LIST endpoint now selects containers for every dashboard. Worst case ≈310KB × 200 dashboards = ~62MB JSON per LIST → drop containers from EXTERNAL_DASHBOARD_PROJECTION and require GET-by-id to read it (or paginate LIST)." The merged code on main still has containers: 1 in EXTERNAL_DASHBOARD_PROJECTION (used by both Dashboard.find and Dashboard.findOne); live verification on 2026-05-12 confirms LIST returns containers on a small dataset, but small-data behavior doesn't resolve a payload-size P1. Decide: (a) drop containers from the projection and require GET-by-id; (b) keep on LIST, add pagination and a documented per-dashboard cap; (c) conditional projection at a response-size threshold. Earlier wording on this bullet said "LIST currently strips it"; that was my own error and contradicts merged code.
  • containers: [] round-trip. Today an empty containers array on PUT is preserved as-is on read; should an explicit empty array be rejected at validation, or treated equivalent to absent? Either is defensible; pick one and pin it with a regression test.
  • Optimistic concurrency on PUT. The dashboard PUT endpoint accepts last-writer-wins. If two clients edit the same dashboard the second write silently overwrites the first. Bigger than feat(external-api): round-trip dashboard containers, tabs, and tile container/tab refs #2201's scope but worth tracking.

From #2200 deep-review (heatmap external API)

Two P2 findings deferred from the in-flight #2200 + #2199 work.

  • Heatmap GET on a malformed Mongo doc silently rewrites to line. convertTileToExternalChart's heatmap arm returns undefined for malformed/legacy stored docs and the caller falls through to defaultTileConfig, which is hardcoded displayType: 'line'. A GET → mutate → PUT round-trip on a corrupt heatmap silently persists the loss of displayType: 'heatmap'. Sibling Number/Pie/Table arms preserve displayType under the same kind of corruption. Either substitute a heatmap-shaped default or drop the tile entirely rather than morphing it.
  • Source-kind change wedge. A source whose kind is later changed from Trace to another kind (the v1 source-update endpoint allows this with no dashboard-tile check) wedges every subsequent dashboard PUT, even when editing an unrelated tile, because getHeatmapTilesWithIncompatibleSources re-runs over the round-tripped tiles on every write. Either block source-kind changes when a heatmap tile references the source, or scope the PUT-time check to tiles that actually changed in this request.

Out of scope here (already tracked)

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions