A proof of concept should answer architectural questions, not become an infrastructure project of its own.

Yet, as architects, we often spend more time preparing the environment than challenging the design. We create application skeletons, resolve dependencies, assemble containers, configure a broker, provision a database, and connect everything. By the time a message finally reaches its destination, a large part of the available time has already disappeared.

The demonstration works. The difficult questions may still be unanswered.

Apache Camel JBang interests me because it can reduce that preparation cost. Combined with local infrastructure services, visual route design, and runtime inspection, it offers a short path from an integration diagram to something we can execute and investigate.

The value comes from what we do with the time saved: testing assumptions, introducing failures, and collecting evidence for a decision.

Start with the Decision the PoC Must Support

Consider a familiar flow: a REST API receives data, a transformation prepares an event, Kafka carries it to a processing service, and the result is stored in a database.

The diagram is easy to draw. Its arrows leave plenty of room for interpretation.

When does the API consider a request accepted? After validation? After the broker acknowledges the event? Only after the database transaction commits? What happens when the consumer crashes between writing a row and recording its progress? Can two events for the same business entity be processed out of order?

Those questions determine the behaviour that callers and operators will experience. A successful request on a quiet laptop cannot answer all of them.

Before creating the environment, I would write down one concrete decision and the evidence needed to make it. For example:

Can we acknowledge a request after durable publication, process it asynchronously, and recover from a consumer interruption without creating duplicate business records?

That gives the experiment a boundary. It identifies which parts must be real, which failures matter, and what success means. It also makes an uncomfortable result useful: if the proposed design cannot meet the requirement, the PoC has done its job.

Why Camel Fits This Kind of Architecture Work

Apache Camel provides an integration framework built around Enterprise Integration Patterns. Routing, filtering, transformation, enrichment, and related patterns have explicit representations, while components connect those routes to external systems. The Camel pattern catalogue describes the available building blocks.

For an architect, that creates a useful link between design vocabulary and executable behaviour. A content-based routing decision can be represented in the integration itself. An enrichment step becomes a visible dependency that can be timed, interrupted, and discussed.

It also helps expose decisions that a diagram can hide. A retry needs a limit and a destination when attempts are exhausted. A transformation needs a policy for missing fields. A route to a database needs an answer about transaction boundaries.

Camel does not choose those policies for the team. It gives us a practical place to express and test them.

Run the Route Before Building the Application Around It

Camel JBang, now documented as the Camel CLI, can run routes written in YAML, Java, or XML without first creating a Maven application. It resolves the required dependencies for the integration. The official documentation also makes an important distinction: the CLI is a development tool, not a production application management platform. See the Camel CLI overview .

With the tool installed and a route file prepared, the basic workflow is small:

camel run integration.camel.yaml

During development, the documented reload mode supports a shorter edit-and-run cycle:

camel run integration.camel.yaml --dev

The running integrations guide explains the execution options. These commands illustrate the workflow; they assume an authored route and its configuration. They are not a complete implementation of the REST-to-database example.

There are still prerequisites: a compatible Java environment, the CLI installation, access to dependencies, and a container engine when local services are involved. Removing the initial application skeleton does not remove the runtime or its dependencies.

What changes is the order of the work. We can first examine the integration behaviour, then invest in the application packaging once the design has earned that investment.

Bring the Infrastructure into the Same Development Loop

The route needs something to talk to. Kafka, a database, or a messaging service should not each require a separate miniature platform project just to begin an experiment.

Camel’s development infrastructure commands let us discover and start supported local services:

camel infra list
camel infra run kafka
camel infra get kafka

The available services and implementations depend on the installed version. Camel uses its container-based test infrastructure, built around Testcontainers, to support this workflow. The development services documentation describes service selection, lifecycle commands, and the returned connection information.

That last detail matters. Starting a broker does not mean every route is automatically configured correctly. Use the connection details reported by the service, including the actual mapped port, in the integration configuration. Avoid assuming that Kafka will always be reachable at a familiar fixed port.

The same workflow covers other supported services, including Artemis. Apache Camel’s end-to-end prototyping article shows how the infrastructure commands fit into an evolving integration experiment.

I would keep the local environment deliberately small. If the decision concerns Kafka delivery and database persistence, use real instances of both. If an unrelated downstream API adds no useful evidence, a controlled stub may be enough. Record that boundary so nobody later mistakes the stubbed behaviour for a validated dependency.

A local container proves something about the integration under those conditions. It does not establish the behaviour of a production cluster during a network partition, replica failure, or sustained peak load.

Give Design and Observation Different Jobs

Kaoto provides a visual designer for Apache Camel integrations. It makes the structure of a route easier to explore and edit, with the underlying integration definition remaining part of the development workflow. Its designer documentation explains the available capabilities.

That is useful in an architecture discussion. A reviewer can follow where data enters, where it changes shape, and which branch handles a particular condition. The team can discuss the flow while still reviewing and versioning the actual route definition.

Hawtio serves a different purpose. It provides runtime inspection and management capabilities, including visibility into Camel routes and their execution. Camel documents this integration in its management guide .

