Skip to content
Tutorial1/5

1. Scaffold the component

In this chapter you render the transactional template with empty step bodies, look at what the CLI generated, and confirm it compiles, including the two tests that are supposed to fail today.

Create the component directory and render the template into it:

Terminal window
mkdir order-sync && cd order-sync
intropy int create transactional -n OrderSync -s organization=Fluxia -s empty=true -o . --no-input
fetching integrio-intropy/intropy-templates@v0.4.1
created . from integrio-intropy/intropy-templates@v0.4.1 (template transactional)

The directory name is not cosmetic. -n OrderSync names the .NET project; its kebab-case form order-sync becomes the component name and Dapr app-id, and the system host you create in chapter 4 locates the project by a folder convention: a sibling directory named exactly like the component. mkdir order-sync + -o . satisfies that convention up front.

Use your own organization in place of Fluxia: it becomes the ServiceNamespace on every telemetry signal and the source URN on every business incident. empty=true strips the sample business logic and the platform-service wiring, leaving both for you. To see a template’s parameters before rendering, ask the CLI:

Terminal window
intropy template show transactional
Transactional Integration (transactional) @ integrio-intropy/intropy-templates@v0.4.1
.NET job that polls a local source folder, publishes via in-memory Dapr pub/sub,
and writes the transformed result to a local destination folder.
Parameters:
* name — Project name [string]
* organization — Organization [string]
empty — Empty bodies [boolean] (default: false)
(* = required)

intropy int create writes a single .NET job with two pipelines and their tests:

order-sync/
├── OrderSync.slnx
├── Taskfile.yml # task build / test:unit / test:integration
├── Dockerfile # .NET 10 chiseled runtime, app only
├── AGENTS.md # project facts for AI assistants
├── .intropy/scaffold.json # what was rendered, from which release
├── src/
│ ├── Program.cs # four lines: build DI, resolve the runner, run
│ ├── Configuration/
│ │ ├── Composition.cs # every service registration, shared with the tests
│ │ └── Constants.cs # component, queue, binding, and context-key names
│ ├── Model/ # In, Line, Out — empty shells until chapters 2–3
│ ├── Receive/ # Receiver → Enqueuer → Completer, implemented
│ └── Send/ # Deserializer → … → Sender, bodies throw
└── test/
├── OrderSync.Test.Unit/ # one stub per send step, real Receiver tests
└── OrderSync.Test.Integration/ # both pipelines against faked edges

Three things are worth reading before you write any code:

  • src/Receive/ is fully implemented. It lists files in the source folder, publishes each one to the component’s internal queue (internal-order-sync, topic hop; the names live in Constants.cs), and deletes the source file. Transport is generic; the template doesn’t make you rewrite it.
  • Every class in src/Send/ compiles but throws NotImplementedException, and the records under src/Model/ are empty shells. The job would start under its host right now; it just can’t process a message yet.
  • .intropy/scaffold.json is the component’s birth certificate: template, release, and the values it was rendered with. It’s meant to be committed: chapter 4’s intropy sys create reads these records to assemble the System.

All registrations live in src/Configuration/Composition.cs rather than Program.cs, so the integration tests can build the exact production DI graph with only the edges faked.

Confirm the scaffold compiles and run the whole test suite:

Terminal window
dotnet build
dotnet test

The build succeeds with one expected warning:

src/Send/Sender.cs(10,34): warning CS9113: Parameter 'fileAdapter' is unread.
Build succeeded.
1 Warning(s)
0 Error(s)

The stubbed Sender never touches its injected file adapter; the warning is the seam waiting for chapter 4’s implementation, and it disappears there. The test run is more interesting: it does not pass:

Passed! - Failed: 0, Passed: 2, Skipped: 1, Total: 3 - OrderSync.Test.Unit.dll
[xUnit.net] OrderSync.Test.Integration.SendPipelineIntegrationTests.Execute_WithValidMessage_WritesOutput [FAIL]
[xUnit.net] OrderSync.Test.Integration.ReceivePipelineIntegrationTests.Execute_WithUnreadableFile_RoutesIncidentKeyedOnFileName [FAIL]
Failed! - Failed: 2, Passed: 6, Skipped: 0, Total: 8 - OrderSync.Test.Integration.dll

This is the scaffold working as intended. The unit project holds two green Receiver tests (that step ships implemented), one skipped placeholder, and comment-only stubs you’ll fill as you implement each step. The integration project pins how both pipelines must behave, against the real DI graph with faked edges, and two of those pins can’t hold yet:

  • Execute_WithValidMessage_WritesOutput demands that a valid order comes out the other end of the send pipeline. Every step throws today. It flips green in chapter 4, when the last step lands, with no test edits needed.
  • Execute_WithUnreadableFile_RoutesIncidentKeyedOnFileName demands that a broken source file is routed as a business incident. empty=true scaffolds no incident wiring, so the failure surfaces as a plain result instead. It flips green in chapter 5, when you add .WithBusinessIncidents(...).

The two red tests are the tutorial’s finish line, written down before you start. The six green ones prove the transport contract already holds: files are enqueued and deleted, a dead broker leaves the file for the next run, a failed delete keeps the file for redelivery.