InstallHub
Installation
After validation, security scanning, and ID remapping, the import engine installs each artifact in dependency order within a single database transaction. All artifacts install or none do.
Install Order
Artifacts are installed in the order specified by manifest.installOrder — a topological sort of the dependency graph. Dependencies are always created before the artifacts that reference them:
installOrder: ["ent-44", "rule-305", "form-2005", "thread-2002", "proc-1001"]
Step 1: Create EntitySchema (ent-44 → ent-2291 after remapping)
Step 2: Create RuleSet (rule-305 → rule-6612)
Step 3: Create AtlasForm (form-2005 → form-9104) — references ent-2291
Step 4: Create ThreadDef (thread-2002 → thread-8831) — references form-9104
Step 5: Create ProcessDef (proc-1001 → proc-7823) — references all above
Transactional Installation
The entire installation runs within a single database transaction. If any artifact fails to install — for any reason — the transaction is rolled back and the target tenant is left unchanged:
await using var transaction = await _db.BeginTransactionAsync(ct);
try
{
foreach (var artifactId in manifest.InstallOrder)
{
var artifact = remappedArtifacts[artifactId];
await InstallArtifactAsync(artifact, context, ct);
}
await transaction.CommitAsync(ct);
}
catch
{
await transaction.RollbackAsync(ct);
throw;
}
Install vs. Update Decision
For each artifact, after conflict resolution, the install engine decides whether to create or update:
| Conflict Strategy | Existing Artifact? | Action |
|---|---|---|
| Any strategy | No | CREATE — new artifact in target tenant |
| Replace | Yes | UPDATE — overwrite the existing artifact |
| Merge | Yes | MERGE — apply diff to existing artifact |
| Skip | Yes | SKIP — leave existing artifact unchanged |
Per-Artifact Type Install Operations
| Artifact Type | Install Operation |
|---|---|
| ProcessDefinition | Call Process Engine's CreateProcessAsync or UpdateProcessAsync |
| ThreadDefinition | Call Process Engine's CreateThreadAsync or UpdateThreadAsync |
| AtlasForm | Call Atlas Forms service's CreateFormAsync or UpdateFormAsync |
| RuleSet | Call Rules Engine's CreateRuleSetAsync or UpdateRuleSetAsync |
| EntitySchema | Call Entity service's CreateEntitySchemaAsync or UpdateEntitySchemaAsync |
| AppDefinition | Call App Studio's CreateAppAsync or UpdateAppAsync |
ImportContext During Install
public class ImportContext
{
public string ImportId { get; }
public string TargetTenantId { get; }
public PackageManifest Manifest { get; }
public IDRemapTable RemapTable { get; }
public ImportOptions Options { get; }
public ConflictReport ConflictReport { get; }
public List<InstallRecord> Installed { get; }
public List<string> Skipped { get; }
public bool IsDryRun { get; }
}
public record InstallRecord(
string ArtifactId,
string ArtifactType,
string Name,
InstallAction Action, // Created | Updated | Merged | Skipped
DateTimeOffset InstalledAt
);
Atomic Guarantee
The transaction guarantee means a partially installed package is impossible. Either all 5 artifacts are installed, or zero artifacts are. You never end up with an inconsistent state where a workflow exists but its form does not.