Skip to Content

The Domain Data Model

The persisted representation of a cloud environment (AWS, GCP, or Azure) lives in src/aws/model.ts. It is deliberately decoupled from rendering: a resource references a ServiceDefinition by id and stores config keyed by that service’s ConfigField keys. This is exactly what the server stores and what the discovery transform and IaC importers produce.

Entities

  • Account — an account in scope: accountId (an AWS 12-digit account id, or a GCP project / Azure subscription identifier), name, optional environment ("prod" | "staging" | …) and color.
  • RegionRef{ code, name }. The common set lives in src/aws/regions.ts (REGIONS, regionName(code)); extend freely.
  • ResourceInstance — a concrete instance of a service:
    • serviceId references ServiceDefinition.id.
    • Placement / scoping: accountId, region, and parentId.
    • config: Record<string, unknown> keyed by the service’s ConfigField keys.
    • tags, arn (real ARN when known), and source ("manual" | "imported" | "mcp" — drives trust/edit affordances).
    • position?: CanvasPosition (x, y, w, h) — presentation kept separate from data.
    • raw?: RawSource — the verbatim source type + properties from an IaC import, kept so the resource can be re-emitted faithfully (never holds credentials). See IaC Import & Export.
  • Relationship — a typed, directional (or symmetric) edge: { id, from, to, kind, label?, source? } where from/to are ResourceInstance.ids and kind is a RelationshipKind.
  • InfrastructureGraph — the top-level persisted entity: id, name, accounts[], resources[], relationships[], optional viewport, createdAt/updatedAt (stamped by the repository, never by scripts), schemaVersion (SCHEMA_VERSION = 1, for forward migration), and optional iacSource — the template-level sections (Parameters / Mappings / Conditions / Outputs / Metadata) preserved from an IaC import for faithful re-emit (see IaC Import & Export).
export interface InfrastructureGraph { id: string; name: string; description?: string; accounts: Account[]; resources: ResourceInstance[]; relationships: Relationship[]; viewport?: Viewport; iacSource?: IacSource; // template-level sections kept for lossless IaC re-emit createdAt?: string; updatedAt?: string; schemaVersion: number; }

Containment via parentId

Logical containment is modeled as a single field, ResourceInstance.parentId: a VPC contains subnets, a subnet contains EC2 instances, etc. This is a tree reference, distinct from the relationship graph. Helpers:

  • childrenOf(graph, parentId) — direct children.
  • resourcesByAccount(graph, accountId).
  • relationshipsOf(graph, resourceId).

Note: containment is both modeled here and rendered — children pack visually inside their parent’s bounds via the pure layout engine in src/canvas/layout.ts. See Visual Mapping.

Placement scopes

ServiceDefinition.scope (global | region | az | vpc | subnet | project | resource-group) describes where a resource conceptually belongs and is the basis for placement validation and future layout: IAM is global, an S3 bucket is region-scoped, a subnet is az-scoped, an EC2 instance must sit inside a subnet, and so on. The last two are the multi-cloud containers: project is a GCP project/org-level scope, and resource-group is an Azure resource group (a mandatory regional container).

Validation & summaries

  • validateGraph(graph) returns structural errors: duplicate resource ids, parentIds pointing at missing resources, and relationships referencing missing from/to. The API enforces this on every write (see Persistence) and it is covered by the model and route tests in CI (see Testing).
  • summarize(graph) → GraphSummary produces the lightweight shape list endpoints return (avoids shipping full graphs).
  • emptyGraph(name) produces a minimal valid graph; id/timestamps are assigned on persist.

A separate runtime shape check lives in src/server/graphSchema.ts (isInfrastructureGraph, hasGraphCollections): the model is a compile-time contract only, so data crossing a trust boundary (request bodies, JSON on disk) is structurally validated before being treated as an InfrastructureGraph.

Last updated on