Each time a scan completes, Z-Sans creates a timestamped project directory inside the output directory, containing the complete asset graph and an interactive report.

Directory Structure

output/                            # Root directory (configured by output.dir / -o)
└── 20260812_231800/               # Timestamped subdirectory YYYYMMDD_HHMMSS
    ├── zsans_20260812_231800.json          # Complete asset graph
    ├── zsans_20260812_231800_assets.csv    # Asset table
    ├── zsans_20260812_231800_relations.csv # Relation table
    ├── zsans_20260812_231800.graphml       # GraphML topology
    └── zsans_20260812_231800_report.html   # Interactive HTML report
  • Prefix: default zsans, controlled by the output.output_prefix configuration
  • Timestamp: %Y%m%d_%H%M%S (local time)
  • Directory creation timing: pre-created and cached when the engine start() is called; plugin artifacts are written to the same directory, accessible via engine.output_handler.run_dir

File generation is controlled by the output.formats switches (html maps to the internal report type report).

JSON Asset Graph

{prefix}_{timestamp}.json — a machine-readable format of the full asset graph; it is the data source for the Web console and project comparison.

{
  "schema_version": 2,
  "zs_version": "0.0.7",
  "stats": { "nodes": 120, "edges": 310 },
  "metrics": {
    "assets_processed": 120,
    "new_assets_found": 115,
    "depth_reached": 4,
    "errors": 0
  },
  "seeds": { "domains": ["example.com"], "ips": [], "ip_ranges": [] },
  "config_hash": "<sha256 of config>",
  "generated_at": "2026-08-12T23:18:00",
  "nodes": [
    {
      "uid": "domain:example.com",
      "type": "domain",
      "value": "example.com",
      "source": "manual",
      "depth": 0,
      "state": "scanned",
      "properties": { "domain": "example.com" }
    }
  ],
  "edges": [
    { "source": "domain:example.com", "target": "ip:93.184.216.34", "relation": "resolved" }
  ]
}

CSV Asset Table

{prefix}_{timestamp}_assets.csv — includes BOM (UTF-8-sig), so Excel opens it directly without garbled characters.

Column Description
ID Asset unique identifier type:value
Type domain / ip / url / port / js / cert
Value Asset value
Depth Discovery depth
Discovery Time Discovery time %Y-%m-%d %H:%M:%S
State new / scanning / scanned / eliminated / failed / excluded
Title/Note url assets take the title (truncated by max_length); port assets take the service name
Fingerprints Comma-joined fingerprint list for url assets
CMS CMS identified by fingerprinting
Server Server-side information

CSV Relation Table

{prefix}_{timestamp}_relations.csv — 3 columns:

Column Description
Source Asset ID Source asset value (UID prefix stripped)
Target Asset ID Target asset value
Relation Type discovered / resolved / hosted

GraphML Topology

{prefix}_{timestamp}.graphml — a standard GraphML 1.0 directed graph, visualizable with Gephi, Cytoscape, etc.

  • Node id: asset UID (type:value)
  • Node attribute keys: type, value, depth, discovery_time, state, plus url-asset-specific title, fingerprints, cms, server
  • Edge attribute key: relation

{prefix}_{timestamp}_report.html — a self-contained interactive report (inline JS/CSS, no internet required), works right after opening.

Overview Tab

  • Statistics cards: total assets, total relations, processed, newly discovered, max depth, elapsed time, seed count
  • Seed asset list (domains + IPs)
  • Top Hosts: top 15 by descending degree
  • Asset type distribution: horizontal bar chart + donut chart

Topology Tab

  • Native Canvas force-directed topology graph (no third-party graph library)
  • When nodes > 300, truncated to 300 by degree
  • Nodes colored by type, radius grows with degree, labels shown when zoom > 1.6
  • Drag to pan, wheel / pinch zoom (0.05~8x), auto fit

Active Assets Tab

Asset table (Type/Value/Depth/Discovery Time/State/Title-Note/Fingerprints/CMS/Server) + live filtering.

Excluded Assets Tab

Table of excluded assets + reasons; requires output.keep_eliminated_assets: true (on by default) to have data.

Metrics Tab

  • Full engine.metrics key-value pairs
  • Port distribution (service / count)
  • Exclusion reason statistics (reason / count)
  • Search box: case-insensitive substring match on the whole row text
  • Three dropdown filters: Type, State, Depth
  • Live-updating count: Showing N assets (filtered)

The report language follows the i18n configuration (zh prefix → lang="zh-CN").

Sample HTML Report

HTML report

Checkpoint File

<output_dir>/checkpoint.json (default location) is used for resumable scanning:

  • Save triggers: every checkpoint.interval (default 50) processed assets, and on stop()
  • Atomic write: first write .tmpflush + fsyncos.replace, to prevent corruption on interruption
  • Contents: seeds, metrics, all nodes, edge triples, pending queue