> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/developer-guides/architecture-decision-log/adr-0040-notifications-disabled-by-default.md).

# ADR-0040: Notifications ship disabled by default behind one condition

## Status

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

## Context

The Notifications subsystem is heavyweight: it consumes the Postgres write-ahead log via a replication slot, runs a background subscriber, and fans alerts out to external channels. It spans several Spring components (a bean-wiring `@Configuration`, a startup subscriber, a message processor). Most deployments don't need it. The platform needs it off by default, turned on by a single switch, with no risk that one component activates while another stays dormant.

## Decision

**The Notifications subsystem ships `notifications.enabled: false` and is gated by a single `Condition` class consulted through one `@ConditionalOnNotifications` meta-annotation applied to every Notifications component.** The condition (`NotificationsFeatureCondition`) reads `notifications.enabled` from Spring's `Environment`, defaulting to `false`. The reusable `@ConditionalOnNotifications` annotation wraps `@Conditional(NotificationsFeatureCondition.class)` and is placed on all three top-level components — the `@Configuration` that wires the senders, the startup subscriber, and the alert message processor. When the property is not `true`, none of the three register and the WAL subscriber never starts.

The design is **single-source-of-truth gating**: one property, one condition class, one meta-annotation. A developer changing the gating semantics (say, sourcing the flag from a feature-flag service) edits one file rather than each component's annotation. This is the meta-annotation variant of the platform's ship-disabled-by-default family — the same posture as GenAI (ADR-0004, inline) and Data Collaboration (ADR-0019, which uses the identical meta-annotation idiom).

## Consequences

* A default deployment runs with notifications entirely absent — no subscriber, no WAL replication slot created, no senders wired.
* The subsystem turns on as a unit: setting `notifications.enabled: true` activates all three components together, so there is no partially-enabled state where (for example) the processor exists but the subscriber doesn't.
* Enabling the subsystem is necessary but not sufficient to receive notifications — individual channels then activate by the presence of their own keys (ADR-0041). The two together form a two-stage opt-in.
* Centralising the flag in one condition class avoids the drift that scattered per-component property checks would cause; the trade-off is one extra indirection (a meta-annotation) over a bare `@ConditionalOnProperty`, chosen deliberately because the flag has three consumers.

## Evidence

* `odd-platform-api/src/main/resources/application.yml:173` — `enabled: false` under the `notifications:` key (line 172), the verbatim shipped default.
* `odd-platform-api/.../notification/config/NotificationsFeatureCondition.java:11-13` — reads `FeatureResolver.NOTIFICATIONS_ENABLED_PROPERTY` from the `Environment` with default `false`.
* `odd-platform-api/.../notification/config/ConditionalOnNotifications.java:9-12` — the meta-annotation: `@Conditional(NotificationsFeatureCondition.class)`.
* The annotation is applied to all three components: `NotificationConfiguration.java:27` (`@Configuration`), `NotificationSubscriberStarter.java:17` (startup subscriber), `AlertNotificationMessageProcessor.java:15` (alert processor).

## See also

* [ADR-0041 — Notification channels activate by the presence of their keys](/developer-guides/architecture-decision-log/adr-0041-notification-per-channel-presence-activation.md) — the second stage of the opt-in, once the subsystem is enabled.
* [ADR-0004 — GenAI ships disabled by default](/developer-guides/architecture-decision-log/adr-0004-genai-disabled-by-default.md) and [ADR-0019 — Data Collaboration ships disabled by default](/developer-guides/architecture-decision-log/adr-0019-data-collaboration-disabled-by-default.md) — the same ship-off-by-default posture.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opendatadiscovery.org/developer-guides/architecture-decision-log/adr-0040-notifications-disabled-by-default.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
