ADR-0019: Data Collaboration ships disabled by default

ODD Platform ships Data Collaboration off by default — a conditional gates the whole controller on datacollaboration.enabled, so every route returns 404 until an operator opts in.

Status

Accepted. Reconstructed from the codebase on 2026-05-30; the decision is live in the source today.

Context

Data Collaboration (the in-platform Discussions surface and the Slack message bridge) is a heavyweight, outbound-integration feature: it needs a Slack OAuth token, a background sender, and Postgres coordination artefacts. Most deployments do not use it. The platform needs a default that keeps the feature inert for the operators who never configure it, while making it a single, explicit opt-in for those who do.

Decision

Data Collaboration ships with enabled: false (under datacollaboration:) as the verbatim default, and the whole feature is gated by a @ConditionalOnDataCollaboration conditional. The feature's controller (and its background components) carry that annotation; when the property is not true, the conditional does not match, the controller bean is never registered, and every Data Collaboration route returns 404 Not Found — there is no degraded mode, no "feature disabled" payload.

The gating is centralised in one Condition class that reads the property from Spring's Environment (defaulting to false), consulted through a single reusable @ConditionalOnDataCollaboration meta-annotation. A developer changing the gating semantics touches one place, not each component.

This is one member of the platform's ship-disabled-by-default family for heavyweight / outbound-integration features, alongside GenAI (ADR-0004) and Notifications (ADR-0040). Once an operator turns the feature on, the required integration config is validated fail-fast at boot (ADR-0018) — so the deployment story is: feature off → operator opts in → operator must supply the Slack OAuth token or the platform refuses to start.

Consequences

  • A default deployment runs with Data Collaboration entirely absent — no beans, no background workers, no Postgres artefacts created.

  • Because gating removes the controller bean rather than guarding each method, a disabled feature responds 404 (route does not exist), not 403 or a disabled-state body. A client cannot distinguish "feature disabled" from "wrong URL" without out-of-band knowledge.

  • Enabling is a single property (datacollaboration.enabled: true) plus the integration config that ADR-0018 then requires at boot; there is no per-route toggle.

  • The single-Condition + meta-annotation design keeps the on/off semantics in one file, avoiding the drift that scattered per-bean property checks would produce.

Evidence

  • odd-platform-api/src/main/resources/application.yml:205enabled: false (under the datacollaboration: key), the verbatim shipped default.

  • odd-platform-api/.../datacollaboration/controller/DataCollaborationController.java:21-22@ConditionalOnDataCollaboration on the @RestController class: no bean when disabled, so its routes 404.

  • odd-platform-api/.../datacollaboration/config/DataCollaborationFeatureCondition.java:18-22 — the single Condition reads FeatureResolver.DATA_COLLABORATION_ENABLED_PROPERTY from the Environment with default false.

  • odd-platform-api/.../datacollaboration/config/ConditionalOnDataCollaboration.java — the reusable @Conditional(DataCollaborationFeatureCondition.class) meta-annotation applied across the feature's components.

See also

Last updated