Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 68 additions & 46 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const referenceSidebar = [
],
},
{
text: 'Domain',
text: 'Contracts And Domain',
collapsed: false,
items: [
{ text: 'AggregateRoot', link: '/reference/aggregate-root' },
Expand All @@ -28,7 +28,7 @@ const referenceSidebar = [
],
},
{
text: 'Adapters',
text: 'Pub/Sub',
collapsed: false,
items: [
{ text: 'Consumer', link: '/reference/consumer' },
Expand All @@ -37,12 +37,38 @@ const referenceSidebar = [
link: '/reference/amqp-message-bus-adapter',
},
{ text: 'InMemoryPubSub', link: '/reference/in-memory-pub-sub' },
],
},
{
text: 'DB',
collapsed: false,
items: [
{ text: 'InMemoryRepository', link: '/reference/in-memory-repository' },
{ text: 'MongoRepository', link: '/reference/mongo-repository' },
],
},
{
text: 'UI',
collapsed: false,
items: [
{ text: 'ExpressKernelServer', link: '/reference/express-kernel-server' },
{ text: 'Route', link: '/reference/route' },
{ text: 'Scheduler', link: '/reference/scheduler' },
{ text: 'WinstonLogger', link: '/reference/winston-logger' },
],
},
{
text: 'Scheduling',
collapsed: false,
items: [{ text: 'Scheduler', link: '/reference/scheduler' }],
},
{
text: 'Logs',
collapsed: false,
items: [{ text: 'WinstonLogger', link: '/reference/winston-logger' }],
},
{
text: 'WebSocket',
collapsed: false,
items: [
{ text: 'WebSocketEventHub', link: '/reference/web-socket-event-hub' },
{
text: 'WebSocketRealtimeServer',
Expand All @@ -52,6 +78,36 @@ const referenceSidebar = [
},
];

const gettingStartedSidebar = [
{
text: 'Getting started',
items: [
{ text: 'Introduction', link: '/getting-started/introduction' },
{ text: 'Package map', link: '/getting-started/package-map' },
{ text: 'Installation', link: '/getting-started/installation' },
{
text: 'Application startup',
link: '/getting-started/application-startup',
},
],
},
];

const guideSidebar = [
{
text: 'Guides',
items: [
{
text: 'Dependency injection',
link: '/guides/dependency-injection',
},
{ text: 'Adapters', link: '/guides/adapters' },
{ text: 'AMQP pub/sub', link: '/guides/amqp-pubsub' },
{ text: 'HTTP routes', link: '/guides/http-routes' },
],
},
];

export default defineConfig({
lang: 'en-US',
title: 'DDD Kernel',
Expand All @@ -77,55 +133,21 @@ export default defineConfig({
siteTitle: 'DDD Kernel',

nav: [
{ text: 'Guide', link: '/getting-started/introduction' },
{ text: 'Adapters', link: '/guides/adapters' },
{ text: 'Getting Started', link: '/getting-started/introduction' },
{ text: 'Guide', link: '/guides/dependency-injection' },
{ text: 'Reference', link: '/reference/' },
],

sidebar: {
'/getting-started/': [
{
text: 'Getting started',
items: [
{ text: 'Introduction', link: '/getting-started/introduction' },
{ text: 'Installation', link: '/getting-started/installation' },
{
text: 'Application startup',
link: '/getting-started/application-startup',
},
],
},
{
text: 'Guides',
items: [
{
text: 'Dependency injection',
link: '/guides/dependency-injection',
},
{ text: 'Adapters', link: '/guides/adapters' },
{ text: 'AMQP pub/sub', link: '/guides/amqp-pubsub' },
{ text: 'HTTP routes', link: '/guides/http-routes' },
],
},
],
'/guides/': [
{
text: 'Guides',
items: [
{
text: 'Dependency injection',
link: '/guides/dependency-injection',
},
{ text: 'Adapters', link: '/guides/adapters' },
{ text: 'AMQP pub/sub', link: '/guides/amqp-pubsub' },
{ text: 'HTTP routes', link: '/guides/http-routes' },
],
},
...referenceSidebar,
],
'/getting-started/': gettingStartedSidebar,
'/guides/': guideSidebar,
'/reference/': referenceSidebar,
},

socialLinks: [
{ icon: 'github', link: 'https://github.com/haskou/ddd-kernel' },
],

outline: {
level: [2, 3],
label: 'On this page',
Expand Down
12 changes: 10 additions & 2 deletions docs/getting-started/application-startup.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ import { applicationConsumers } from './apps/ApplicationConsumers.js';
import { recurringSchedulers } from './apps/ApplicationSchedulers.js';
import GetUserByIdRoute from './apps/api/routes/GetUserByIdRoute.js';

const kernel = new Kernel();
const kernel = new Kernel({
sourceDirectory: 'src',
servicesYamlPath: 'config/container/services.yaml',
});

await kernel.dependencyInjection();
await kernel.dependencyInjection({
containerBuild: process.env.CONTAINER_BUILD === 'true',
});
kernel.registerRoutes(GetUserByIdRoute);
kernel.registerConsumers(...applicationConsumers);
kernel.registerSchedulers(...recurringSchedulers);
Expand All @@ -31,6 +36,9 @@ kernel.logger.info('Application running on port 3000');
`CONTAINER_BUILD=true` regenerates `config/container/services.yaml`. Without it,
the generated YAML is loaded.

`new Kernel(...)` configures defaults for the runtime. `kernel.dependencyInjection(...)`
can override the DI-specific values for a particular boot.

Call `kernel.shutdown()` from your process signal handlers to stop consumers,
stop schedulers, close servers, flush logs and release connections registered
through shutdown hooks:
Expand Down
53 changes: 47 additions & 6 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
# Installation

Install the package in an application:
Install the kernel package in an application:

```bash
yarn add @haskou/ddd-kernel
```

Install only the peer dependencies required by the adapters you import. For
example, AMQP requires `amqplib`:
That is enough for the core kernel, contracts, domain primitives, dependency
injection and in-memory adapters.

Install extra packages only for the adapters your application imports.

## Pub/Sub Adapters

The in-memory pub/sub adapter has no extra runtime dependencies.

The AMQP adapter uses `amqplib`:

```bash
yarn add amqplib
```

Express routes require:
## DB Adapters

The in-memory repository adapter has no extra runtime dependencies.

The MongoDB repository adapter uses `mongodb`:

```bash
yarn add mongodb
```

## UI Adapters

The Express adapter uses `express`, `routing-controllers` and decorator
metadata packages:

```bash
yarn add express routing-controllers reflect-metadata class-transformer class-validator
```

MongoDB repositories require:
Install `cors` only when enabling `routingControllersOptions.cors`:

```bash
yarn add mongodb
yarn add cors
```

## Other Adapters

Schedulers use `node-cron`:

```bash
yarn add node-cron
```

The Winston logger uses `winston`:

```bash
yarn add winston
```

WebSocket helpers use `ws`:

```bash
yarn add ws
```

## TypeScript Resolution
Expand Down
9 changes: 9 additions & 0 deletions docs/getting-started/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ Use it when you want:

The core package does not force a database or HTTP framework into your app. Use
adapter subpaths only when a service needs them.

The recommended dependency direction is:

1. Domain and application code depend on contracts and domain primitives.
2. Adapters implement those contracts at the infrastructure boundary.
3. Bootstrap code chooses the adapter for the current runtime.

For the available imports and adapters, see the
[package map](/getting-started/package-map).
74 changes: 74 additions & 0 deletions docs/getting-started/package-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Concepts And Package Map

`@haskou/ddd-kernel` is split into three layers:

- **Core**: lifecycle, dependency injection, kernel logging contracts and the
`Kernel` runtime.
- **Contracts and domain primitives**: stable interfaces and base classes that
application code depends on.
- **Adapters**: optional infrastructure implementations for a contract or
runtime boundary.

Application code should usually depend on contracts and domain primitives.
Bootstrap code chooses adapters.

## Core

| Area | Import | Purpose |
| ---------------------- | ----------------------------------------- | ------------------------------------------------------------------------ |
| Kernel runtime | `@haskou/ddd-kernel` | Registers consumers, routes, schedulers, runtimes and shutdown hooks. |
| Dependency injection | `@haskou/ddd-kernel/dependency-injection` | Wraps `node-dependency-injection` and container YAML generation/loading. |
| Lifecycle | `@haskou/ddd-kernel/lifecycle` | Runtime and initializer contracts. |
| Kernel logger contract | `@haskou/ddd-kernel/contracts/kernel` | `KernelLogger` interface. |

`node-dependency-injection` and `fs-extra` are package dependencies because the
core DI implementation uses them directly. Applications do not install them
separately.

## Contracts And Domain

| Area | Import | Purpose |
| ----------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- |
| Domain | `@haskou/ddd-kernel/domain` | `AggregateRoot`, `DomainEvent`, domain event bus contracts and consumer/publisher contracts. |
| Pub/sub contracts | `@haskou/ddd-kernel/contracts/pubsub` | Generic message bus, consumer registration and handler contracts. |
| DB contracts | `@haskou/ddd-kernel/contracts/db` | Repository-oriented persistence contracts. |
| UI contracts | `@haskou/ddd-kernel/contracts/ui` | Route contracts and HTTP status constants. |

## Adapters

| Group | Adapter | Import | Extra packages |
| --------- | -------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pub/sub | In-memory | `@haskou/ddd-kernel/adapters/pubsub/in-memory` | None |
| Pub/sub | AMQP | `@haskou/ddd-kernel/adapters/pubsub/amqp` | `amqplib` |
| DB | In-memory repository | `@haskou/ddd-kernel/adapters/db/in-memory` | None |
| DB | Mongo repository | `@haskou/ddd-kernel/adapters/db/mongo` | `mongodb` |
| UI | Express server and HTTP error handling | `@haskou/ddd-kernel/adapters/ui/express` | `express`, `routing-controllers`, `reflect-metadata`, `class-transformer`, `class-validator`; `cors` only when `routingControllersOptions.cors` is enabled |
| UI | Route base class | `@haskou/ddd-kernel/adapters/ui/routes` | Same runtime as the HTTP server that executes routes |
| Kernel | Console logger | `@haskou/ddd-kernel/adapters/kernel/console` | None |
| Logs | Winston logger | `@haskou/ddd-kernel/logs` | `winston` |
| Scheduler | Cron scheduler base | `@haskou/ddd-kernel/scheduler` | `node-cron` |
| WebSocket | Event hub and realtime server | `@haskou/ddd-kernel/websocket` | `ws` |

Adapters are optional. Importing the kernel or domain contracts does not require
Express, AMQP, MongoDB, Winston or WebSocket packages.

## Application Boundary

Use constructor injection inside consumers, schedulers, routes and services.
Use bootstrap code to choose infrastructure:

```ts
await kernel.dependencyInjection({
overrides: [
{
token: UserRepository,
useClass:
process.env.NODE_ENV === 'test'
? InMemoryUserRepository
: MongoUserRepository,
},
],
});
```

That keeps domain/application code stable while adapters change per runtime.
10 changes: 10 additions & 0 deletions docs/guides/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ Adapters live under the same high-level groups as contracts:
- `adapters/ui` implements HTTP/UI runtime concerns.
- `adapters/kernel` implements kernel-level defaults such as logging.

The package already includes these adapters:

| Group | Included adapters |
| ------------------- | ------------------------------------------------------------------------- |
| Pub/sub | `InMemoryPubSub`, `AmqpMessageBusAdapter`, consumer middleware primitives |
| DB | `InMemoryRepository`, `MongoRepository` |
| UI | `ExpressKernelServer`, `HttpErrorHandler`, route base classes |
| Kernel/logging | `ConsoleKernelLogger`, `WinstonLogger` |
| Scheduler/WebSocket | `Scheduler`, `WebSocketEventHub`, `WebSocketRealtimeServer` |

An adapter should implement a contract or abstract class from the domain/kernel
surface and stay free of application-specific concepts.

Expand Down
12 changes: 12 additions & 0 deletions docs/reference/console-kernel-logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@ const kernel = new Kernel({

It implements `KernelLogger` with `console.debug`, `console.info`,
`console.warn` and `console.error`.

You usually do not need to configure it explicitly. `Kernel` creates one when
no `logger` option is provided:

```ts
const kernel = new Kernel();

kernel.logger.info('Application running');
```

Use a custom `KernelLogger` or `WinstonLogger` when the application needs
structured logs, files or a central logging backend.
Loading
Loading