V1 Web PWA · Surface walkthrough

Topic Hub Workspace · Veritas (default topic)

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
8sections5 minread

On this page

Context. surface customer · domain veritas · route /domains/veritas/topics · auth signed-in · source apps/oshun/web/src/app/domains/veritas/topics/page.tsx

Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content re-verified 2026-06-03 against current source

Purpose#

The Veritas Topic Hub workspace mounted with the default topic (renewable energy, since topicId is unset). Functionally identical to the dynamic /domains/veritas/topics/[topicId] route — same VeritasTopicHubWorkspace, same rendering — but the default topic surface serves as the topics index / showcase entry. The workspace tracks topic follow-state via the Veritas store and supports follow alert-frequency changes.

Entry points#

  • /domains/veritas index — verify the internal-namespace tool grid
  • Linked from /explore — topic cards in discovery (verify)
  • Linked from /domains/veritas/story/[id] — story workspace topic-hub href targets the topic by slug
  • Direct URL / bookmark — yes (auth required)

Layout regions#

page.tsx is a 'use client' component:

tsx
<VeritasTopicHubWorkspace onClose={() => router.back()} origin="explore" />

(no topicId is passed, so the workspace selects the default topic via getTopicKey(undefined)'renewable-energy'.)

VeritasTopicHubWorkspace renders inline (not an overlay). Layout (anchored to data-veritas-topic-* attributes):

  • Top toolbar (line 541): back button (onClose), trend label and metric pills ({trendLabel}, {tracked claims}, {source institutions}), and a follow toggle (data-veritas-topic-follow-toggle, data-veritas-topic-follow-state="following|unfollowed")
  • Hero (line 596, data-veritas-topic-hub-title): topic.eyebrow, topic.title (clamp), topic.headline lede, topic.overviewSignals pills
  • Two-column grid (minmax(0, 1.8fr) minmax(300px, 0.95fr)):
    • Main column (left):
      • "Current read" — metrics grid (topic.metrics[]: value + label)
      • "Timeline" (data-veritas-topic-hub-timeline): per topic.timeline[], an article (data-veritas-topic-timeline-entry) colour-coded by tone (anchor / watch / other)
      • "Story clusters" — per topic.clusters[], an action card (data-veritas-topic-cluster-action)
      • "Claim posture" — per topic.claims[], a card with Inspect claim button (data-veritas-topic-inspect-claim) and a "Open claim detail" link (data-veritas-topic-claim-action → builds an href to the claim route)
      • "Sources" — per topic.sources[], a card with Inspect source button (data-veritas-topic-inspect-source) and an "Open source lane" link (data-veritas-topic-source-action)
    • Aside column (right):
      • "Alert controls" (data-veritas-topic-alert-controls): per frequency (realtime | daily | weekly), buttons (data-veritas-topic-alert-frequency); only enabled when followed
      • "Topic follow-up" Links to related views (data-veritas-topic-followup-action="topics|clusters|research")
  • VeritasInspectionOverlay — opened by inspect buttons

States#

  • Loading — synchronous from imported TOPIC_HUBS; no fetch
  • Populated — default topic always renders fully
  • FollowedtopicFollowed = true; toggle button reads "Following topic" (accent border + accent text); alert controls become active
  • UnfollowedtopicFollowed = false; toggle button reads "Follow topic" (muted); alert controls render but handleTopicAlertFrequencyChange no-ops when not followed
  • Alert frequency: realtime / daily / weekly — driven by followedTopic?.alertFrequency from the Veritas store (default 'daily')
  • Inspection openactiveInspection !== null shows the overlay (handleTopicClaimInspection, handleTopicSourceInspection, handleTopicSophiaBundleInspection)
  • No timeline entries / clusters / claims / sources — verify graceful empty branches (the workspace currently maps unconditionally)
  • Offline — uses imported data + local Veritas store; the follow toggle is local-only (verify whether it should sync to a BFF)
  • Standalone PWA — verify the 1.8fr/0.95fr grid collapses cleanly
  • Reduced motion — verify (no explicit animations in observed code)

