Skip to Content
Architecture · Web application

The components, grouped by the job each one does.

What they are for

The web application is built from ReactReactThe library used to build the interface from reusable pieces called components. components in apps/ui/components. Together they provide the organisation mapMapThe view of teams, services and their dependencies for the selected part of the organisation. Details appear beside the map., findingsFindingA difference in the records that needs a decision. It includes its sources and can describe a slow handoff, disputed fact or missing owner., evidence, AskAskThe tab that composes an answer to a question in your own words, from the records, with each statement pointing to its sources. Ask answers only as far as your role can see., accountability, agent views, import, documents and GuideGuideThe help pages inside NovusLens. They explain the pages, input formats and tasks in the version you use. They are product instructions, not evidence about the organisation.. A reader sees these as pages; an engineer maintaining them needs to know which component owns which view and where its data comes from.

This page groups the components by feature. For each group it gives a short description and a table: the component, its role, and how it reaches data. Data arrives in one of three ways, and the tables say which:

  • PropsPropsValues a parent component supplies to another component, such as the organisation identifier or records it should display. from a server page. A page under apps/ui/app loads the twinTwinNovusLens’s model of one organisation, built from records about its teams, services and how they rely on one another. It is only as current as those records. with loadTwinForPage (in apps/ui/lib/pageAccess.ts) and passes the result down as props.
  • A fetch to the reasoning proxyProxyA service that receives a request and forwards it to another service. The NovusLens web proxy adds the signed-in identity and service token.. Browser code calls /api/reasoning/.... The route handler at apps/ui/app/api/reasoning/[...path]/route.ts forwards the call to the reasoning service.
  • A fetch to a small route. A few components call /api/guide/{id} (help text) or /api/access/record (a receiptReceiptA recorded acknowledgement of a request or action, with its identity, time and result. An evidence intake receipt confirms storage. It does not establish acceptance or prove that an agent acted. check).
The tables below say which of the three paths each component uses.

The shell and navigation

Every organisation page starts with the same header, navigation, refusal pattern and account controls. These components are what a reader sees before any content.

OrgHeader is the one header for organisation pages. It renders FidelityStrip, the live fidelityTwin fidelityCounts of the model's sourced facts at the told, shown and measured evidence levels. It describes the available support, not whether the claims are true. read-out with a plain-words explainer for each term. WorkspaceNav holds five destinations (organisation and records), with pages nested beneath the active destination in the left navigation. On phones, a navigation drawer presents the same links. AccessRefusal is the single refusal pattern, with three states: sign in, no access, and erased. Every page that loads a twin uses it when loadTwinForPage refuses.

ComponentRoleClient or serverHow it reaches data
OrgHeaderProduct mark, a link back to the reader’s organisations, and the facts line.No directive. Rendered by the server pages app/page.tsx, app/overview, app/car, app/evidence and app/brief.Props org, viewer and twin from the page. No fetch.
FidelityStripLive fidelity read-out, with an explainer for each term.Client.Props fidelity, readModel and now, passed down from OrgHeader. No fetch.
WorkspaceNavGrouped sidebar, mobile navigation drawer and current-page breadcrumb.Client.Props org, viewer, active, role, view, cell, drill and capturedAt. No fetch.
ProfileMenuAccount avatar, organisation and role, documentation, operator diagnostics and sign-out menu.Client. Uses shadcn menu, avatar, button and drawer components backed by Radix.Props from AccountMenu, including the server sign-out action. No record fetch.
AccountMenuAccount controls and the recent receipts list.Server only, an async component. Imported by app/layout.tsx.Reads the session cookieCookieA small value a browser keeps and sends back to a website. NovusLens uses a signed cookie to remember the signed-in account. with cookies() from next/headers, then calls sessionViewer and getLoginRow from apps/ui/lib/twin. It renders RecentReceipts from ui/Overlay. It imports redirect from next/navigation.
GlobalSearchThe Find field. Results are grouped by kind (teams, findings, requests, knowledge).Client.POST /api/reasoning/tools/query_graph with args.select set to search. Props org, viewer, autoSearch and initialQuery. InterrogatePanel also imports it.
HardNavigateA full browser navigation after sign-in, so the next request carries the cookie the browser kept.Client. Used by app/login.Prop href. No fetch.
AccessRefusalThe refusal pattern for a missing sign-in, a missing grant, or an erased organisation.No directive. Rendered by the server pages.Prop refusal, from loadTwinForPage. No fetch.

