Skip to content

feat(portal): Unique Verifications analytics UI (3/3) - #2193

Open
soamdesai-tfh wants to merge 19 commits into
feat/world-id-analytics-readfrom
feat/world-id-analytics-ui
Open

feat(portal): Unique Verifications analytics UI (3/3)#2193
soamdesai-tfh wants to merge 19 commits into
feat/world-id-analytics-readfrom
feat/world-id-analytics-ui

Conversation

@soamdesai-tfh

@soamdesai-tfh soamdesai-tfh commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Third of three stacked PRs (on #2192, which is on #2191). The product surfaces.

Scope

  • Shared WorldIdAnalyticsGraph under WorldId/common/: Last 7 Days default, lazy + mounted-page-cached All Time, at-most-seven near-equal buckets (sum-preserving, never cumulative), UTC labels/tooltips, five-minute visible refresh + focus refresh, prior data kept through pending/failed refreshes, flat-zero rendering
  • web/lib/world-id-analytics: BigInt-safe series sums, bucket math, UTC-immune date formatting
  • App hero (combined v3+v4, "Includes legacy World ID actions"), batched ≤12-id per-page action-card previews, v4 detail graph replacing the live nullifiers_aggregate count
  • ActionStatsGraph unmounted from both active legacy v3 detail scenes (files kept per owner ruling; its action_stats() query no longer runs); "Verified humans"/"Human" copy → "Recent verifications"/"Nullifier"; latest-100 feed preserved
  • Card links carry aria-label so preview stats don't change accessible names; ruled fetch/isolation amendments to the two pre-existing pv3 suites (no assertion changes)

Verification

This branch's tree is byte-identical to the fully verified feature branch: UI unit tests 51/51 (graph, surfaces, bucketing, amended pv3), full unit sweep green except the pre-existing base portal-v3-shell-dropdown-focus failure already fixed on main by 333cfd0 (resolves on rebase), tsc --noEmit, pnpm format:check.

@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-read branch from 7b12100 to 705315e Compare July 31, 2026 07:41
@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-ui branch from 7e6bd8d to ce94b9e Compare July 31, 2026 07:41
@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-read branch from 705315e to 268ecfc Compare July 31, 2026 14:31
@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-ui branch from bd8bfa1 to 263b00c Compare July 31, 2026 14:31
@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-read branch from 268ecfc to 3abc011 Compare July 31, 2026 16:46
@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-ui branch from adfe310 to 138fe18 Compare July 31, 2026 20:54
soamdesai-tfh and others added 2 commits July 31, 2026 14:28
GET /api/portal/apps/{app_id}/world-id-analytics: database-backed app
authorization with soft-delete 404s, id resolution against both action
tables with ambiguity/cross-app/cross-environment/wrong-source rejection,
PostgreSQL-side combined app aggregation, UTC zero-filling with the
three All Time start branches, bigint-safe integer-string counts, and
source-specific legacy_actions/actions blocks. Lands the fresh-stack
integration suite and the opt-in million-row load gate, which exercise
the data layer and this endpoint together.
The data slice scoped the fresh-stack runner to its own suites; now
that integration.test.ts and million.test.ts exist in this tree,
re-extend the default path and restore the --million entrypoint and
its package script.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shared WorldIdAnalyticsGraph (Last 7 Days default, lazy cached All Time,
seven-bucket grouping, five-minute visible/focus refresh that keeps
prior data), the app hero with the legacy-inclusion disclosure, batched
per-page action-card previews, the v4 detail graph replacing the live
nullifiers_aggregate count, ActionStatsGraph unmounted from both active
legacy detail scenes, Verified humans/Human copy replaced with Recent
verifications/Nullifier, and the ruled fetch/isolation amendments to the
two pre-existing pv3 suites.
Soam's UI ruling: the period switcher is a Select dropdown like the
archived PeriodSelector and the app/team switchers, not aria-pressed
segment buttons. Interaction mechanics only; every behavioral pin
(lazy All Time, mounted cache, URL untouched, refresh semantics,
grouped tooltips) is unchanged.
Rebuild the graph presentation on the archived PR 2100-2103 components:
a shared Sparkline with uniform stroke (non-scaling-stroke over a
stretched viewBox), the dashed hover rule with a count/date popup, and a
Select-dropdown period switcher matching the app/team switchers. Card
previews render their real Last 7 Days series instead of a hardcoded
line. Presentation only; fetch/cache/refresh logic is unchanged.
The dropdown had no whitespace-nowrap and could shrink, so a narrow hero
card wrapped "Last 7 Days" onto three lines and pushed it out of the
card. Pin the button's width and let the header row wrap instead.
Soam's product call: remove the "Includes legacy World ID actions" help
text from the app hero. This is a substantive contract change, not a
mechanics amendment — frozen spec sections 3 and 7 mandate the copy and
section 8 requires the assertion. Recorded as a deviation.
soamdesai-tfh and others added 10 commits July 31, 2026 18:44
Soam's product call. Deviation from frozen spec sections 3 and 7, which
mandate this copy so the hero total's inclusion of v3 actions (absent
from the v4 card grid) is disclosed.
A brand-new app's Last 7 Days series is truncated at its creation date,
so it carries one point — and a one-vertex polyline paints nothing,
leaving an empty card where the spec requires a flat zero graph. Span a
lone (or empty) series across the full width at its own height.
The existing flat-zero test uses a three-point series, so it passed while
a newly created entity (one point, truncated at creation) rendered no
line at all. Pin that a lone point still produces a drawable segment.
portal-border is #f1f1f1, so the dashed hover line was effectively
invisible; use portal-subtle (#9c9c9c) as the archived sparkline did.
The tooltip card keeps its light border.
Match archive/pr-2103's ActionCard: taller frame, title/description at
the top, a full-width sparkline in the middle, and the count inline with
its label in a footer row. Drops the stacked label-over-number block.
The archived footer's "last <relative time>" clause stays out — latest
verification time is an out-of-scope metric.
actionCardFrameClassName is composed by the team app tiles
(Team/page/Apps/App), so the analytics card's taller geometry was
enlarging every app tile and failing main's portal-v3-app-grid-design
test. Restore that constant byte-for-byte and give the analytics card
its own worldIdActionCardFrameClassName.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep the app hero on production with the v4 cards, and map legacy v3 detail graphs from app.is_staging so staging actions no longer 400.

Co-authored-by: Cursor <cursoragent@cursor.com>
@soamdesai-tfh
soamdesai-tfh marked this pull request as ready for review August 3, 2026 00:50

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b35e2a1888

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

setPeriod(next);
if (!cache[next]) void load(next);
};
const response = cache[period] ?? cache.last_7_days;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop labeling failed All Time loads as All Time

