Portal Community

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 StrategyExisting Artifact?Action
Any strategyNoCREATE — new artifact in target tenant
ReplaceYesUPDATE — overwrite the existing artifact
MergeYesMERGE — apply diff to existing artifact
SkipYesSKIP — leave existing artifact unchanged

Per-Artifact Type Install Operations

Artifact TypeInstall Operation
ProcessDefinitionCall Process Engine's CreateProcessAsync or UpdateProcessAsync
ThreadDefinitionCall Process Engine's CreateThreadAsync or UpdateThreadAsync
AtlasFormCall Atlas Forms service's CreateFormAsync or UpdateFormAsync
RuleSetCall Rules Engine's CreateRuleSetAsync or UpdateRuleSetAsync
EntitySchemaCall Entity service's CreateEntitySchemaAsync or UpdateEntitySchemaAsync
AppDefinitionCall 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.