# How Archify Traces Upstream and Downstream Relationships in the Viewer: A Complete Technical Guide

> Learn how Archify's viewer traces upstream and downstream relationships. This technical guide explains its transitive closure and DFS analysis on the JSON IR for complete graph visibility.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: deep-dive
- Published: 2026-08-05

---

**Archify's interactive viewer performs upstream/downstream reachability analysis by computing the transitive closure of directed edges in the authored graph, using depth-first search over the JSON IR to highlight all reachable nodes from any selected focus point.**

The `tt-a1i/archify` repository provides a specialized tool for visualizing software architecture through authored facts rather than runtime telemetry. Its viewer component includes a sophisticated reachability engine that lets developers trace dependency chains in both directions through their system's topology. This article explains exactly how that analysis works, where the implementation lives, and how to invoke it programmatically.

## What Upstream/Downstream Reachability Analysis Actually Does

Archify's viewer operates on **authored facts** — deterministic, source-verified relationships stored in a typed JSON intermediate representation. When you select a node and trigger reachability analysis, the viewer does not query live systems or parse code on demand. Instead, it walks the pre-computed edge list that was generated when the architecture was authored.

The analysis produces the **transitive closure** of all relationships connected to your chosen node:

- **Upstream** — finds every node that can reach the focus node (dependencies flowing in)
- **Downstream** — finds every node reachable from the focus node (dependencies flowing out)

Because the graph is fully typed and the edge directions are explicit in the JSON IR, this computation is deterministic and fast regardless of graph size.

## The Algorithm: Depth-First Search Over Directed Edges

