Apex StemA thought-driven Apex development stack

Handler-Usecase Architecture +4 OSS libraries, born from 5 years of refactoring real-world chaos.

The Stack

Four OSS libraries, one architecture. Each can be adopted independently — or together as a unified stack.

Data Access

ApexEloquent

SOQL/DML ORM with a mock-first testing API. Used for unit-testing the Usecase layer.

⚡ SELECT-omission detection via MockEntry

GitHub →
Test Data Factory

ApexBlueprint

Declarative test data factory. Used for integration-testing the Handler layer with real DML.

⚡ Layered topological sort for bulkified DML

GitHub →
Lifecycle Logging

ApexTrace

Usecase lifecycle logging.Trace.of() with start / skip / finish / log.

⚡ TraceFlow-based behavior assertions in tests

GitHub →
Foundation

ApexTools

TriggerHandlerbase class and an HTTP request wrapper with DI support.

⚡ Field-change detection helpers for after-update handlers

GitHub →

Plus a thin Result DTO convention for the LWC ↔ Apex boundary. Start with one library — start anywhere.

Handler-Usecase Architecture

Two layers. One rule per layer. The rest is up to you.

Handler Layer

Integration tests · ApexBlueprint

Entry points — Trigger, Batch, REST, Flow, Schedulable. Absorbs the entry-point ceremony, then hands off to a Usecase.No business logic here.

Usecase Layer

Unit tests · ApexEloquent (mock DB)

Business logic. Only invoke() is public. Constructor takes every dependency —no half-built objects.

Laravel-MVC philosophy

Define the trunk only. Reader / Validator / Mapper emerge from the business — they're never enforced.

Tests map 1-to-1

Handler → integration with real DML. Usecase → unit with mock DB. Same convention everywhere.

AI-friendly by design

The whole convention fits in 30 lines of CLAUDE.md. AI codegen doesn't drift — there's nowhere to drift to.

Get Started

You don't have to rewrite anything. Start with one query — grow from there.

Take the first step

~2 minute read · then continue to the full guide

Five years in the making

The Story

How a five-year-old Salesforce org turned into Apex Stem — one Usecase at a time.

The Challenge

A five-year-old Salesforce org, with trigger-on-trigger debt and assertions that didn't really assert.

fflib felt too heavy for a small team. Raw Apex felt too unstructured for the long run.

I wanted something AI coding assistants could actually follow — a convention small enough to fit in CLAUDE.md.

What emerged

Rebuilt incrementally — one Usecase, one mockable query at a time.

ApexEloquent came first. ApexBlueprint, ApexTrace, and ApexTools followed as the needs surfaced.

The stack you see today is what I'd want if I had to start the refactor over.