@ooneex/module package organizes your application by feature, not by file type. A module is a single, domain-scoped unit — billing, catalog, order, auth — that groups everything that capability needs: controllers, entities, services and repositories, middleware, cron jobs, and events. Instead of spreading one feature across a controllers/ tree, an entities/ tree, and a services/ tree, you keep it together under modules/<name>/ and let the framework wire it into the running app.
Why modules
- Vertical slices. Each module owns a whole business capability end to end, so the code you change for one feature lives in one place rather than scattered across the codebase.
- Domain boundaries. Naming modules after the domain (
billing,order,auth) makes ownership and intent obvious, and keeps unrelated features from leaking into each other. - Real packages. Every module is its own workspace package named
@module/<name>with a path alias in the roottsconfig.json, so imports are explicit and boundaries are enforced. - One contract. A module exports a single
ModuleTypeobject — a predictable shape that lists exactly what the module contributes to the app. - Generated, not hand-wired. Artifact generators scaffold straight into a module’s
src/, so adding a controller or service to a feature is one command, not a manual file dance.
How it works
A module is a value that satisfiesModuleType from @ooneex/module. Each field is a collection of the classes that the module contributes — the app reads these collections to register the feature.
| Field | What it collects |
|---|---|
controllers | HTTP and WebSocket controllers that expose the module’s routes and handlers. |
entities | Entity classes that model the module’s data. |
middlewares | Middleware classes that intercept requests for this module. |
cronJobs | Scheduled jobs the module runs on a timer. |
events | Event classes the module emits or listens for. |
Structure and composition
Modules live undermodules/<name>/, each its own workspace package (@module/<name>) with a src/ directory and a path alias in the root tsconfig.json. Two core modules always exist and cannot be removed:
| Module | Role |
|---|---|
app | The application root module. |
shared | Cross-cutting code shared across feature modules. |
app destination registers the new module into both AppModule and SharedModule, composing it into the running application. The result is a tree of feature modules that the app assembles from a small set of roots.
See structure for the on-disk layout of a module and composition for how modules register into AppModule and SharedModule.
Lifecycle
A module moves through three phases: create it, fill it with artifacts, then remove it when the feature is retired. 1. Create. Scaffold a new module and choose its destination.modules/<name>/ as a workspace package, names it @module/<name>, adds its path alias to the root tsconfig.json, and registers it into the chosen destination module.
2. Fill with artifacts. Generate controllers, services, entities, middleware, and the rest straight into the module’s src/.
modules/<module>/src/ — for example modules/billing/src/middlewares/<Name>Middleware.ts — and you register it in the matching field of the module’s ModuleType.
3. Remove. Tear a module down when its feature is gone.
app and shared modules are permanent and cannot be removed.
Next steps
- Module structure — the on-disk layout of a module package.
- Composition — how modules register into
AppModuleandSharedModule. - Create a module — the workflow for scaffolding a new module.
- Remove a module — retiring a feature safely.
module:createcommand — the full CLI reference.- Artifact components such as controllers and services that fill a module.