The shared controls use shadcn sources in components/ui/ and the semantic theme in app/globals.css. The sign-in form uses Button, Input and Card. Overview items use Card. The theme follows the Novus paper, navy and blue brand, with self-hosted Source Sans. Focus outlines remain visible, and reduced-motion preferences apply to transitions.

The twin and the map

The twin surface is one page with several lenses. TwinView is the client shell: it holds the Twin lens (the graphGraphA model made of units and links between them. In NovusLens it records teams, services and their dependencies. and a context panel), the Accountability Map, Alignment and Ask. Selection, lens, view and drill-down live in the URL. The page passes the snapshot in as props, and TwinView itself does not fetch.

TwinGraph draws the graph with CytoscapeCytoscapeThe library that draws the interactive boxes and dependency lines in the organisation map. and places its units automatically using the ELKELKThe layout library that decides where the map boxes and lines are placed. It runs in the browser from code included with the application. layout library. It imports cytoscape and cytoscape-elk, then registers cytoscape.use(elk) at load. Bundled elkjs computes the layout in the browser without external downloads. The elk layout uses elk.direction: DOWN and INCLUDE_CHILDREN for hierarchy handling. This lets a selected team open in place to show its units. Selecting a node and drilling into it are separate gestures: a tap selects, and a double-tap or the panel’s button drills. If Agility and RecoverabilityRecoverabilityThe R in C/A/R: how well a team or service restores acceptable service after a failure. Recovery times and tested alternatives can supply evidence. are unmeasured, the node stays neutral. Complexity alone cannot determine its colour.

The Accountability Map, Alignment and Domains views are sub-views of TwinView. Each takes the twin’s cellsCellA box on the map that stands for a team, service, supplier or AI agent. It is a unit you can inspect, not necessarily a department or a person., edges or domains as props. The Accountability Map and the Domains view open a team through an onOpen callback, so the change happens in place, without a reload. CarAssessment is the one exception: it is the complexity, agility and recoverability assessment on its own page at /car, and it does fetch.

ComponentRoleClient or serverHow it reaches data
TwinViewThe twin surface. Holds the lenses, the selection, the drill-down and the URL state.Client. Rendered by app/page.tsx.Props twin, org, viewer, initialView, initialDrill, initialSelected, initialLens, initialTab and capturedAt. No fetch.
TwinGraphThe live graph (Cytoscape with ELK layout). Shows the twin’s teams and dependenciesDependencyA link where one unit needs something from another. A dependency is not a reporting line: it shows where work relies on something else.. Critical path lengthCPLCritical path length. The total coordination weight of the longest chain of dependencies in the model. NovusLens reports it as index points, not elapsed time. (CPL) is emphasised by drawing an outline behind its links.Client. Imported by TwinView and by the rail.Cells and edges as props. No fetch.
TimelineViewThe change history for the twin, newest first.Client. Imported by TwinView.Props history, org, viewer, cells and findings. No fetch.
AccountabilityMapOne row per team: CapabilityCapabilityWhat a team can provide or an agent can do. NovusLens records the claim and the evidence that supports it. (what it provides), AuthorityAuthorityWhat a team or agent is allowed to decide or do. For an agent, this comes from a named person or system that grants permission. (who may act) and ResponsibilityResponsibilityThe work or result that a team or agent answers for. NovusLens records the person answerable for it. (who stays accountable). A gap is flagged where the authority half is blank.No directive. Imported by TwinView.Props cells, edges, org, viewer, onOpen and emphasis. No fetch.
AlignmentViewCoverageCoverageWhat the available records cover, and what is missing. A count such as “3 of 5 dependencies measured” names the measured portion and the gap. by provenanceProvenanceThe record of where a value came from, who stated it and when. Every value keeps this record. rungRungOne of three levels of support for a recorded value: told, shown or measured. The level appears beside the value. and by attribute (Structure, Complexity · Agility · Recoverability, Authority), with staleness. The rungs are named Told, Shown and Measured.No directive. Imported by TwinView.Prop rows. No fetch.
DomainLensThe business-domain view beside the team map. A domain spread across teams is shown as evidence, not a verdict.No directive. Imported by TwinView.Props domains, cells, findings, org, viewer and onOpen. No fetch.
CarAssessmentThe complexity, agility and recoverability assessment for a team, with the dependency capture form and the archive and replay actions.Client. Rendered by app/car/page.tsx.Props org, viewer, role, cells, initialCell and initialScope. Fetches GET /api/reasoning/car/assessment. Posts to POST /api/reasoning/car/archive, /car/retain-findings and /car/capture. The archive link is GET /api/reasoning/car/replay.

