Onboarding

Welcome to the Team 🚀

This document guides you step by step through the key technologies and tools of our tech stack. The order is intentional: first you learn the domain fundamentals, then the technical platform, and finally our programming language and framework.

Fundamentals: BPMN & DMN

Before diving into the tools, it's important to understand the underlying standards. BPMN and DMN are the language we use to describe business processes and decision logic.

What is BPMN?

Business Process Model and Notation (BPMN) is a graphical standard for modeling business processes. It defines a unified notation that is understood by both domain experts and developers.

What is DMN?

Decision Model and Notation (DMN) complements BPMN with the modeling of decision logic – typically in the form of Decision Tables.

Installation & Tools (Mac)

# Option 1: Camunda Modeler (recommended – supports BPMN & DMN)
brew install --cask camunda-modeler

Or download manually: https://camunda.com/download/modeler/

Further Reading


Process Engines – Overview

Orchescala is engine-agnostic – it supports multiple BPMN engines through a unified abstraction. For onboarding, it's important to understand the differences.

Supported Engines

Engine Description Status Architecture
Camunda 7 The classic Camunda platform Production Embedded or standalone engine, REST API
Camunda 8 Zeebe-based cloud-native engine Proof of Concept Distributed engine, gRPC + REST API
Operaton Open-source fork of Camunda 7 Proof of Concept Same as Camunda 7 (compatible REST API)

Camunda 7

The classic Camunda platform – battle-tested for years and our production standard.

Core Concepts:

Links:

Camunda 8

The next generation – cloud-native, based on Zeebe as a distributed workflow engine.

Key Differences from Camunda 7:

Aspect Camunda 7 Camunda 8
Engine Embedded / Standalone Zeebe (distributed engine)
Communication REST API gRPC + REST API
Variables Java objects + JSON JSON only
Expressions JUEL FEEL
Scripts Inline Groovy/JS FEEL or Workers
Tasklist Classic Tasklist New Tasklist (React)

Links:

Operaton

Operaton is the open-source fork of Camunda 7, maintained by the community. The REST API is compatible with Camunda 7, allowing Orchescala to use the same client.

Why Operaton?

Links:

Which Engine to Use?

Use Case Recommended Engine
Production processes (established) Camunda 7
New projects / cloud-native Camunda 8
Open source without license costs Operaton

Scala – User

As a user of Orchescala, you need to be able to read and write Scala to describe processes and domain objects – without diving deep into the infrastructure libraries. These two concepts and three domain libraries are sufficient for that.

Setup (Mac)

# Install Coursier (Scala Toolchain Manager)
brew install coursier/formulas/coursier

# Set up Scala toolchain (installs Java, Scala, sbt, scala-cli, etc.)
cs setup

# Install specific Java version (Temurin 21 LTS recommended)
cs java --jvm temurin:21 --setup

# Verify everything is installed
java -version
scala -version
sbt --version
💡 cs setup automatically installs a current JVM, Scala, sbt, and other useful tools. Use cs java --jvm temurin:21 --setup to set a specific JVM as the default.

If Coursier doesn't work – Homebrew fallback:

brew install --cask temurin@21
brew install scala sbt
# IntelliJ IDEA + Scala Plugin (recommended IDE)
brew install --cask intellij-idea

Basics

The fundamentals of Scala – type system, collections, pattern matching, etc.

Key Concepts:

Resources:

DSLs (Domain Specific Languages)

Orchescala provides its own DSL for describing processes and workers. Scala is excellent for this thanks to its flexible syntax.

Concepts:

Resources:

Iron

Iron is a Scala 3 library for Refined Types – types with embedded constraints that enable compile-time validation.

// Example: Type-safe amount – never negative
import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.numeric.*

type PositiveAmount = Double :| Positive
val amount: PositiveAmount = 100.0.refineUnsafe

Resources:

Tapir

Tapir enables type-safe HTTP API definitions in Scala. Endpoints are described as values and can be interpreted as server, client, or OpenAPI documentation.

// Define endpoint
val bookListing: PublicEndpoint[Unit, String, List[Book], Any] =
  endpoint.get
    .in("books" / "list" / "all")
    .errorOut(stringBody)
    .out(jsonBody[List[Book]])

Resources:

Circe

Circe is the standard library for JSON encoding/decoding in our Scala stack.

import io.circe.*
import io.circe.generic.auto.*
import io.circe.syntax.*

case class Book(title: String, year: Int)

// Encoding: Scala → JSON
val json: Json = Book("Clean Code", 2008).asJson

// Decoding: JSON → Scala
val result: Either[Error, Book] = decode[Book]("""{"title":"Clean Code","year":2008}""")

Resources:


Orchescala – User

As a user, you use Orchescala to describe processes, domain objects, and workers – using the provided DSL. You don't need a deep understanding of the underlying libraries (ZIO, Tapir, etc.).

What You Do as a User

See Orchescala - Introduction


Setup the Orchescala Projects

This section guides you through cloning all necessary repositories to start working on your Orchescala projects.

Git SSH Key Setup (Mac)

If you already have access rights to your company's Git provider (e.g. https://code.mycompany.com/repos), follow these steps to configure SSH-based access.

1. Generate an SSH key pair

# Generate a new Ed25519 key (recommended)
ssh-keygen -t ed25519 -C "your.email@company.com"

# Follow the prompts – choose a secure passphrase
# Default location: ~/.ssh/id_ed25519

2. Enable SSH passphrase caching via macOS Keychain

