Skip to content

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-boot on release/1.3.80 at commit df7cabf7f21b on 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 basePackage and controller,
  • 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:

cmn
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.backend defines the namespace of the component.
  • The component is named GreetingBackend.
  • The attribute basePackage provides package metadata that a Java-generating platform can use. The Base platform selected in this fragment does not itself generate Java controllers.
  • The import com.example.joinedworkz.quickstart makes the API model (resource /hello) available so it can be provided by the component.
  • The platform Base selects the Base platform, 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:

cmn
component GreetingBackend {
    provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" { }
}

This means:

  • The component GreetingBackend implements the resource /hello defined in the imported API model.
  • The implementation is grouped under the subPackage greeting.v1 below the component's basePackage (platforms use this to compute final package names).
  • GreetingV1Controller is 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 GreetingV1Controller class in a package derived from basePackage and subPackage.
  • The OpenAPI cartridge of the Base platform can use the controller name 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:

cmn
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 read block corresponds to the read endpoint 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' ]]).

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:

cmn
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 use section 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.yaml for the resources in the API model;
  • org.joinedworkz.examples.backend_customerbackend.yaml for all endpoints provided by CustomerBackend.

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.