Lesson 0201 drew three contexts. Now they become code: for each context a group of libraries that together carry one domain, with rules that the lint run enforces. That includes everyday questions: What may be in the front end, in which direction may a library look, how do you find a cycle, how do you move a library?
The workspace from 0101 and 0102 is assumed (Nx, tags, enforce-module-boundaries); this lesson does not repeat the commands there.
State of the checks. Run (Node 24.22.3, Nx 24.0.6, Angular 22.2, Vitest 4.1.12, throwaway workspace outside the repository): eleven libraries in four groups and the application
kladde-buerowith@nx/angular:library;nx run-many -t lintover 12 projects (exit 0);nx graph --file=graph.jsonand the edges from it; a violation against the domain (exit 1); a deliberate cycle (exit 1, message below) and its removal (exit 0, 13 projects);nx generate @nx/workspace:move(twice, see the trap below);nx test termine-domain(1 test, exit 0);nx build kladde-buero(exit 0). Not run: a browser, the pages of the application, splitting a library (described, no command), Sheriff, the pipeline. The library bodies are written for the exercise. The paths/api/contacts,/api/appointmentsmatch the plan;/api/tendersand the fielddeadlineare invented for this lesson (the plan names no tenders API for the front end: check the state of K2).
One context, one group
The names follow <domain>-<type>[-<name>], the folders libs/<domain>/<type>[-<name>]. The Kladde gets:
| Group | Libraries |
|---|---|
kontakte |
kontakte-domain, kontakte-data-access, kontakte-ui, kontakte-feature-liste |
termine |
termine-domain, termine-data-access, termine-feature-kalender |
ausschreibungen |
ausschreibungen-domain, ausschreibungen-data-access, ausschreibungen-feature-liste |
shared |
shared-util-datum |
If you worked through 0102, you already have kontakte-feature-liste, kontakte-data-access, kontakte-ui, termine-data-access and shared-util-datum; new are the four domain libraries (one each), termine-feature-kalender, ausschreibungen-data-access and ausschreibungen-feature-liste. You create a library as in 0102; the tags are in quotation marks:
npx nx generate @nx/angular:library --directory=libs/kontakte/domain `
--name=kontakte-domain --prefix=kl --importPath=@kladde/kontakte/domain `
"--tags=scope:kontakte,type:domain" --no-interactive
The generator also creates a sample component; a domain library does not need it, so delete its folder lib/ and write your own files.
From now on two things apply compared with 0102. There is a fifth type: type:domain for plain TypeScript files without Angular, in which the model of the context lives. And there is the domain scope:ausschreibungen, which the application scope:buero may use. The rules in eslint.config.mjs change like this:
{ sourceTag: 'type:ui', onlyDependOnLibsWithTags: ['type:ui', 'type:domain', 'type:util'] },
{ sourceTag: 'type:data-access', onlyDependOnLibsWithTags: ['type:data-access', 'type:domain', 'type:util'] },
{ sourceTag: 'type:domain', onlyDependOnLibsWithTags: ['type:domain', 'type:util'] },
{ sourceTag: 'scope:ausschreibungen', onlyDependOnLibsWithTags: ['scope:ausschreibungen', 'scope:shared'] },
plus 'type:domain' in the lists of type:app and type:feature and 'scope:ausschreibungen' in the one of scope:buero; everything else stays as in 0102.