Add the following to your ~/.ssh/config (create the file if it doesn't exist):

Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519

Then add the key to the agent:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519
💡 With UseKeychain yes, macOS stores the passphrase in the system Keychain – you only need to enter it once after each reboot.

3. Add the public key to your Git provider

# Copy the public key to your clipboard
pbcopy < ~/.ssh/id_ed25519.pub

Then paste it in your Git provider's SSH key settings (e.g. GitLab → Preferences → SSH Keys).

4. Verify the connection

# Replace with your Git provider's hostname
ssh -T git@code.mycompany.com

Project Checkout

This clones all required projects into your local projects folder.

dev-mycompany
├── mycompany-orchescala
├── projects
    ├── mycompany-commons
    ├── mycompany-services
    └── mycompany-cards

1. Navigate to your development folder and download the checkout script:

cd ~/dev-mycompany   # or your preferred workspace directory

Download project-checkout.scala and put it in your dev-mycompany folder.

2. Adjust the variables in the script to match your company's project layout:

3. Make the script executable and run it:

chmod +x project-checkout.scala
./project-checkout.scala

Backend Development

Our backend is built on modern principles of distributed systems and cloud-native development.

Key Concepts


Open API

We use OpenAPI (formerly Swagger) for describing and documenting our REST APIs. API-first is our standard approach.

Concepts

Tools (Mac)

# Swagger UI locally (via Docker)
docker run -p 8081:8080 swaggerapi/swagger-ui

# OpenAPI Generator CLI
brew install openapi-generator

# Example: Generate Scala client
openapi-generator generate -i openapi.yaml -g scala-sttp -o ./client

Further Reading


Functional Programming

Functional programming (FP) is a fundamental paradigm in our stack – especially in Scala. It's worth understanding the concepts before diving deep into the developer libraries.

Core Concepts

Concept Meaning
Pure Functions No side effects, same input → same output
Immutability Data is not modified, but recreated
Higher-Order Functions Functions as parameters or return values
Typeclasses Abstraction over types (Functor, Monad, etc.)
Monads Structured chaining of computations (Option, Either, IO)
Referential Transparency Expression can be replaced by its result

Groovy

Groovy is primarily used for Camunda scripts and build scripts (Gradle). It is a dynamic JVM language with Scala/Java interoperability.

Installation (Mac)

# Via Homebrew
brew install groovy

# Check version
groovy --version

# Interactive shell
groovysh

Typical Usage in the Camunda Context

// Example: Set process variable in a Script Task
execution.setVariable("approved", true)

// Read variables
def amount = execution.getVariable("amount") as Double

// Decision
if (amount > 10000) {
  execution.setVariable("requiresApproval", true)
}

Further Reading


Scala – Developer

As a developer of the Orchescala framework, you need next to the basic Scala 3 stuff from above, an understanding of the Effect libraries like ZIO and Scala 3 Macros.

Additional Setup (Mac)

# Scala CLI (already installed via `cs setup`, alternatively via Homebrew)
brew install Virtuslab/scala-cli/scala-cli

# List available JVMs
cs java --available

# Switch between JVM versions
cs java --jvm temurin:21 --setup   # Temurin 21 as default
cs java --jvm temurin:17 --setup   # Temurin 17 as default

Scala 3 Macros

Scala 3 Macros enable compile-time metaprogramming in Scala – code that inspects or generates other code during compilation, before the program ever runs.

This is fundamentally different from runtime reflection: errors are caught at compile-time, there is no runtime overhead, and the generated code is fully type-safe.

Key Macro Mechanisms:

Mechanism Purpose
inline Forces inlining at call-site; prerequisite for most macros
Expr[T] Typed representation of a code expression
Quotes The compile-time context needed to inspect/build expressions
scala.quoted.* The standard macro API

How We Use It in Orchescala:

The most visible use case is automatic variable name extraction in Simulations. Instead of specifying field names as strings (fragile, not refactor-safe), we extract them directly from the variable reference at compile-time:

// Without macros – fragile string, breaks silently on rename:
variable("amount", myProcess.amount)

// With macros – name is extracted from the val reference itself:
variable(myProcess.amount)  // name "amount" extracted at compile-time

Under the hood, a macro inspects the Expr of the argument, reads the symbol name from the AST, and injects it as a compile-time constant – no strings, no runtime cost.

Inline + Macro pattern (simplified):

import scala.quoted.*

inline def nameOf[T](inline value: T): String =
  ${ nameOfImpl('value) }

def nameOfImpl[T](expr: Expr[T])(using Quotes): Expr[String] =
  import quotes.reflect.*
  val name = expr.asTerm match
    case Select(_, name) => name
    case _               => report.errorAndAbort("Expected a field reference")
  Expr(name)
💡 You don't need to write macros as an Orchescala user – but understanding the concept helps you make sense of why the DSL can "magically" know variable names.

Resources:

ZIO

ZIO is our primary framework for asynchronous and functional effects. It replaces Future and enables type-safe, composable effect management.

# Add to build.sbt
libraryDependencies += "dev.zio" %% "zio" % "2.x.x"

Core Concepts:

Resources:


Orchescala – Developer

As a developer of Orchescala itself, you work on the framework core: designing the DSL, extending library integrations, and maintaining the infrastructure.

What You Do as a Developer

Architecture Overview

Getting Started

⚠️ Internal framework: Documentation and source code are available in the internal Git repository.
  1. Request repository access from the team lead
  2. Read the architecture documentation and Developer Guide (internal Confluence)
  3. Build the framework module locally and run tests
  4. Implement your first framework contribution via pair programming

Questions? Don't hesitate to ask the team – nobody expects you to learn everything at once! 🙌