Domain Specification: Network Analysis¶
Validated against PRD v1.0 — FR-NA-01 and FR-NA-02. See Traceability Matrix.
1. Context Overview¶
Bounded Context: networkanalysis
Responsibility: Map ownership structures as graphs. Discover linked entities through shared attributes.
Owns: EntityGraph aggregate.
Depends On: Onboarding (ownership data), Configuration Engine.
MVP Constraint: Basic relationship traversal only. No advanced graph intelligence (centrality, clustering, hidden network detection — all v2+).
2. Data Model¶
data class EntityGraph(
val graphId: UUID,
val customerId: UUID,
val nodes: List<GraphNode>,
val edges: List<GraphEdge>,
val discoveredLinks: List<LinkedEntity>,
val createdAt: Instant
)
data class GraphNode(
val entityId: UUID,
val entityType: NodeType, // CUSTOMER, UBO, INTERMEDIATE, UNKNOWN
val label: String,
val country: String?,
val riskFlags: List<String> // PEP, SANCTIONED, HIGH_RISK_JURISDICTION
)
enum class NodeType { CUSTOMER, UBO, INTERMEDIATE, UNKNOWN }
data class GraphEdge(
val sourceId: UUID,
val targetId: UUID,
val edgeType: EdgeType, // OWNS, DIRECTS, SHARES_ADDRESS, SHARES_DIRECTOR, SHARES_IDENTIFIER
val ownershipPct: Double?, // only for OWNS edges
val confidence: Double // 0.0-1.0 for auto-discovered edges
)
enum class EdgeType { OWNS, DIRECTS, SHARES_ADDRESS, SHARES_DIRECTOR, SHARES_PHONE, SHARES_EMAIL, SHARES_IDENTIFIER }
data class LinkedEntity(
val entityId: UUID,
val linkType: String, // "Shared director: John Smith", "Shared address: 123 Main St"
val sharedAttribute: String,
val confirmationStatus: ConfirmationStatus // DISCOVERED, CONFIRMED, DISMISSED
)
enum class ConfirmationStatus { DISCOVERED, CONFIRMED, DISMISSED }
3. Discovery Algorithms¶
3.1 Ownership Graph (FR-NA-01)¶
Traverses onboarding.ownership_relationship recursively (PostgreSQL recursive CTE) up to 10 levels deep. Color codes nodes: customer (blue), UBO (green), intermediate (gray), unknown (red).
3.2 Linked Entity Discovery (FR-NA-02)¶
For all entities in the ownership graph, query for matches on: - Shared director: Same individual is a director of both entities - Shared address: Registered addresses match (normalized) - Shared phone/email: Contact information matches - Shared registration agent: Same agent filed incorporation
Results shown as dashed edges in the graph. Analyst confirms or dismisses each.
4. API Contracts¶
4.1 Build Ownership Graph¶
POST /api/v1/network-analysis/graph
Authorization: System
Request: { "customerId": "uuid", "maxDepth": 10, "includeDiscoveredLinks": true }
Response 200:
{
"graphId": "uuid",
"nodes": [
{ "entityId": "uuid-cust", "entityType": "CUSTOMER", "label": "ACME Holdings B.V.", "country": "NLD", "riskFlags": [] },
{ "entityId": "uuid-ubo1", "entityType": "UBO", "label": "John Smith", "country": "GBR", "riskFlags": ["PEP"] },
{ "entityId": "uuid-int", "entityType": "INTERMEDIATE", "label": "ACME International Ltd.", "country": "BMU", "riskFlags": ["HIGH_RISK_JURISDICTION"] }
],
"edges": [
{ "sourceId": "uuid-ubo1", "targetId": "uuid-int", "edgeType": "OWNS", "ownershipPct": 100.0, "confidence": 1.0 },
{ "sourceId": "uuid-int", "targetId": "uuid-cust", "edgeType": "OWNS", "ownershipPct": 100.0, "confidence": 1.0 }
],
"discoveredLinks": [
{
"entityId": "uuid-other",
"linkType": "Shared director: John Smith",
"sharedAttribute": "John Smith (DOB 1975-03-15) is director of both ACME International Ltd. and XYZ Corp.",
"confirmationStatus": "DISCOVERED"
}
]
}
5. Error Handling¶
| Scenario | Behavior |
|---|---|
| No ownership data | Returns empty graph with 1 node (customer). "No ownership data available for this customer." |
| Max depth exceeded | Returns graph up to maxDepth. Warning: "Ownership chain exceeds max depth (10). Deeper levels not shown." |
| Customer not found | 404 Not Found. |
Spec validated against PRD v1.0. MVP scope: basic traversal + shared attribute discovery. No advanced graph algorithms.