Group of twins

A group is several regional twins seen together. The Group page shows each member’s published summary and the signed, verified facts that cross a region boundary. Raw in-region graphs are not shown here.

ComponentRoleClient or serverHow it reaches data
GroupViewThe consolidated cross-region picture, and a question box that asks the group.Client. Rendered by app/group/page.tsx.Props viewer and groupId from the page. Fetches GET /api/reasoning/group/snapshot with viewer and group_id. The question box posts to POST /api/reasoning/compass/group.

Findings and the evidence rail

The rail is the side panel beside the twin. It has four tabs, Summary, Findings, Changes and Evidence, and the active tab is held in ?tab=. The header holds the breadcrumb, the team picker and the switch between told and current evidenceCurrent evidenceA view that uses only measurements recent enough to count. The “What we were told” view uses recorded statements instead.. The rail is the place where a reader moves from a number to the record behind it.

Each finding carries a recorded detail, shown as labelled lines rather than raw JSONJSONJavaScript Object Notation: a text format for data, using named fields, lists and values. Configuration files and service messages use it.. For a generated finding, GeneratedFindingReview shows the support review that GET /api/reasoning/findings/support-review returns. Items that need a decision come first in NeedsDecision, and each carries the one action it needs. The evidence drawer lists the records behind a team or a finding, and it is where a reader can challenge a record. A challengeChallengeA recorded dispute of a value. Both the original and the disputed version are kept, and the challenge is listed under Findings., a resolution or a retractionRetractionThe withdrawal of a finding or meaning entry, with the reason recorded. The record keeps who withdrew it, when and why; it is not deleted. is a form in the drawer that ends in a receipt. The page never uses window.prompt.

ComponentRoleClient or serverHow it reaches data
RailThe rail shell with its four tabs.Client. Imported by TwinView.Props from TwinView, including twin, org, viewer, view, selectedCell, edges and drill. Imports FindingsList, TwinGraph and the other rail panels. No fetch of its own.
RailHeaderBreadcrumb, team picker and the told or current switch. Exports Breadcrumb and TeamPicker.Client.Props cells, selected, orgLabel and onSelect. No fetch.
RailPanelsThe Summary and Evidence panels, including CellSummary. A blank value says why it is blank.Client.Props from Rail (cell, cells, edges, domains, aliases and more). Renders CellChat, ProvenanceChip and EvidenceDrawer. Calls /api/access/record only to show a receipt.
ChangesListThe Changes tab: what changed, when, and the values in the details.Client.Props history, cells, findings, org, viewer, scoped and atCell. No fetch.
FindingsListThe Findings tab. Lists findings with their recorded detail.Client. Imported by Rail.Props findings, cells, org and viewer. Renders GeneratedFindingReview and EvidenceButton. No direct fetch.
GeneratedFindingReviewShows the support review for a generated finding. Also used on the overview page and inside GovernanceLens.Client.Props org and viewer. Fetches GET /api/reasoning/findings/support-review.
NeedsDecisionOpen items, each with its one action. Exports findingTouches.Client.Props findings, requests, cells, org, viewer, readOnly, onSelect and atCell. Renders FulfilRequest, FindingActions and EvidenceDrawer.
FulfilRequestAttaches a document to an open evidence requestEvidence requestA request for a document to support something somebody stated. The Findings tab lists it as Evidence requested.. The attached facts move from told to shown.Client. Imported by NeedsDecision.Props viewer, org, request and onFulfilled. Posts to POST /api/reasoning/operations/fulfil.
FindingActionsResolve and retract forms for a finding.Client.Posts to POST /api/reasoning/operations/resolve-finding for a resolution, or POST /api/reasoning/steward/retract-finding for a retraction. Shows a receipt that checks /api/access/record.
EvidenceDrawerThe records behind a team or finding, and the challenge form. Exports EvidenceButton and useEvidenceDrawer.Client. Also used by app/evidence/page.tsx, QuestionPanel, FindingsList and NeedsDecision.Posts a challenge to POST /api/reasoning/dispute and a view record to POST /api/reasoning/evidence/view.
ProvenanceChipThe rung as a word and a glyph: TOLD (a dim outline), SHOWN (a bright outline) or MEASURED (filled). Renders nothing when there is no rung.No directive. Imported by AlignmentView and RailPanels.Props rung, atCeiling and citation. No fetch.

