Skip to content

Server-side built-in plugins do not load in Docker production image (v1.11.10) #305

@JerryDurand

Description

@JerryDurand

Summary
In the official Docker image moonrailgun/tailchat:1.11.10 and any custom builds derived from it, none of the 17 built-in server-side plugins are loaded. The compiled .service.js files exist in the container at /app/tailchat/server/dist/plugins/*/services/, but Moleculer never discovers or registers them as services.

Steps to Reproduce
Deploy Tailchat v1.11.10 using the official Docker image

Run curl http://localhost:11000/health

Examine the services array in the JSON response

Expected Behavior
The services array should include plugin services such as:

plugin:com.msgbyte.welcome

plugin:com.msgbyte.autojoinGroup

plugin:com.msgbyte.linkmeta

...and 14 others

Actual Behavior
Only 22 core services are registered. The plugin.registry service starts but remains empty. Example output:

json
"services": ["$node","debug","openapi.bot","openapi.integration","openapi.oidc","gateway","chat.ack","chat.converse","chat.inbox","chat.message","config","group","group.extra","group.invite","plugin.registry","user.dmlist","friend","friend.request","mail","user","openapi.app","file"]
Root Cause Analysis
Production uses a different entry point than development. The startDevRunner function (which sets runner.servicePaths) is called in development mode but not in production. The production cli.js simply creates a bare moleculer.Runner() and starts it:

javascript
const moleculer_1 = require("moleculer");
const runner = new moleculer_1.Runner();
runner.start(process.argv);
The moleculer.config.ts file does not specify a services array. Moleculer's ServiceBroker requires explicit service paths to auto-discover services. Without this configuration, it only loads services that are manually imported or registered.

The glob pattern is incorrect. Even if service paths were set, the pattern plugins/**/.service.js does not match the actual directory structure plugins//services/*.service.js.

Impact
The following 17 built-in plugins are completely non-functional:

com.msgbyte.agora

com.msgbyte.autojoinGroup

com.msgbyte.bbcode

com.msgbyte.discover

com.msgbyte.getui

com.msgbyte.github

com.msgbyte.iam

com.msgbyte.linkmeta

com.msgbyte.livekit

com.msgbyte.meeting

com.msgbyte.notify

com.msgbyte.offline-icons

com.msgbyte.prettyinvite

com.msgbyte.simplenotify

com.msgbyte.tasks

com.msgbyte.topic

com.msgbyte.welcome

com.msgbyte.wxpusher

Administrators may not realize these features exist at all.

Workaround Attempted (Failed)
Modified server/packages/sdk/src/runner/index.ts to change servicePaths from .service.ts to .service.js and fixed the glob pattern to plugins//services/.service.js

Rebuilt Docker image multiple times with --no-cache

Verified compiled files exist at correct paths and can be require()d without errors

Result: No change. Plugins still do not load because startDevRunner is not the production entry point.

Proposed Fix
Add a services array to server/moleculer.config.ts:

typescript
services: [
'services/**/.service.js',
'plugins/
/services/*.service.js',
],
Alternatively, modify the production CLI entry point to set service paths before starting the Runner.

Environment
Tailchat version: 1.11.10

Deployment: Docker (official image and custom builds)

Host: Linux VPS (2GB RAM, Docker 24.x)

Additional Context
This issue was discovered after a multi-day debugging effort to get the auto-join plugin working. The client-side builtin.ts changes work correctly, but the server-side services never register. The compiled .service.js files are present and valid, confirming this is a service discovery issue, not a compilation failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions