# Domain Modeling in API Cloud: An Explainer for AI Agents

This document explains how Data/Domain Modeling works in the `api-cloud` ecosystem. It serves as a context guide for AI agents needing to generate, manipulate, or understand domain models.

## 1. Core Concepts and Hierarchy

The modeling system is hierarchical, allowing users to define data structures cleanly. The main abstractions, in order of hierarchy, are:

- **DataDomain**: The root level container. Holds everything else. Think of it as a complete project or bounded context.
- **DomainNamespace** *(Optional)*: A grouping mechanism inside a DataDomain. Namespaces can be nested or contain models.
- **DomainModel**: Groups a set of related entities. For example, a `BillingContext` model might contain `Invoice` and `Payment` entities. Models go inside Namespaces or directly at the DataDomain root.
- **DomainEntity**: Defines a concrete data structure or database table (e.g., `User`, `Product`). Belongs to a DomainModel.
- **DomainProperty**: A single data field inside an entity (e.g., `name` string, `age` number). Belongs to a DomainEntity.
- **DomainAssociation**: Represents relationships (foreign keys, links) between different entities (e.g., one-to-many from `User` to `Post`). Belongs to a DomainEntity and points to another DomainEntity.

All these elements descend from abstract base classes, carrying a `kind` identifier (e.g., `DomainEntityKind`, `DomainPropertyKind`) and a unique string `key`.

## 2. Graph-Based Storage and Structure

Under the hood, domains don't merely use nested arrays or objects. **The entire data domain is represented as a mathematical Graph** (specifically a directed, compound, multigraph).

- **Nodes**: Every Namespace, Model, Entity, Property, and Association is a node in the graph.
- **Edges**: 
  1. **Hierarchical Edges**: Represent `parent-child` relationships (e.g., an Entity node has an edge pointing from a Model node indicating ownership).
  2. **Relational Edges**: For Associations, an additional edge is drawn from the source Entity to the target Entity.
- **Root Fields Array**: The `DataDomain` retains an ordered `fields` array for localized ordered presentation, but the graph acts as the authoritative source for querying node linkages and moving nodes across parents.

**Why a Graph?**
- Allows for easy cyclic relationships or cross-referencing without deep object cloning issues.
- Fast traversal of dependencies.
- Simpler algorithm logic to "move" an item: simply delete the edge to the old parent and add an edge to the new parent (e.g., `moveNamespace(key, parentKey)`).

## 3. Managing State & Lifecycle

### Adding and Moving Nodes
When creating models programmatically, operations happen via factory-like methods on parents or the root domain:
- `dataDomain.addNamespace({ ... })`
- `model.addEntity({ key: 'user' })`

Moving elements (e.g., `dataDomain.moveNamespace(namespaceKey, newParentKey)`) involves safely updating graph edges and arrays without rebuilding entire trees.

### Change Notification
Elements manage their reactive lifecycle using events.
- Elements fire a `change` event when updated.
- Updates are dispatched asynchronously using `queueMicrotask` (`notifyChange()`). This debounces subsequent operations in a single tick, ensuring that multiple property modifications only trigger one UI refresh or save cycle refresh.

### Graph Consistency Validation
Before exporting or serializing, graphs are heavily validated to ensure consistency:
- Every `DomainProperty` and `DomainAssociation` *must* have exactly one incoming parent edge from a `DomainEntity`.
- Every `DomainEntity` *must* be rooted under a `DomainModel`.
- `DomainModels` can be at the root level or under `DomainNamespaces`.
- Association targets must exist and appropriately point to entities.

## 4. Storing, Serialization, and Deserialization

Data domains need to be persisted to JSON and loaded back into memory without losing graph connectivity.

### Serialization
Triggered via `toJSON()`, serialization iterates through the core Graph.
- **Nodes Array**: Saves all local nodes' properties.
- **Edges Array**: Saves all edges, retaining metadata like `type: 'association'` vs standard `parent` linkages. 
- *Note*: It smartly ignores transient internal state and specific un-serializable references.

### Deserialization
Loading is complex and handled carefully (`DomainSerialization.ts`):
1. A fresh `DataDomain` is instantiated.
2. Nodes are reconstructed based on their `kind` strings (e.g., passing schema into a `new DomainEntity()` class constructor).
3. **Edges/Linkages**: After nodes are instantiated, the edges are reconstructed. Properties and associations look for their parent IDs in the edges array to establish ownership.
4. **Modes**: Deserialization supports `strict` (fails on errors) and `lenient` (gathers issues in an array for graceful degradation, dropping malformed pieces while preserving the main graph).

### Foreign Domains (Dependencies)
A `DataDomain` can depend on "Foreign Domains" (other domains). 
- In the graph, foreign nodes and edges are dynamically attached at runtime with a namespace prefix (`foreignDomainKey:nodeKey`).
- When serializing, these foreign nodes are intentionally excluded from the local domain's JSON output. They are re-merged during deserialization when dependencies are passed back in. This allows models to locally reference external domain libraries seamlessly.