Asking and answering

Ask is one field with a visible scopeScopeThe work, data, activity or access that a rule, statement or calculation covers. For access, it names the records an account can see. For team measures, “Own operations” covers the selected unit. “Including descendants” adds the units beneath it. and examples that fill it. An answer is shown as the answer, the reason it holds, its numbered sources, and what it does not establish. Saved questions have their own tab. The in-progress question is kept in sessionStorage, so switching tabs does not lose an answer that is still coming.

Ask does not answer from the browser. QuestionPanel posts to the reasoning service through the proxy, and reads the answer back with polling. The Interrogate panel adds two more routes on top of Ask: a named what-ifWhat-ifA scenario that changes one or more dependencies in the model and reports the result. A what-if changes nothing in the records, and its result is indicative. (tools/simulate_scenario) and a search. The cell chat is the reverse path. It captures what a reader tells the twin about one team. A document handed over mid-conversation is ingestedIngestRead supplied records or documents and add their information to NovusLens, after the required checks. inline, and its rung moves from told to shown in the same conversation.

ComponentRoleClient or serverHow it reaches data
QuestionPanelAsk and Saved questions. Keeps the polling state, so a switch of tab does not lose an answer.Client. Imported by InterrogatePanel.Props viewer, org, mode, scope, show and onShowAnswer. Fetches GET and POST /api/reasoning/questions, GET /api/reasoning/questions/{id}, and posts to /api/reasoning/questions/{id}/stop-waiting.
InterrogatePanelThree tools in one panel: ask, search and a named what-if.Client. Imported by TwinView.A local post(path, body) helper calls /api/reasoning/{path}. The what-if is tools/simulate_scenario. Renders QuestionPanel and GlobalSearch.
CellChatThe per-cell capture chat. Adds told input about one team, with a document attached mid-conversation.Client. Imported by RailPanels.A local post(path, body) helper calls capture/start, capture/answer, capture/attach, capture/commit and capture/discard under /api/reasoning/.

Accountability and agents

The agent views show what each operational agent is permitted to do, and what it did. They are evidence for the customer’s own review, not a verdict. The governance lens states the evidence ladderEvidence ladderThe three levels of support a record can have, in order: told, shown and measured. once: a claim taken from the agent’s published facts, moving toward what the boundary telemetryBoundary feedRecords supplied by the customer’s own systems about activity at the edge of an agent or service. NovusLens reads those records; it does not watch the agent. observed. Each control gap is shown as evidence for the compliance function.

The remitRemitA written list of an agent’s allowed actions, resources and destinations for information. The list states whether it is complete. is the permitted scope of one agent: its operations, resources and destinations. RemitPanel shows that scope beside each observed activity, with the comparator’s result and the classification of any detector. An incomplete activity stream is shown as incomplete, never as clear. DeclareRemit lets a responsible person author a remit in the product. A draft publishes nothing, and approval comes from the named responsible person.

ComponentRoleClient or serverHow it reaches data
GovernanceLensThe agent-governance lens. Agents as mapped nodes, control gaps as evidence.No directive. Imported by TwinView.Props cells, findings, withheldFindings, org and viewer. Renders AgentEvidenceCases, GeneratedFindingReview and RemitPanel.
AgentEvidenceCasesThe per-agent case list and the case detail: authorisation, execution, outcome and corrections.Client.Fetches GET /api/reasoning/agent-evidence/requests and GET /api/reasoning/agent-evidence/case, each with query parameters.
RemitPanelThe remit and its observed activities, per agent.Client.Fetches GET /api/reasoning/agent-evidence/activities. Props org, viewer, findings, cellLabel and onOpen. Renders DeclareRemit.
DeclareRemitAuthoring and publishing a remit, and export of a declaration.Client.Fetches GET /api/reasoning/catalogues, GET /api/reasoning/remits/product-source and GET /api/reasoning/remits/declarations. Posts to POST /api/reasoning/remits/{path}. Export is GET /api/reasoning/remits/export. Receipts check /api/access/record.

Meaning and import

Two surfaces change what the twin holds from outside it. The meaning panel manages the knowledge libraryKnowledge libraryThe organisation’s written procedures and definitions. Each entry records its source, date and who can read it. NovusLens cites these entries as supplied information.: scoped entries, an ingest form and retraction. The import panel takes an organisation chart, an interview transcript or a structured file, and shows what it proposes before anything is written.