When Last 7 Days has loaded and the first All Time request fails, this fallback selects the cached seven-day response while period remains all_time. Because metric is still defined, the error branch is skipped, so the selector says “All Time” and the graph rebuckets and presents the seven-day count as all-time data until a later refresh succeeds. Distinguish a pending request from a failed uncached period, or revert/show an error rather than retaining the fallback after failure.

Useful? React with 👍 / 👎.

)
.catch(() => {});
return () => controller.abort();
}, [props.appId, page, props.search]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refetch previews when the action list changes

After a successful create, handleDialogClose invokes onActionsChanged, which refetches the overview and updates props.actions; however, if the search and page number are unchanged, this effect does not rerun. Since actions are ordered newest-first, the new action can immediately appear on the current page without its ID ever being requested, leaving its preview at the fallback value until the user searches or changes pages. Include the visible action IDs in the effect dependency/key.

Useful? React with 👍 / 👎.

/>
<div className="flex items-baseline gap-1.5">
<span className="font-twk text-20 leading-none font-medium text-portal-heading">
{BigInt(props.previewCount ?? "0").toLocaleString()}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid reporting unavailable previews as zero

On every initial card render—and permanently after a non-2xx or network failure swallowed by ActionsGridpreviewCount is undefined, so this renders 0 and a flat empty sparkline. That makes loading or unavailable analytics indistinguishable from a genuine zero-verification action and presents inaccurate production data; render a loading/unavailable state until a successful response supplies the metric.

Useful? React with 👍 / 👎.

@soamdesai-tfh
soamdesai-tfh force-pushed the feat/world-id-analytics-read branch from fee4fd4 to 6c3f84d Compare August 3, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant