Sign-in, end to end
On Node: register, sign in, sessions in an httpOnly cookie, password reset. On Java: OAuth2 with Keycloak, the API as a resource server, and a realm with a demo user.
[ v1.0.0 ] Hexagonal projects, generated
forja generates a TypeScript monorepo with Next.js and Expo, or a
Spring Boot or Quarkus API with a Next.js web app. The hexagonal
architecture is in place, sign-in works, and every test is green on the
first run. Then forja add grows it one use case at a time,
inside the rules.
npm install -g @rsaglobaltech/forja
forja init shop # the wizard
forja add usecase orders/PlaceOrder
Plain code you ownMITEvery path generated, installed, tested, built and driven in a browser before a release
A starter template gets copied once. A month later the first shortcut lands: a page that queries the database, a use case that imports React. Nothing fails, so nothing stops it.
forja generates the rules with the code. On Java, ArchUnit fails the
build when the domain reaches for Spring or one module uses another's
infrastructure. On Node, forja doctor catches a UI import
in the core. And forja add writes each new use case, entity
and port where those rules expect it, already wired and already tested.
What you get
shop/
├── apps/
│ ├── web/ Next.js 16: pages, server actions, auth API
│ └── mobile/ Expo SDK 57 + NativeWind
├── packages/
│ ├── core/ the hexagon, shared by both apps
│ │ └── src/
│ │ ├── domain/ User, Email, Password
│ │ ├── application/ Register, Login, Logout…
│ │ ├── ports/ IUserRepository, IMailer…
│ │ └── infrastructure/ Drizzle, bcrypt, container.ts
│ └── shared/ design tokens
├── docker-compose.yml PostgreSQL
└── forja.config.json
shop/
├── apps/
│ ├── api/ Spring Boot 4 (or Quarkus 3)
│ │ └── src/main/java/com/shop/
│ │ ├── tasks/
│ │ │ ├── domain/ Task, TaskTitle
│ │ │ ├── application/ CreateTask… + port/
│ │ │ └── infrastructure/ web, persistence, config
│ │ └── shared/
│ └── web/ Next.js 16, signs in with Keycloak
├── infra/keycloak/ a realm with demo / demo
├── docker-compose.yml PostgreSQL + Keycloak
└── forja.config.json
The day after
Run forja add anywhere inside the project.
It reads forja.config.json, writes the class and its test,
wires it into the composition root, and overwrites nothing. With
Specgate in the project, the requirement comes with it.
$ forja add usecase orders/PlaceOrder
┌ forja add usecase
◆ created packages/core/src/application/orders/PlaceOrderUseCase.ts
◆ created packages/core/tests/unit/orders/PlaceOrderUseCase.test.ts
● updated packages/core/src/index.ts
● updated packages/core/src/infrastructure/config/container.ts
◇ REQ-003 · Place order
│ scenario to write: features/place-order.feature
└ Next: write the scenario, make the test prove it (npm test),
then npx specgate done REQ-003
$ forja doctor
┌ forja doctor · shop
◆ Node.js v24.14.0
◆ Docker engine 29.5.3
▲ env (root) no .env yet: the defaults in the code apply
│ cp .env.example .env
◆ React one version everywhere (19.2.3)
■ core imports packages/core/src/domain/entities/Order.ts:31 imports react
│ Move that code to apps/* or infrastructure/, and reach it through a port
└ 1 to fix, 1 to look at
On the first run
On Node: register, sign in, sessions in an httpOnly cookie, password reset. On Java: OAuth2 with Keycloak, the API as a resource server, and a realm with a demo user.
vitest for the core's use cases; JUnit, Testcontainers and a real
PostgreSQL for the API. Add --tests e2e-web and
Playwright drives the sign-in in a browser.
ArchUnit on the API: a pure domain, no framework in the application,
ports as interfaces, no cycles. forja doctor keeps the
Node core free of UI imports.
Next.js and Expo import the same packages/core. One React
version for both, the one Expo pins, so hooks never meet two copies.
With the specgate extra, the project starts with a brief
to fill in and a gate that runs your tests. Each use case you add
names its requirement.
What forja writes is yours: no runtime package, no generated folder to
leave alone. Delete forja.config.json and the project
still builds.
forja + Specgate
forja builds the structure. Specgate
decides when a requirement is done: a scenario, a test that names it,
and a suite that passes. forja add usecase creates the
requirement, names it in the test, and regenerates the traceability
matrix.
import { describe, expect, it } from "vitest";
import { PlaceOrderUseCase } from "../../../src/application/orders/PlaceOrderUseCase.js";
describe("REQ-003 Place order", () => {
it("runs", async () => {
const result = await new PlaceOrderUseCase().execute();
expect(result.ok).toBe(true);
});
it.todo("proves the scenario in features/place-order.feature");
});
Only as forja.config.json, which forja add
and forja doctor read. The generated code has no
dependency on forja; delete the file and the project still builds
and tests.
It needs the layout forja generates and a forja.config.json
that describes it. On another layout it stops with an error before
it writes anything.
Node with web, mobile or both; Spring Boot or Quarkus with a web app or as an API only. Mobile with a Java backend is not supported yet, and the CLI says so instead of generating half a project. See the command line reference.
No. The ci extra writes a workflow if you want one; it is
off by default. Everything forja generates runs locally with
npm test.
npx @rsaglobaltech/forja init