Backend Onboarding
You are about to write your first Kotlin change in an Arda backend repository. This page is the reading order. It is short on purpose: eight pages, roughly half a day, and it is the difference between a first pull request that gets reviewed for its logic and one that gets reviewed for its shape.
Set up your environment first — Development Environment Setup and Development Workflows cover installing prerequisites, cloning the workspace, 1Password secrets, and the build/test commands. This page picks up where those leave off: not how to run the code, but how the code is expected to look.
Read these, in this order
Section titled “Read these, in this order”Each entry says why it is where it is. Skipping ahead mostly works, except for the first two.
1. The shape of a module
Section titled “1. The shape of a module”Read this first. Almost every backend change happens inside a module, and every module has the same four layers with the same responsibilities. Everything below is a detail inside this shape, and it is much harder to place a detail when you do not have the shape.
2. Where each file goes
Section titled “2. Where each file goes”The package layout is not filing; it is enforced. Packages form a directed acyclic graph at every aggregation level, so a type in the wrong package is a cycle waiting to happen rather than a cosmetic problem. This page also covers the common.lib.* staging area — where a type lives when it is on its way to common-module but not there yet.
3. How a module starts
Section titled “3. How a module starts”One function per module, a fixed signature, and a defined order of responsibilities: resolve configuration, construct services, register routes and observers, return the service handle. When you need to add a collaborator, this page says where it is built.
4. How a REST surface is declared
Section titled “4. How a REST surface is declared”Never raw Ktor routing in a module. Routes are declared through the endpoint DSL, and the DSL is not decoration — it is what puts a route in the secured scope, in the generated OpenAPI spec, and in the startup collision check. A hand-mounted route silently has none of those. The page’s decision rubric tells you whether your surface wants DataAuthorityEndpoint or the lightweight serviceDefinition DSL.
5. How errors leave the system
Section titled “5. How errors leave the system”URL shape, required headers, and the error contract. The rule that surprises people: a handler never builds an error response. It returns Result and lets the DSL throw, or it throws an AppError directly. A central StatusPages boundary turns that into the response — attaching the correlation id, setting Retry-After on transient failures, capturing to Sentry, and choosing the log severity. Every one of those is lost by a handler that responds on its own.
6. How the code itself is written
Section titled “6. How the code itself is written”The binding language conventions. Start with the ten rules on that page, then follow its reading order — Functions and Result Handling and Nullability and Return Types are the two that change how you write every method.
7. How anything with a lifecycle is stored
Section titled “7. How anything with a lifecycle is stored”Universe Design and Persistence and Transactions
If an entity is created, updated, soft-deleted, or otherwise evolves, it belongs in a bitemporal Universe — you get identity, version history, audit columns, and tenant isolation without writing them. A plain Exposed table is for immutable append-only records only. Anything else, ask before you build it.
8. How it is tested
Section titled “8. How it is tested”Kotest FunSpec, isolation mode, what a unit test is expected to cover, and where integration tests draw the line.
Two things to know before your first review
Section titled “Two things to know before your first review”These pages are binding, not advisory. If a design document you are implementing conflicts with one of them, the pages win and the design needs amending — say so before you implement, rather than implementing the design and discovering the conflict in code review. That has happened, it cost a rewrite, and it was not the implementer’s fault.
If you think a page is wrong, say that too. Some are. Conventions here are written down after the fact by whoever hit the problem, which means they are occasionally stale, occasionally contradictory, and occasionally just wrong. Two of the pages in this list were corrected because a new joiner followed them and the result did not match what reviewers expected. Reporting that is a contribution, not a complaint.
Bring a module to current conventions when you touch it
Section titled “Bring a module to current conventions when you touch it”You will find modules that do not match these pages — older package layouts, older idioms. The rule is opportunistic compliance: when a project touches a module, bring that module to current conventions as part of the work. Do not raise backward-correction tickets, and do not schedule migrations. Fixing it while you are already in the file is nearly free; scheduling it is not.
Related
Section titled “Related”- Implementation Overview — the full index of implementation guides.
- Design Pattern Index — every pattern, with summaries.
- Working with AI Agent Assistants — how agents are used here, and what they are given as context.
- Worktree Conventions — branch naming and the worktree layout used for project work.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved