Components and applications
This page explains how to model components and applications in the canonical model and how they relate to APIs and generation.
We focus on:
- component definitions and provided endpoints
- optional pseudo-code for documenting behaviour
- applications as compositions of components
- what generators typically do with this information
It builds on the concepts from:
Release baseline
This page documents JoinedWorkz 1.3.80. The Greeting fragments are a conceptual follow-on to the verified Base quickstart; they are not part of that first one-model build. The release Spring Boot output names in section 3.2 were checked against
example-spring-booton release/1.3.80 at commitdf7cabf7f21bon 2026-07-26.
1. Components
A component represents a deployable building block in your system. It groups API endpoints and (optionally) behaviour that belongs together.
Typical examples:
- a backend service
- a microservice or bounded context
- a web API with a set of controllers
In the canonical model, a component:
- provides resources/endpoints from your API model,
- can be linked to implementation artefacts (e.g. Java controllers) via attributes like
basePackageandcontroller, - can optionally contain pseudo-code to document the internal flow of a call for documentation and diagrams.
1.1 Basic component definition
A minimal component definition continuing the Greeting model looks like this:
package com.example.joinedworkz.quickstart.backend
import com.example.joinedworkz.quickstart
platform Base
component GreetingBackend basePackage='com.example.joinedworkz.quickstart.webapp' {
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" { }
}Key points:
- The package
com.example.joinedworkz.quickstart.backenddefines the namespace of the component. - The component is named
GreetingBackend. - The attribute
basePackageprovides package metadata that a Java-generating platform can use. TheBaseplatform selected in this fragment does not itself generate Java controllers. - The
import com.example.joinedworkz.quickstartmakes the API model (resource/hello) available so it can be provided by the component. - The
platform Baseselects theBaseplatform, which among other things includes the OpenAPI and diagram cartridges.
1.2 Provided endpoints
Inside a component you declare which API endpoints it provides. The following CMN model shows a minimal component with one provided endpoint:
component GreetingBackend {
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" { }
}This means:
- The component
GreetingBackendimplements the resource/hellodefined in the imported API model. - The implementation is grouped under the
subPackagegreeting.v1below the component'sbasePackage(platforms use this to compute final package names). GreetingV1Controlleris the logical controller name. Base can use it as an OpenAPI tag; a platform such as SpringBoot can additionally use it for a generated implementation class.
Different platforms may use this information in different ways. For example:
- A Spring Boot platform could generate a
GreetingV1Controllerclass in a package derived frombasePackageandsubPackage. - The OpenAPI cartridge of the
Baseplatform can use thecontrollername as a tag in the generated OpenAPI documents. - Diagram cartridges can show which endpoints belong to which component.
2. Optional pseudo-code for behaviour
Components can optionally contain pseudo-code that documents the behaviour of individual endpoints. This pseudo-code is not executable business logic – it is used for diagrams and documentation.
Extending the previous example:
component GreetingBackend basePackage='com.example.joinedworkz.quickstart.webapp' {
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" {
read {
if 'is morning' {
[[ return 'Good Morning' ]]
} else 'is evening' {
[[ return 'Good Evening' ]]
}
}
}
}Here:
- The
readblock corresponds to thereadendpoint on/hello. - Inside the block you describe the flow as pseudo-code:
- conditions (
if 'is morning',else 'is evening'), - actions (
[[ return 'Good Morning' ]],[[ return 'Good Evening' ]]).
- conditions (
The diagram cartridge of the Base platform can turn this into a sequence-like diagram that visualises the flow of the endpoint. This is useful for:
- documentation,
- discussions with other developers or stakeholders,
- understanding complex flows without reading implementation code.
Important:
- Pseudo-code is optional. Components are still useful without it (for assigning endpoints to components and driving generation).
- The exact pseudo-code syntax is intentionally lightweight and focused on readability. Details belong in the DSL reference and the documentation of the diagram cartridge.
3. Applications
An application is a top-level model element that represents a logical system boundary and composition of components.
Applications are used to:
- get an overview of which components belong to a specific app,
- visualise dependencies between own and external components,
- generate application and component diagrams.
3.1 Basic application definition
Continuing the Greeting follow-on example:
application GreetingApp {
consists of {
GreetingBackend
}
use {
// referenced components
}
}Meaning:
- The application is called
GreetingApp. - It consists of the component
GreetingBackend. These are the components that are part of the application itself. - The optional
usesection can list external components that this application depends on (for example shared or third-party components).
Platforms and cartridges can use this information to:
- draw a component diagram showing the application and its components,
- highlight dependencies between internal and external components.
3.2 OpenAPI scope in release 1.3.80
The Base OpenAPI cartridge generates two complementary kinds of documents:
- A model-scoped document contains the non-abstract resources declared in one CMN model.
- A component-scoped document contains all resource paths that one component provides. This is the important aggregation boundary: a component can provide resources imported from several resource models, and the cartridge combines their provided endpoints into one additional OpenAPI YAML and HTML viewer for that component.
Controller names on the provided resources can contribute operation tags to the component document. For example, the release Spring Boot example produces both:
org.joinedworkz.examples.customer.api.yamlfor the resources in the API model;org.joinedworkz.examples.backend_customerbackend.yamlfor all endpoints provided byCustomerBackend.
Applications do not define this aggregation boundary. They contribute to application/component diagrams, but release 1.3.80 does not generate a separate application-wide OpenAPI YAML or viewer.
4. How components and applications fit in
Putting it all together:
- APIs (
resource/service) define what is exposed. - Components define who provides which part of the API, aggregate all of their provided endpoints into a component OpenAPI document, and map the boundary to implementation artefacts (controllers, packages, etc.).
- Optional pseudo-code inside components documents how calls are handled and enables generation of behavioural diagrams.
- Applications assemble components into logical systems and define the scope for application and component diagrams.
Because components and applications live in the canonical model, you can:
- reuse the same component/application structure across different platforms,
- generate diagrams and, at the model/component scope, OpenAPI and implementation artefacts from a single source of truth,
- evolve your technical stack while keeping the logical architecture stable.
5. Next steps
From here you can:
- read about Profiles & platforms (.profile) to see how platforms configure cartridges (including diagram and API generators) and interpret component/application models;
- explore Modeling with JoinedWorkz Studio for details on how components and applications are visualised and edited in the Studio;
- consult the CMN reference for the exact syntax of component and application definitions and pseudo-code blocks.
