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: guides (REST, realtime, SPA/PWA), public packages hub, apps hubs
- Not responsible for: private workspace tooling docs (config-*, agent-registry, cli-init, 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.3.13+ (pinned in the monorepo) | bun --version prints 1.3.13 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. |
| backend-template | Reference backend app in the monorepo that shows REST/realtime composition for juniors. |
| 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.3.13.
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 |
|---|---|---|
| Consume published packages | You build an app that calls Jumentix SDKs | bun add @jumentix/sdk-rest-client |
| Work inside the monorepo | You contribute to or extend the factory itself | bun install at the repo root |
| Study the reference backend | You need a working REST/realtime service to copy patterns from | See Step 3 (backend-template) |
For product teams consuming published packages:
bun add @jumentix/cana @jumentix/sdk-rest-clientFor contributors working in the full workspace:
cd Jumentix
bun installSuccess check: bun install completes without errors; node_modules exists.
Step 3 — Open the reference backend (< 10 minutes)
Private bootstrap tooling is not documented on this public site. For your first backend, study the reference app already in the monorepo:
cd apps/backend-template
bun install
# follow scripts in that app's package.json / README for local runThen open the REST API guide and reproduce the hello path against that template.
Success check: you can locate the HTTP adapter + a use-case folder inside
apps/backend-template and open the REST guide next.
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 — First success: touch Cana in the browser (< 10 minutes)
Before building a full API, 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 |
| Cannot find adapters in backend-template | Wrong folder | Stay under apps/backend-template and use the REST guide map | You can name one HTTP adapter file |
Junior checklist (“I can …”)
- Install Bun 1.3.13+ and confirm
bun --version. - Explain the adapter → application → domain layers using the diagram above.
- Scaffold or open a Jumentix service and locate
.jumentix/service-profile.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.