Skip to main content

2026-09-25-server-features


title: "The server is its features: lib/src/ by feature, DwAppServer(features:)" affects: dartway_core_server: "0.21.0-dev.5" dartway_cli: "0.12.0"​

Who is affected​

Every project. DwAppServer no longer takes handlers:, channels:, jobs: or routes:; it takes features:. And dartway check now refuses a server lib/src/ that is not laid out by feature (invalidTopLevelLayout).

The layout​

lib/src/ holds folders only:

  • core/ — sign-in hooks (DwAuthConfig), what the caller is and the access rules, channel addresses, upload rules, startup steps;
  • migrations/ — unchanged;
  • one folder per feature — everything of that area: its row classes, handlers, rows → data objects, publications, jobs, rules — in files named after it, subfolders when it grows. It declares itself in <feature>/<feature>_feature.dart.

No file at the top of src/, and no layer folder there: handlers/, rows/, entities/, domain/, objects/, publications/, services/, models/. Where an area was split across layers, gather it into its feature's folder; what two features share goes to the one that owns it, or to core/.

Moving a row class changes nothing in the database: the table is named by @DwSqlTable, not by the file. Rename the file's part '….dw.dart' to the new file name and run dartway generate.

The declaration​

Per feature, <feature>_feature.dart:

final chatFeature = DwServerFeature(
'chat',
handlers: chatHandlers,
channels: [
DwChannelRule.keyed<int>(
AppChannel.conversation,
parseKey: int.parse,
canSubscribe: (ctx, id) => ctx.isMemberOf(id),
),
],
jobs: chatJobs,
);

The channel rules that lived in one list (AppChannels.rules) move to the feature that owns each channel kind; the channel addresses handlers publish to (AppChannels.profileOf(…)) stay in core/channels.dart.

And the server lists the features:

DwAppServer(
- handlers: [...profileHandlers, ...chatHandlers],
- channels: AppChannels.rules,
- jobs: [...chatJobs],
+ features: [profileFeature, chatFeature],
...
);

A feature's name is its folder's name: lower-case letters, digits and _. A test that builds a DwAppServer of its own passes features: [DwServerFeature('test', handlers: …)], or features: const [].