For the PoC, I would use that visibility to investigate a specific question: which step is waiting, where are failures accumulating, or how does processing change when a dependency slows down?

Route-level visibility should be paired with evidence from the rest of the flow. Check broker progress, database state, and correlation identifiers. A healthy-looking route is not proof that the intended business effect occurred exactly once.

Together, these tools support a useful cycle: design, provision, run, observe, iterate. Each iteration should refine an assumption or produce a result worth keeping.

Spend the Saved Time on Failure Behaviour

The first successful message establishes that the components can communicate. The next experiments should test whether the architecture behaves as intended when that communication becomes unreliable.

For the example flow, I would start with the following matrix. These are proposed acceptance criteria, not results from a benchmark.

Architectural questionExperimentEvidence to collect
What does API acceptance promise?Interrupt publication and inspect the response.Response status, broker acknowledgement, and the caller’s retry behaviour.
Are invalid inputs contained?Submit malformed data and a structurally valid but unsupported business value.Explicit rejection or quarantine, with no unintended database change.
Can processing recover safely?Stop the consumer after a database commit but before its progress is recorded.Replay behaviour and the final number of business records.
Is ordering required and preserved?Send related events concurrently using the intended partitioning strategy.The observed processing order and resulting entity state.
What happens under backpressure?Slow the database while maintaining incoming traffic.Lag, resource consumption, timeouts, and recovery after normal service resumes.
Can operators resolve a failed event?Exhaust retries for a deliberately unprocessable message.A traceable failure destination and a controlled recovery procedure.

The consumer interruption is especially revealing. A database write and a Kafka offset commit are separate actions unless the design deliberately coordinates them. If the write succeeds and the process stops before recording progress, the event may be read again.

The experiment should show whether that replay produces a duplicate business effect. One possible design uses a stable event identifier and a database uniqueness constraint, with duplicate detection and the business update coordinated in the same transaction. The right implementation depends on the business operation; simply labelling the route “idempotent” is not sufficient evidence.

Likewise, a retry policy deserves more than a successful second attempt. What happens when a dependency remains unavailable? Does the route retry indefinitely, consume resources, block unrelated work, or eventually hand the event to a recovery path?

These are architecture questions because the answers shape service contracts, support procedures, and the cost of operating the system.

Make the Experiment Repeatable

A PoC that works only on its author’s machine is difficult to use as decision evidence. Another engineer should be able to reproduce the important observations without reconstructing the environment from a chat history.

I would keep the routes, synthetic input messages, expected outcomes, and a short runbook together. Record the Java and Camel versions, the service implementations and container versions, and the configuration required to connect them. Document how to reset the environment between experiments, particularly when offsets or database rows survive a restart.

The runbook should distinguish the initial happy path from the failure tests. Each test needs an initial state, an action, and an observable result. “Restart the consumer and inspect the database for one record with this event identifier” is stronger than “check that recovery works.”

Use synthetic data and configuration supplied outside the route for secrets. Keep development management interfaces local. The goal is a small, reproducible experiment that can be shared without carrying production credentials or sensitive payloads with it.

Export the Validated Integration, Then Prepare It for Production

Once the experiment supports the decision, the route does not have to become disposable work. Camel provides export options for application runtimes, including Quarkus and Spring Boot. For example, an export to a separate Quarkus project directory follows this form:

camel export integration.camel.yaml --runtime=quarkus --directory=../integration-quarkus

Spring Boot is another supported runtime choice. The project export documentation describes the options and generated project structure.

Exporting provides a starting point for application development. It does not establish production readiness. Repeat the important tests in the selected runtime, particularly where component support, configuration, or lifecycle behaviour differs.

The production work then has a clearer purpose: authentication and authorization for the API, TLS for service connections, managed secrets, durable recovery state, bounded retries, health checks, telemetry, dependency maintenance, and an accountable release process. Kubernetes adds its own deployment and operating concerns, including resource limits, network policy, shutdown behaviour, and configuration management.

If one of those concerns is itself the architectural uncertainty, bring it into the PoC earlier. For example, an experiment about shutdown safety needs to exercise the intended termination behaviour. The boundary should follow the question, not a rule that all operational work must wait until later.

Finish with an Architectural Answer

The deliverable I want from a PoC is a decision supported by evidence: which assumption held, under what conditions, which failure modes were exercised, and what remains unverified.

Keep that conclusion alongside the route and the test inputs. A short architecture decision record can capture the chosen approach, alternatives, trade-offs, and reasons to revisit it. An unsuccessful experiment can be just as valuable if it prevents a fragile design from becoming a production commitment.

Camel JBang is useful here because it reduces the distance between describing an integration and examining its behaviour. Kaoto helps us work with its structure. Local development services make the dependencies accessible. Hawtio helps us investigate what the running route is doing.

The tooling creates room for better questions. The architect still has to ask them.

Sometimes the fastest way to validate an architecture is simply to make it run—and then deliberately test the assumptions behind every arrow.