| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- ---
- title: "Graph format"
- description: "Reference for the GraphNode and GraphEdge types used to represent entities and relationships in the Flowsint graph. Understanding these structures is essential for working with the frontend visualization and the graph database layer."
- category: "Developers"
- order: 11
- author: "Flowsint Team"
- tags: ["tutorial", "developers", "graph", "nodes", "edges"]
- version: "1.2.8"
- last_updated_at: "2026-05-15"
- ---
- ## Overview
- Flowsint's graph visualization is built on two core data structures: **GraphNode** (representing entities) and **GraphEdge** (representing relationships between entities). These types are defined in `flowsint-app/src/types/graph.ts` and are used throughout the frontend for rendering, interaction, and data management.
- Understanding these structures is important when:
- - Building enrichers that create nodes and relationships
- - Working on the frontend visualization
- - Debugging graph rendering issues
- - Extending the graph with new visual features
- ## GraphNode
- A `GraphNode` represents a single entity in the graph (e.g., a domain, an IP address, a person). Every node created by an enricher's `create_node()` method ends up as a `GraphNode` in the frontend.
- ```typescript
- type GraphNode = {
- id: string
- nodeType: string
- nodeLabel: string
- nodeProperties: NodeProperties
- nodeSize: number
- nodeColor: string | null
- nodeIcon: keyof typeof LucideIcons | null
- nodeImage: string | null
- nodeFlag: flagColor | null
- nodeShape: NodeShape | null
- nodeMetadata: NodeMetadata
- x: number
- y: number
- val?: number
- neighbors?: any[]
- links?: any[]
- }
- ```
- ### Field reference
- | Field | Type | Description |
- |-------|------|-------------|
- | `id` | `string` | Unique identifier for the node. Derived from the type's primary field value. |
- | `nodeType` | `string` | The entity type (e.g., `"Domain"`, `"Ip"`, `"Email"`). Maps to the Pydantic type class name. |
- | `nodeLabel` | `string` | Human-readable label displayed on the node. Set by the type's `compute_label()` method. |
- | `nodeProperties` | `NodeProperties` | All properties of the entity as key-value pairs. Contains the serialized fields from the Pydantic type. |
- | `nodeSize` | `number` | Visual size of the node in the graph. |
- | `nodeColor` | `string \| null` | Custom color override for the node (CSS color string), or `null` for default. |
- | `nodeIcon` | `keyof LucideIcons \| null` | Icon to display on the node, from the [Lucide icon set](https://lucide.dev/icons/), or `null` for default. |
- | `nodeImage` | `string \| null` | URL to an image to display on the node (e.g., a profile picture), or `null`. |
- | `nodeFlag` | `flagColor \| null` | Color flag for visual tagging (see Flag colors below), or `null`. |
- | `nodeShape` | `NodeShape \| null` | Shape of the node (see Node shapes below), or `null` for default circle. |
- | `nodeMetadata` | `NodeMetadata` | Additional metadata as key-value pairs. Used for internal tracking and extended features. |
- | `x` | `number` | X coordinate position in the graph canvas. |
- | `y` | `number` | Y coordinate position in the graph canvas. |
- | `val` | `number` (optional) | Value used by the force-graph engine for sizing calculations. |
- | `neighbors` | `any[]` (optional) | Adjacent nodes, populated by the graph engine at runtime. |
- | `links` | `any[]` (optional) | Connected edges, populated by the graph engine at runtime. |
- ### NodeProperties
- ```typescript
- type NodeProperties = {
- [key: string]: any
- }
- ```
- A flexible key-value object containing all the entity's properties. When a Pydantic type is serialized into a node, its fields become entries in `nodeProperties`. For example, a `Domain` node would have `nodeProperties.domain`, `nodeProperties.root`, etc.
- ### NodeMetadata
- ```typescript
- type NodeMetadata = {
- [key: string]: any
- }
- ```
- Similar to `nodeProperties` but used for system-level metadata rather than entity data. This can include information like creation timestamps, source enricher, or other tracking data.
- ### Node shapes
- Nodes can be rendered in four shapes:
- ```typescript
- type NodeShape = 'circle' | 'square' | 'hexagon' | 'triangle'
- ```
- | Shape | Use case |
- |-------|----------|
- | `circle` | Default shape for most entity types |
- | `square` | Often used for infrastructure entities |
- | `hexagon` | Used for grouped or aggregate entities |
- | `triangle` | Used for alert or warning-related entities |
- ### Flag colors
- Flags provide a visual tagging system for nodes. Users can flag nodes to highlight them during an investigation.
- ```typescript
- type flagColor = 'red' | 'orange' | 'blue' | 'green' | 'yellow'
- ```
- Each flag color maps to specific Tailwind CSS classes for consistent styling:
- | Flag | Style |
- |------|-------|
- | `red` | `text-red-400 fill-red-200` |
- | `orange` | `text-orange-400 fill-orange-200` |
- | `blue` | `text-blue-400 fill-blue-200` |
- | `green` | `text-green-400 fill-green-200` |
- | `yellow` | `text-yellow-400 fill-yellow-200` |
- ## GraphEdge
- A `GraphEdge` represents a relationship between two nodes (e.g., "RESOLVES_TO", "HAS_SUBDOMAIN", "FOUND_IN_BREACH"). Every relationship created by an enricher's `create_relationship()` method ends up as a `GraphEdge` in the frontend.
- ```typescript
- type GraphEdge = {
- source: GraphNode['id']
- target: GraphNode['id']
- date?: string
- id: string
- label: string
- caption?: string
- type?: string
- weight?: number
- confidence_level?: number | string
- }
- ```
- ### Field reference
- | Field | Type | Description |
- |-------|------|-------------|
- | `source` | `string` | ID of the source node (the "from" node in the relationship). |
- | `target` | `string` | ID of the target node (the "to" node in the relationship). |
- | `id` | `string` | Unique identifier for this edge. |
- | `label` | `string` | Display label for the edge (e.g., `"RESOLVES_TO"`, `"HAS_EMAIL"`). This is the relationship type string passed to `create_relationship()`. |
- | `date` | `string` (optional) | Timestamp associated with the relationship (ISO 8601 format). |
- | `caption` | `string` (optional) | Additional descriptive text displayed on or near the edge. |
- | `type` | `string` (optional) | Relationship classification type for filtering or styling. |
- | `weight` | `number` (optional) | Numerical weight of the relationship, can be used for visual thickness or importance ranking. |
- | `confidence_level` | `number \| string` (optional) | Confidence score for the relationship, indicating how reliable the connection is. |
- ## How enrichers map to the graph
- When you write an enricher and call graph methods in `postprocess()`, here's how the data flows:
- ### Creating nodes
- ```python
- # In your enricher's postprocess method
- self.create_node(domain) # domain is a Pydantic Domain object
- ```
- The graph service automatically:
- 1. Extracts the **type name** from the Pydantic class (e.g., `"Domain"`) -> `nodeType`
- 2. Reads the **primary field** value (e.g., `domain.domain`) -> used for `id`
- 3. Reads the **nodeLabel** field (set by `compute_label()`) -> `nodeLabel`
- 4. Serializes all fields into `nodeProperties`
- 5. Sets defaults for visual properties (`nodeSize`, `nodeColor`, etc.)
- ### Creating relationships
- ```python
- # In your enricher's postprocess method
- self.create_relationship(domain, ip, "RESOLVES_TO")
- ```
- The graph service automatically:
- 1. Identifies the **source node** from `domain`'s type and primary field -> `source`
- 2. Identifies the **target node** from `ip`'s type and primary field -> `target`
- 3. Uses the relationship label `"RESOLVES_TO"` -> `label`
- 4. Generates a unique `id` for the edge
- ### Relationship naming conventions
- Relationship labels follow these conventions:
- - Use **UPPER_SNAKE_CASE** (e.g., `"RESOLVES_TO"`, `"HAS_SUBDOMAIN"`)
- - Use **verb phrases** that describe the relationship direction (source -> target)
- - The default relationship label is `"IS_RELATED_TO"` if none is specified
- - Common patterns:
- - `HAS_*` for ownership/containment (e.g., `"HAS_EMAIL"`, `"HAS_SUBDOMAIN"`)
- - `RESOLVES_TO` for DNS-type lookups
- - `FOUND_IN_*` for breach/leak associations
- - `REGISTERED_BY` for WHOIS data
- ## Graph settings
- The graph visualization is configurable through settings types:
- ### ForceGraphSetting
- Controls the physics simulation of the force-directed graph layout:
- ```typescript
- type ForceGraphSetting = {
- value: any
- min?: number
- max?: number
- step?: number
- type?: string
- description?: string
- }
- ```
- ### ExtendedSetting
- General-purpose settings with richer type information:
- ```typescript
- type ExtendedSetting = {
- value: any
- type: string
- min?: number
- max?: number
- step?: number
- options?: { value: string; label: string }[]
- description?: string
- }
- ```
- These settings allow users to customize graph behavior like node repulsion, link distance, simulation speed, and visual preferences.
- ## Reserved properties
- When creating nodes, certain property names are reserved by the system and should not be used as field names in your custom types:
- - `id` - Node identifier
- - `x`, `y` - Position coordinates
- - `nodeLabel` - Display label (set by `compute_label()`)
- - `label` - Legacy label field
- - `nodeType`, `type` - Entity type identifiers
- - `nodeImage`, `nodeIcon`, `nodeColor`, `nodeSize` - Visual properties
- - `created_at` - Creation timestamp
- - `sketch_id` - Investigation sketch association
|