Export System Overview
Phase 1 of InstallHub is production-ready. The export system creates installable packages from any combination of BizFirstGO artifacts, automatically resolving all dependencies.
What the Export System Does
The export system takes one or more artifact IDs and produces a self-contained, integrity-verified ZIP bundle that can be stored, transferred, or installed into any BizFirstGO tenant. The entire pipeline is orchestrated by IExportService and executes in a single operation.
Export Pipeline
Pre-Export Validation
Validates that all specified artifact IDs exist and belong to the requesting tenant. Checks for circular dependencies in the artifact graph. Aborts with a detailed error if any artifact is missing or incomplete.
Dependency Resolution
DependencyResolver traverses the artifact graph starting from the specified root artifacts. It follows all references recursively until no new dependencies are discovered. The result is the complete ordered set of artifacts to include.
Artifact Serialization
PackageSerializer converts each artifact to its JSON representation. Each artifact type has a dedicated serializer ensuring the output is stable and complete.
Checksum Computation
ChecksumComputer computes the SHA-256 hash of all artifact file contents concatenated in dependency order. This checksum is embedded in the manifest.
Manifest Generation
A complete manifest.json is generated listing all included artifacts with their types, versions, and per-artifact hashes, plus the overall bundle checksum.
ZIP Assembly
BundleWriter assembles the final ZIP: artifact files under artifacts/{type}/, the manifest at the root, and an auto-generated README.md.
Audit Logging
The completed export is recorded in ExportHistoryRepository — who exported, what artifacts, when, and the resulting checksum.
What Can Be Exported
| Artifact Type | Dependency Identifier | Auto-resolved? |
|---|---|---|
| Process Definition (workflow) | ProcessDefinition | Root — not auto-resolved from others |
| Thread Definition (sub-workflow) | ThreadDefinition | Yes — resolved from parent ProcessDefinition |
| Atlas Form | AtlasForm | Yes — resolved from workflows that use them |
| Rule Set | RuleSet | Yes — resolved from workflows and forms |
| Entity Schema | EntitySchema | Yes — resolved from entity data nodes |
| App Definition | AppDefinition | Yes — resolved from app-type artifacts |
Service Contract
public interface IExportService
{
/// <summary>
/// Creates an InstallHub package from the specified artifacts.
/// Dependencies are resolved automatically.
/// </summary>
Task<ExportResult> ExportAsync(ExportRequest request, CancellationToken ct = default);
/// <summary>
/// Returns the export history for a tenant, newest first.
/// </summary>
Task<IReadOnlyList<ExportHistoryRecord>> GetHistoryAsync(
string tenantId,
int pageSize = 50,
CancellationToken ct = default);
/// <summary>
/// Downloads the ZIP bytes for a previously created package.
/// </summary>
Task<byte[]> DownloadBundleAsync(string packageId, string tenantId, CancellationToken ct = default);
}
ExportRequest and ExportResult
public class ExportRequest
{
public string TenantId { get; init; }
public string PackageName { get; init; }
public string PackageType { get; init; } // "workflow-package" etc.
public string Version { get; init; } // SemVer: "1.0.0"
public string? Description { get; init; }
public string[] ArtifactIds { get; init; } // Root artifact IDs
public string RequestedBy { get; init; } // User making the request
}
public class ExportResult
{
public string PackageId { get; init; }
public string PackageName { get; init; }
public string Version { get; init; }
public string Checksum { get; init; } // "sha256:..."
public int ArtifactCount { get; init; }
public string BundleUrl { get; init; }
public PackageManifest Manifest { get; init; }
public DateTimeOffset ExportedAt { get; init; }
public bool IsSuccess { get; init; }
public string? ErrorMessage { get; init; }
}