Portal Community
Phase 1 — COMPLETE The entire export pipeline is implemented, tested (86% coverage), and deployed to production. All services described in this guide are available now.

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

1

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.

2

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.

3

Artifact Serialization

PackageSerializer converts each artifact to its JSON representation. Each artifact type has a dedicated serializer ensuring the output is stable and complete.

4

Checksum Computation

ChecksumComputer computes the SHA-256 hash of all artifact file contents concatenated in dependency order. This checksum is embedded in the manifest.

5

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.

6

ZIP Assembly

BundleWriter assembles the final ZIP: artifact files under artifacts/{type}/, the manifest at the root, and an auto-generated README.md.

7

Audit Logging

The completed export is recorded in ExportHistoryRepository — who exported, what artifacts, when, and the resulting checksum.

What Can Be Exported

Artifact TypeDependency IdentifierAuto-resolved?
Process Definition (workflow)ProcessDefinitionRoot — not auto-resolved from others
Thread Definition (sub-workflow)ThreadDefinitionYes — resolved from parent ProcessDefinition
Atlas FormAtlasFormYes — resolved from workflows that use them
Rule SetRuleSetYes — resolved from workflows and forms
Entity SchemaEntitySchemaYes — resolved from entity data nodes
App DefinitionAppDefinitionYes — 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; }
}