Getting started with Jumentix
Responsibility in context
- Owns: the public on-ramp for juniors adopting Jumentix (mental model + first journey)
- Stack: concepts / learning path (not a runtime package)
- Used with:
@jumentix/cli-initfactory generator, guides (REST, realtime, SPA/PWA), public packages hub - Not responsible for: private workspace tooling docs (config-*, agent-registry, security-scanner)
What it is
Jumentix is a software factory framework: you describe business rules and API contracts once, then generate and run REST APIs, realtime channels, and offline clients from the same core. This page is the on-ramp for junior developers who have never used Jumentix before.
Why it exists
Product teams often rebuild the same plumbing — HTTP wiring, OpenAPI alignment, WebSocket handlers, IndexedDB sync — in every project. Jumentix gives you a repeatable path so you spend time on domain logic instead of adapter glue. This page gets you from zero to a verified first success in under 30 minutes.
Prerequisites
| Item | Minimum | How to verify |
|---|---|---|
| Bun | 1.4.2+ (pinned in the monorepo) | bun --version prints 1.4.2 or higher |
| Terminal | Any modern shell | You can run commands in your project folder |
| Editor | VS Code, Cursor, or similar | You can open TypeScript files |
| Node.js | 22.x (optional) | Only needed if a legacy tool still requires Node |
Install Bun if you do not have it yet:
curl -fsSL https://bun.sh/install | bash
bun --versionPrior reading (skim once, return when a term appears):
Glossary
| Term | Plain meaning |
|---|---|
| Contract | A machine-readable description of an API shape — usually OpenAPI (REST) or AsyncAPI (realtime). |
| Adapter | Code that connects your domain to a technology (Express, Socket.IO, IndexedDB, Redis, etc.). Adapters are swappable. |
| Domain | Business entities, rules, and events — the code that should not change when you swap HTTP frameworks. |
| Use case | Application-layer logic that orchestrates domain rules for one user-facing action. |
| Port | An interface your domain defines; an adapter implements it. |
| Hexagonal architecture | Domain at the center; adapters on the outside. Also called ports and adapters. |
| OpenAPI | YAML/JSON spec describing REST endpoints, request bodies, and response shapes. |
| AsyncAPI | Spec describing channels and message payloads for WebSocket or event streams. |
| Bun | Fast JavaScript/TypeScript runtime and package manager used across Jumentix workspaces. |
| Factory CLI | @jumentix/cli-init — `jumentix init |
| GenerationPlan | Normalized plan from designer export, OAS, catalog URL, or Users preset before files are written. |
| Cana | @jumentix/cana — IndexedDB adapter for offline-first PWAs. |
| Service Management | The Jumentix app where Domain Designer and service configuration live. |
Numbered steps
Step 1 — Install the toolchain (< 5 minutes)
- Install Bun (see Prerequisites).
- Confirm the version gate passes:
bun --version.
Success check: the command exits 0 and prints a semver ≥ 1.4.2.
Step 2 — Pick your starting path (< 2 minutes)
Choose one path — do not try both on day one:
| Path | When to use | First command after setup |
|---|---|---|
| Generate a product workspace | You want a runnable Jumentix app (default first success) | npx @jumentix/cli-init init — see Step 3 |
| Consume published packages | You build an app that calls Jumentix SDKs only | bun add @jumentix/sdk-rest-client |
| Work inside the monorepo | You contribute to or extend the factory itself | bun install at the repo root |
For product teams generating a workspace (recommended):
npx @jumentix/cli-init init my-app \
--preset=users --non-interactive --mode=monolith \
--http=express --db=sqlite --installFor teams that only need SDKs:
bun add @jumentix/cana @jumentix/sdk-rest-clientFor contributors working in the full workspace:
cd Jumentix
bun installSuccess check: factory path creates my-app/ with .jumentix/project.json;
package path completes bun install without errors.
Step 3 — First success: factory init (< 10 minutes)
The public factory generator is @jumentix/cli-init. It writes a lean Bun
workspace for one factory mode (monolith / services / hybrid / frontend)
from a GenerationPlan (--preset=users, --from designer/OAS/catalog).
npx @jumentix/cli-init init demo \
--preset=users --non-interactive --mode=hybrid --frontend \
--http=express --db=sqlite --install
cd demo
npx @jumentix/cli-init doctor
ls apps # core (+ frontend when hybrid)What you should see:
.jumentix/project.json— mode, plan, template cohort (not the retiredservice-profile.json).jumentix/manifest.json— sha256 of generated filesjumentix.init.json— answers for--configround-tripsapps/*workspace packages ready forbun run dev|test|lint|build
Extend later with jumentix add domain|service|frontend, refresh templates with
jumentix upgrade, and diagnose with jumentix doctor. Modes map to the
service factory capabilities matrix
(see also repository doc JUMENTIX-SERVICE-FACTORY-CAPABILITIES-MATRIX.md).
Success check: demo/.jumentix/project.json exists, doctor exits 0, and
you can name the HTTP adapter folder under apps/.
Then open the REST API guide and call the generated service.
Step 4 — Learn the mental model (< 5 minutes)
Keep this picture visible while you read guides:
[ Adapters ] Express / Fastify / Socket.IO / gRPC / IndexedDB (Cana)
↓
[ Application ] use-cases, ports
↓
[ Domain ] entities, rules, eventsThree rules that prevent most junior mistakes:
- Contracts first — OpenAPI / AsyncAPI / shared packages describe the shape before you wire handlers.
- Adapters are replaceable — swap Express for Fastify without rewriting domain code.
- Offline is first-class —
@jumentix/canais the IndexedDB adapter for PWAs; it is not the same aslocalStorage.
Step 5 — Touch Cana in the browser (< 10 minutes)
Before building a full offline PWA, confirm the docs toolchain works. Run the playground below — Run should return a green result, then Reset should restore the starting state.
Getting started
Open a client, create Category and Task records, then read them back.
### Getting started
```ts
const client = cana.createClient({
name: dbName,
schema: {
version: 1,
stores: [
{ name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
{
name: 'tasks',
keyPath: 'id',
indexes: [
{ name: 'byCategory', keyPath: 'categoryId' },
{ name: 'byCompleted', keyPath: 'completed' },
{ name: 'byUpdatedAt', keyPath: 'updatedAt' }
]
}
]
}
});
await client.open();
await client.table('categories').add({
id: 'work',
name: 'Work',
color: '#2563eb',
createdAt: Date.now(),
updatedAt: Date.now()
});
await client.table('tasks').add({
id: 'task-1',
title: 'Write the Cana tutorial',
categoryId: 'work',
completed: false,
priority: 'high',
createdAt: Date.now(),
updatedAt: Date.now()
});
return {
backend: client.backend,
category: await client.table('categories').get('work'),
task: await client.table('tasks').get('task-1')
};
```const client = cana.createClient({
name: dbName,
schema: {
version: 1,
stores: [
{ name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
{
name: 'tasks',
keyPath: 'id',
indexes: [
{ name: 'byCategory', keyPath: 'categoryId' },
{ name: 'byCompleted', keyPath: 'completed' },
{ name: 'byUpdatedAt', keyPath: 'updatedAt' }
]
}
]
}
});
await client.open();
await client.table('categories').add({
id: 'work',
name: 'Work',
color: '#2563eb',
createdAt: Date.now(),
updatedAt: Date.now()
});
await client.table('tasks').add({
id: 'task-1',
title: 'Write the Cana tutorial',
categoryId: 'work',
completed: false,
priority: 'high',
createdAt: Date.now(),
updatedAt: Date.now()
});
return {
backend: client.backend,
category: await client.table('categories').get('work'),
task: await client.table('tasks').get('task-1')
};Success check: playground Run completes without errors; you see IndexedDB records created in the output panel.
Step 6 — Core workflows (this week)
Complete these guides in order when you need each capability:
| Order | Guide | You will |
|---|---|---|
| 1 | Create a REST API | Start a REST service, align OpenAPI, call it from @jumentix/sdk-rest-client |
| 2 | Create a Realtime API | Enable WebSocket (or gRPC server-to-server) with REST fallback |
| 3 | Create a SPA or Offline PWA | Model domains in Service Management and persist offline with Cana |
| 4 | SaaS Monolith | Ship one deployment unit with modular boundaries |
| 5 | SaaS Microservices | Split bounded contexts when scale demands it |
Step 7 — Full surface (when you need lookup, not tutorials)
| Area | Path | Use when |
|---|---|---|
| Packages | /docs/jumentix/packages | You need API docs or a Try it playground |
| Adapters | /docs/jumentix/adapters/http | You pick HTTP, database, or realtime adapters |
| Reference | /docs/jumentix/reference/errors-responses | You debug status codes and error contracts |
| AI maps | /llms.txt, /docs-index.json | Agents or search tools need a machine-readable index |
Examples
Minimal REST client call (static)
Inject the OpenAPI document in the browser — do not load specs with Node fs:
const client = api.createMockClient();
const result = await client.request({ method: 'GET', path: '/health' });
console.log(result.status, result.body);See the interactive version on Create a REST API.
Offline record with Cana (static)
const client = await cana.open({ name: 'my-app', version: 1 });
await client.put('tasks', { id: '1', title: 'Hello Jumentix' });
const task = await client.get('tasks', '1');
console.log(task.title);Use the Cana playground in Step 5 to run this pattern live.
Common errors
| Symptom | Likely cause | Fix | Verify success |
|---|---|---|---|
bun: command not found | Bun not on PATH | Re-run the install script; restart the terminal | bun --version works |
TransactionInactive in Cana | await fetch (or other non-IndexedDB I/O) inside a Cana transaction | Only await IndexedDB work inside the transaction callback | Playground Run green; no transaction errors |
| REST client cannot load specs | Node fs loader used in the browser | Inject the OpenAPI object (see REST guide playground) | Mock client returns /health |
| Works in memory, fails in Redis | Wrong key-value adapter for the runtime | Start with InMemory in tests; use Redis adapter only in Node | Unit tests pass locally |
| Lost offline data | Expecting localStorage to behave like IndexedDB | Use Cana; read client.backend after open() | Records survive page reload |
jumentix init exits 1 on missing answers | --non-interactive without full flags/config | Pass --preset/--mode/--http/--db or a jumentix.init.json via --config | Init writes .jumentix/project.json |
| Cannot find adapters in generated app | Looking in the monorepo seed instead of the generated tree | cd into the init output and open apps/<service> | You can name one HTTP adapter file |
Junior checklist (“I can …”)
- Install Bun 1.4.2+ and confirm
bun --version. - Explain the adapter → application → domain layers using the diagram above.
- Run
jumentix init(ornpx @jumentix/cli-init init) and locate.jumentix/project.json. - Run the Cana playground (Run green, Reset restores state).
- Name the difference between OpenAPI (REST) and AsyncAPI (realtime).
- Open the REST guide and know it is my next hands-on task.
- Find package docs and playgrounds at /docs/jumentix/packages.
Next step
Go to Create a REST API and complete the hello-world path end to end — that is the default second page in the learning journey.