In [`archify/viewer.js`](https://github.com/tt-a1i/archify/blob/main/archify/viewer.js) (bundled within [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html)), the `reach()` method implements the core traversal logic. The algorithm maintains two data structures: a `visited` Set to track processed nodes and a stack for iterative depth-first search.

```javascript
// Simplified implementation from archify/viewer.js
function reach(direction) {
  const startId = this.currentFocus;          // id of the focused node
  const graph = this.graph;                   // authored nodes + edges
  const visited = new Set();
  const stack = [startId];

  while (stack.length) {
    const id = stack.pop();
    if (visited.has(id)) continue;
    visited.add(id);

    const edges = direction === 'upstream' ? graph.inEdges[id] : graph.outEdges[id];
    for (const e of edges) stack.push(e.source === id ? e.target : e.source);
  }

  this.highlightNodes([...visited]);          // visual cue for the reachable set
}

```

The method selects edge direction based on the `direction` parameter:

- `graph.inEdges[id]` — all edges where `id` is the target (for upstream)
- `graph.outEdges[id]` — all edges where `id` is the source (for downstream)

The edge traversal logic handles both cases uniformly: for each edge, it pushes the *other* endpoint onto the stack to continue the walk.

## Data Source: The JSON IR Schema

The reachability algorithm consumes data structured according to the schema defined in [`archify/schemas/README.md`](https://github.com/tt-a1i/archify/blob/main/archify/schemas/README.md). This JSON document contains:

- **nodes** — typed entities (services, databases, queues, etc.) with stable identifiers
- **edges** — directed relationships with explicit `source` and `target` fields

The deterministic nature of this authored data guarantees that reachability results match the source-verified architecture exactly. There is no drift between the visual trace and the actual system design because both derive from the same immutable facts.

## User Interface Controls and Interactions

The README documents three ways to initiate reachability analysis in the viewer:

1. **Toolbar buttons** — click **Upstream** or **Downstream** after focusing a node
2. **Keyboard shortcuts** — press `/` to focus, then `U` (upstream) or `D` (downstream)
3. **Programmatic API** — call `viewer.reach('upstream')` or `viewer.reach('downstream')`

The focused node receives visual emphasis, and all reachable nodes are highlighted with a distinct styling. Nodes outside the reachable set remain visible but de-emphasized, providing immediate visual context for the dependency footprint.

## Deep-Linking and State Persistence

Archify's viewer encodes reachability state directly in the URL hash, enabling shareable, bookmarkable views. The format uses two fragments:

```

#focus=router&reach=downstream

```

- `#focus=<node-id>` — identifies the centered/highlighted node
- `#reach=upstream|downstream` — activates the corresponding reachability mode

When a URL with these fragments loads, the viewer:

1. Parses the hash parameters
2. Centers the viewport on the specified node
3. Executes the reachability analysis automatically
4. Highlights the computed reachable set

This deep-linking capability is implemented in the viewer's initialization sequence within [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html), making architecture reviews and incident response workflows reproducible across teams.

## Programmatic Usage Example

For integrating reachability into custom workflows, the viewer exposes a clean JavaScript API:

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Archify Viewer</title>
  <script src="archify/viewer.js"></script>
</head>
<body>
  <archify-viewer src="examples/web-app.architecture.json"></archify-viewer>

  <script>
    const viewer = document.querySelector('archify-viewer');

    viewer.addEventListener('load', () => {
      // Focus the "router" node and trace downstream dependencies
      viewer.focusNode('router');
      viewer.reach('downstream');
    });
  </script>
</body>
</html>

```

The `focusNode()` method establishes the traversal origin. The `reach()` method accepts either `'upstream'` or `'downstream'` as string parameters, matching the UI controls.

## Where the Implementation Lives

| File | Purpose |
|------|---------|
| [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html) | Full-screen demo with embedded viewer source, includes `reach()` implementation and UI controls |
| [`archify/schemas/README.md`](https://github.com/tt-a1i/archify/blob/main/archify/schemas/README.md) | JSON IR schema specification defining the node/edge structure consumed by reachability analysis |
| [`README.md`](https://github.com/tt-a1i/archify/blob/main/README.md) (section "Trace upstream/downstream authored reach") | User-facing documentation of controls and deep-link format |

The viewer implementation in [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html) contains the bundled [`archify/viewer.js`](https://github.com/tt-a1i/archify/blob/main/archify/viewer.js) source, which is not separately distributed as a standalone file in the repository. For modification or debugging, examine the source embedded in the HTML file between the `<script>` tags.

## Performance Characteristics

The depth-first search implementation provides **O(V + E)** time complexity where V is reachable nodes and E is traversed edges. The iterative stack approach avoids recursion limits on large graphs. Memory overhead is **O(V)** for the `visited` set and active stack.

Because the authored graph is static, reachability results can technically be pre-computed and cached, though the current implementation computes on-demand to support dynamic focus changes. The deterministic IR ensures identical results across repeated executions.

## Summary

- **Upstream/downstream reachability analysis** in Archify computes transitive closures over authored dependency graphs, not live runtime data
- The algorithm uses **depth-first search** with iterative stack traversal in [`archify/viewer.js`](https://github.com/tt-a1i/archify/blob/main/archify/viewer.js)
- Data source is the **typed JSON IR** defined in [`archify/schemas/README.md`](https://github.com/tt-a1i/archify/blob/main/archify/schemas/README.md), ensuring deterministic, source-verified results
- **Three interaction modes**: toolbar buttons, keyboard shortcuts (`/` → `U`/`D`), and programmatic `viewer.reach()` API
- **Deep-linking** via `#focus=<id>&reach=<direction>` URL fragments enables shareable analysis states
- Time complexity is **O(V + E)**, suitable for interactive use on large architecture graphs

## Frequently Asked Questions

### How does Archify's reachability analysis handle cycles in the dependency graph?

The `visited` Set in the `reach()` implementation prevents infinite loops. Before processing any node, the algorithm checks `visited.has(id)` and skips if already processed. This standard cycle-handling approach ensures termination regardless of graph topology, and the reachable set correctly includes all nodes in cyclic dependency chains without duplication.

### Can I trigger upstream/downstream analysis without using the keyboard shortcuts?

Yes. The viewer exposes the `reach(direction)` method on the DOM element. After selecting your target node with `viewer.focusNode(id)`, call `viewer.reach('upstream')` or `viewer.reach('downstream')` from JavaScript. This is the same API the toolbar buttons and keyboard shortcuts invoke internally.

### What's the difference between Archify's reachability and static analysis tools?

Archify operates on **authored facts** — explicit architectural decisions captured in the JSON IR. Static analysis tools infer relationships by parsing source code. Archify's approach guarantees the visualized dependencies match the intended design, making it valuable for design reviews, compliance checks, and communication with stakeholders who need trustworthy topology views.

### Where is the standalone [`archify/viewer.js`](https://github.com/tt-a1i/archify/blob/main/archify/viewer.js) file located?

The viewer is currently distributed as bundled source embedded in [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html). There is no separate [`viewer.js`](https://github.com/tt-a1i/archify/blob/main/viewer.js) file in the repository structure. For production deployments, extract the JavaScript from between the `<script>` tags in that example file, or reference the complete HTML demo directly.