3. Add a second loader by hand
In this chapter you scaffold the web shop’s loader and wire it into the System by editing the topology declaration yourself.
Scaffold the loader
Section titled “Scaffold the loader”From the scratch directory root — the same command as chapter 1, with the new names:
intropy int create loader -n WebLoader -o web-loader --template-version v0.4.1 \ -s organization=Fluxia -s topic=order-notifications -s contract=Order -s empty=falsefetching integrio-intropy/intropy-templates@v0.4.1created web-loader from integrio-intropy/intropy-templates@v0.4.1 (template loader)dependency Contracts already scaffolded from shared-contracts — skippedThe topic and contract are the same values as before: the new loader joins the existing system contract instead of defining anything new.
Wire it into the System
Section titled “Wire it into the System”You could rerun sys create --force and let it regenerate the host from the records. This chapter does it by hand instead, for two reasons: regeneration overwrites any local edits the host has accumulated, and the edit teaches you what the declaration actually is. Three files, one addition each.
First the Port — the loader’s named interface to the web shop:
public static class Ports{ public static readonly PortRef ErpExtractorSource = PortRef.Define("erp-extractor-source");
public static readonly PortRef WebLoaderDestination = PortRef.Define("web-loader-destination");
public static readonly PortRef WmsLoaderDestination = PortRef.Define("wms-loader-destination");}Then the Component, in the system definition. The AddLoader name must match the scaffolded directory (web-loader); the host locates the project by that convention:
public void Define(SystemBuilder builder){ builder.AddExtractor("erp-extractor") .From(Ports.ErpExtractorSource) .Publishes(Topics.OrderNotifications) .Uses(Services.Idempotency) .Uses(Services.BusinessIncidents); builder.AddLoader("web-loader") .Subscribes(Topics.OrderNotifications) .To(Ports.WebLoaderDestination) .Uses(Services.Idempotency) .Uses(Services.BusinessIncidents); builder.AddLoader("wms-loader") .Subscribes(Topics.OrderNotifications) .To(Ports.WmsLoaderDestination) .Uses(Services.Idempotency) .Uses(Services.BusinessIncidents);}Both loaders call .Subscribes(Topics.OrderNotifications) — the same TopicRef, defined once in Topics.cs. That single shared reference is the entire fan-out; there is no routing table anywhere.
Last, the development resolution, so the new Port is a folder when the host runs locally:
public void Define(DevelopmentBuilder development){ development.Mock(Services.Idempotency).FromOpenApi("mocks/idempotency-service.openapi.yaml"); development.Mock(Services.BusinessIncidents).FromOpenApi("mocks/business-incident-service.openapi.yaml"); development.Files(Ports.ErpExtractorSource).RootPath("./test/erp-extractor-source"); development.Files(Ports.WebLoaderDestination).RootPath("./test/web-loader-destination"); development.Files(Ports.WmsLoaderDestination).RootPath("./test/wms-loader-destination");}Nothing else changes. The host’s project file references no Component projects, and no other file names the loaders; the declaration you just edited is the System.
Check it
Section titled “Check it”The host validates its own topology without starting anything:
cd order-notificationsdotnet run -- checkok: 'order-notifications' is valid (3 components).If a name doesn’t line up — an AddLoader that matches no scaffolded directory, a Port declared but never resolved — this is where it surfaces, not at runtime.