Interactions#

Top toolbar#

  • Back (button with ChevronLeft icon) — onClose()router.back()
  • Follow toggle (button, data-veritas-topic-follow-toggle, data-veritas-topic-follow-state)
    • Function: handleTopicFollowToggle calls followTopic or unfollowTopic on the Veritas store and fires trackVeritasTopicFollowed / trackVeritasTopicUnfollowed with { topicId, topicTitle, source: origin }

Claim cards#

  • Inspect claim (button, data-veritas-topic-inspect-claim={claimId})
    • Function: handleTopicClaimInspection(claimId) opens overlay with the claim model and fires trackVeritasInspectionOpened({ workspace: 'topic-hub', kind: 'evidence', itemId, source: origin })
  • Open claim dossier (link, data-veritas-topic-claim-action={claimId})
    • Function: navigates to buildDomainShellHref('veritas', claim.href, origin, stack) → resolves to /domains/veritas/claims/<claimId>

Source cards#

  • Inspect source (button, data-veritas-topic-inspect-source={sourceId})
    • Function: handleTopicSourceInspection(sourceId) opens overlay with source model and fires trackVeritasInspectionOpened({ workspace: 'topic-hub', kind: 'source', itemId, source: origin })
  • Open source lane (link, data-veritas-topic-source-action={sourceId})
    • Function: navigates to source's href

Sophia bundle (if present per topic)#

  • Inspect bundlehandleTopicSophiaBundleInspection(claimId) opens overlay with the Sophia-backed pack (citations, source graph, grounding status, claim checks)

Alert controls#

  • Realtime / Daily / Weekly (buttons, data-veritas-topic-alert-frequency={frequency})
    • Function: handleTopicAlertFrequencyChange(frequency) calls updateTopicAlert and fires trackVeritasTopicAlertFrequencyUpdated({ topicId, topicTitle, alertFrequency, source: origin })
    • Disabled when topic is unfollowed (the handler returns early)

Topic follow-ups#

  • Topics follow-up link (data-veritas-topic-followup-action="topics")
  • Clusters follow-up link (data-veritas-topic-followup-action="clusters")
  • Research follow-up link (data-veritas-topic-followup-action="research")

Data & contracts#

  • Reads (imported): TOPIC_HUBS[topicKey]getTopicKey(topicId) returns TopicKey | null: a known id resolves to its key, an undefined id (this route — no topicId is passed) defaults to 'renewable-energy', and an unknown id returns null → the workspace renders VeritasTopicNotFoundPanel. This route doesn't pass topicId, so renewable-energy is loaded.
  • Reads (store): useVeritasStore via useSyncExternalStorefollowedTopics, followTopic, unfollowTopic, updateTopicAlert
  • Reads (Sophia): VERITAS_TOPIC_SOPHIA_EVIDENCE_BUNDLES[topicId]
  • Telemetry: trackVeritasInspectionOpened, trackVeritasTopicFollowed, trackVeritasTopicUnfollowed, trackVeritasTopicAlertFrequencyUpdated
  • Writes (store): followTopic, unfollowTopic, updateTopicAlert
  • Realtime: none in this view (alert frequencies are read; actual delivery happens elsewhere)
  • Caching: imported canonical data
  • Auth/role check: shell middleware (verify)
  • Page metadata: not set (client component)

Cross-references#

Open questions / known gaps#

  • No topicId is passed by the page, so the route is effectively pinned to renewable energy; confirm whether this default route should redirect to a slug-shaped URL once V1 wires real data
  • Follow state lives in useVeritasStore (local store) — verify whether V1 wants this synced to a BFF subscription
  • No sr-only <h1> in page.tsx; the workspace hero <h1> provides the page title
  • Alert frequencies surface as buttons but their disabled-when-unfollowed state may not be visually distinct — verify the disabled styling
  • No tests are co-located in this folder (workspace tests live in components/domains/veritas/__tests__/)