Skip to content

App

A named application: a set of modules + per-app defaults.

The app is the unit a wire (HTTP, queue, CLI) instantiates. One repo can declare multiple apps that share modules — that's how a monolith becomes a set of services without code changes.

Shape

ts
import { defineApp } from "@nwire/forge";

export const learnflowApp = defineApp("learnflow", {
  description: "Adaptive learning loop for AMIT students and teachers.",
  modules: [submissionsModule, enrollmentsModule, masteryModule, lessonsModule],
  tenantModel: "per-org",          // 'single' | 'per-org' | 'per-account' | 'per-workspace'
  tenantKey: "schoolId",           // the field in payloads carrying tenant id
  defaults: {
    /* runtime options applied unless wire overrides */
  },
});

// Other apps in the same repo can re-use the modules differently:
export const lmsApp = defineApp("lms", { modules: [enrollmentsModule, rosterModule] });
export const lxApp = defineApp("lx", { modules: [submissionsModule, lessonsModule] });
export const competencyApp = defineApp("competency", { modules: [masteryModule] });

Instantiation

A wire (HTTP / queue / CLI / cron) instantiates the app via defineApp.create():

ts
const app = learnflowApp.create({
  actorStore: new MongoActorStore(client),
  projectionStore: new MongoProjectionStore(client),
  bus: new NatsEventBus({ ... }),
});
await app.start();

In practice you don't call .create() directly — the topology composer (next page) reads a manifest and instantiates apps with the right provider stack for that deployment shape.

Multi-tenancy

tenantModel declares the partitioning strategy; Studio uses it to surface the right tenant picker per view. tenantKey declares the field name in payloads (and HTTP x-tenant-id header) the runtime reads.

tenantModelWhen to use
'single'One tenant per process — the process itself is the boundary
'per-org'School / company / institution-level partition (AMIT, ecw)
'per-account'Each end-user is a tenant (B2C)
'per-workspace'Multi-tenant per workspace inside an org (Slack-shaped)

Apps vs modules

ModulesApps
Bounded contextDeployment unit
defineModule("submissions", { actions, actors, … })defineApp("learnflow", { modules })
Reused across appsTied to a specific topology slice

See also

MIT licensed.