In the import panel a person confirms every proposal. An org chart seeds a new twin’s team skeleton as shown, with no flow between teams. A transcript builds from nothing as told, or, against an existing organisation, challenges the skeleton and records contradictions as contested entries rather than edits. The panel can also export the org chart as the twin now knows it, with the evidence levels and recorded disputes marked. The import page passes readOnly for anyone who is not an operator.

ComponentRoleClient or serverHow it reaches data
MeaningPanelThe knowledge library: list, search, ingest and retract. It previews who can see an entry before it is saved.Client. Rendered by TwinView.Props viewer and org. Fetches GET /api/reasoning/meaning/query. Posts to /api/reasoning/meaning/ingest, /meaning/retract and /meaning/visibility-preview. Teams come from POST /api/reasoning/tools/query_graph. Renders KnowledgeText.
ImportOrgThe Operate surface: import, confirm, discard and export.Client. Rendered by app/import/page.tsx.Props viewer, org and readOnly. A local post(path, body) helper calls operations/import-org, operations/commit-org and operations/discard-proposal under /api/reasoning/. Fetches GET /api/reasoning/operations/pending-proposal, GET /api/reasoning/operations/import-progress (for a running job) and GET /api/reasoning/operations/export-orgchart.

Guide and brief

The Guide is the product’s own help. Docs opens the documentation bundled from apps/docs behind the reader’s session. app/guide/page.tsx redirects stable help identifiers to their local Guide pages. An unknown identifier shows links to the index and manuals. The complete User Manual and Operations Manual each remain one scrolling tutorial. Documentation search uses a local Pagefind index. The question-mark control still opens a help drawer, which reads a Guide page through app/api/guide/[id]/route.ts. See the Guide and help for the reader’s steps.

The briefBriefThe management brief: a printable summary of the differences to review, with their sources, observation dates and limits. It is a snapshot taken when it is printed. is a print-ready page. PrintBrief is the one control on it, a button that opens the browser’s print dialogue. The brief itself is rendered by app/brief/page.tsx, which uses OrgHeader, WorkspaceNav and AccessRefusal.

ComponentRoleClient or serverHow it reaches data
KnowledgeTextA small Markdown renderer. Only http and same-page links become links, and the one image form allowed is a Guide picture. Raw HTMLHTMLHypertext Markup Language: the format used to describe a web page's content and structure. is not run.No directive. Imported by MeaningPanel and ui/HelpLink.Prop text. No fetch.
PrintBriefThe print control.Client. Rendered by app/brief/page.tsx.Calls window.print. No fetch.

Shared interface controls

The controls under components/ui provide shared behaviour: the drawer and receipts, the form for a reason, tabs, help links, provider wiring and the time display.

The receipt is the most important of these. When a reader performs an action, a receipt says what happened. Receipts are kept for the session, and each is bound to the account it was issued under. When a receipt is reopened, its content appears only after /api/access/record answers 204 for that organisation. A refusal or an unavailable check shows a message and no content.

ComponentRoleClient or serverHow it reaches data
OverlayThe overlay provider: one drawer and one confirmation at a time, focus handling, and receipts. Exports useOverlay and RecentReceipts.Client.When a receipt is reopened, fetches its checkUrl, normally /api/access/record, to decide whether its content may be shown.
ProvidersWraps the app in OverlayProvider, passing the session identity and the development viewer fallback.Client. Used by app/layout.tsx.Props identity and devViewerFallback.
ReasonFormAsks for a reason beside the page, then issues a receipt. Exports useReasonForm. Replaces window.prompt and window.alert.Client.Calls a submit function passed by the caller. Uses useOverlay.
HelpLinkThe ”?” beside a section heading. Opens the Guide explanation for that section in the drawer.Client.Fetches GET /api/guide/{id}. Renders KnowledgeText.
TabsARIAARIAAccessible Rich Internet Applications: labels and state information that help assistive tools understand interactive web controls. tabs with arrow keys, Home and End. Exports TabPanel.Client.Props tabs, selected, onSelect, label and idBase. No fetch.
TimeA time formatted for reading, with the exact timestamp on hover.No directive.Props value, dateOnly and missing. No fetch.

How the page components, the rail and the primitives nest, and which proxy routes each one calls.

Last updated