docs(alerting): align @JsonTypeInfo spec with shipped code
Design spec and Plan 02 described AlertCondition polymorphism as Id.DEDUCTION, but the code that shipped in PR #140 uses Id.NAME with property="kind" and include=EXISTING_PROPERTY. The `kind` field is real on every subtype and the DB stores it in a separate column (condition_kind), so reading the discriminator directly is simpler than deduction — update the docs to match. Also add `"kind"` to the example JSON payloads so they match on-wire reality. OutboundAuth (Plan 01) correctly still uses Id.DEDUCTION and is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,7 @@ mvn clean compile # confirm Plan 01 code compiles as baseline
|
||||
|---|---|
|
||||
| `AlertingProperties.java` | Not here — see app module. |
|
||||
| `AlertRule.java` | Immutable record: id, environmentId, name, description, severity, enabled, conditionKind, condition, evaluationIntervalSeconds, forDurationSeconds, reNotifyMinutes, notificationTitleTmpl, notificationMessageTmpl, webhooks, targets, nextEvaluationAt, claimedBy, claimedUntil, evalState, audit fields. |
|
||||
| `AlertCondition.java` | Sealed interface; Jackson DEDUCTION polymorphism root. |
|
||||
| `AlertCondition.java` | Sealed interface; Jackson `kind`-based polymorphism root (Id.NAME + EXISTING_PROPERTY). |
|
||||
| `RouteMetricCondition.java` | Record: scope, metric, comparator, threshold, windowSeconds. |
|
||||
| `ExchangeMatchCondition.java` | Record: scope, filter, fireMode, threshold, windowSeconds, perExchangeLingerSeconds. |
|
||||
| `AgentStateCondition.java` | Record: scope, state, forSeconds. |
|
||||
@@ -126,7 +126,7 @@ mvn clean compile # confirm Plan 01 code compiles as baseline
|
||||
- **One commit per task.** Commit messages: `feat(alerting): …`, `test(alerting): …`, `fix(alerting): …`, `chore(alerting): …`, `docs(alerting): …`.
|
||||
- **Tenant invariant.** Every ClickHouse query and Postgres table referencing observability data filters by `tenantId` (injected via `AlertingBeanConfig` from `cameleer.server.tenant.id`).
|
||||
- **No `FINAL`** on the two new CH count methods — alerting tolerates brief duplicate counts.
|
||||
- **Jackson polymorphism** via `@JsonTypeInfo(use = DEDUCTION)` with `@JsonSubTypes` on `AlertCondition`.
|
||||
- **Jackson polymorphism** via `@JsonTypeInfo(use = Id.NAME, property = "kind", include = EXISTING_PROPERTY)` with `@JsonSubTypes` on `AlertCondition`.
|
||||
- **Pure `core/`, Spring-only in `app/`.** No `@Component`, `@Service`, or `@Scheduled` annotations in `cameleer-server-core`.
|
||||
- **Claim polling.** `FOR UPDATE SKIP LOCKED` + `claimed_by` / `claimed_until` with 30 s TTL.
|
||||
- **Instance id** for claim ownership: use `InetAddress.getLocalHost().getHostName() + ":" + processPid()`; exposed as a bean `"alertingInstanceId"` of type `String`.
|
||||
@@ -403,7 +403,7 @@ git commit -m "feat(alerting): add ALERT_RULE_CHANGE + ALERT_SILENCE_CHANGE audi
|
||||
|
||||
## Phase 2 — Core domain model
|
||||
|
||||
Each task in this phase adds a small, focused set of pure-Java records and enums under `cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/`. All records use canonical constructors with explicit `@NotNull`-style defensive copying only for mutable collections (`List.copyOf`, `Map.copyOf`). Jackson polymorphism is handled by `@JsonTypeInfo(use = DEDUCTION)` on `AlertCondition`.
|
||||
Each task in this phase adds a small, focused set of pure-Java records and enums under `cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/`. All records use canonical constructors with explicit `@NotNull`-style defensive copying only for mutable collections (`List.copyOf`, `Map.copyOf`). Jackson polymorphism is handled by `@JsonTypeInfo(use = Id.NAME, property = "kind", include = EXISTING_PROPERTY)` on `AlertCondition` — the subtype is read from the existing `kind` field each record exposes.
|
||||
|
||||
### Task 3: Enums + `AlertScope`
|
||||
|
||||
@@ -606,14 +606,15 @@ package com.cameleer.server.core.alerting;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "kind",
|
||||
include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(RouteMetricCondition.class),
|
||||
@JsonSubTypes.Type(ExchangeMatchCondition.class),
|
||||
@JsonSubTypes.Type(AgentStateCondition.class),
|
||||
@JsonSubTypes.Type(DeploymentStateCondition.class),
|
||||
@JsonSubTypes.Type(LogPatternCondition.class),
|
||||
@JsonSubTypes.Type(JvmMetricCondition.class)
|
||||
@JsonSubTypes.Type(value = RouteMetricCondition.class, name = "ROUTE_METRIC"),
|
||||
@JsonSubTypes.Type(value = ExchangeMatchCondition.class, name = "EXCHANGE_MATCH"),
|
||||
@JsonSubTypes.Type(value = AgentStateCondition.class, name = "AGENT_STATE"),
|
||||
@JsonSubTypes.Type(value = DeploymentStateCondition.class, name = "DEPLOYMENT_STATE"),
|
||||
@JsonSubTypes.Type(value = LogPatternCondition.class, name = "LOG_PATTERN"),
|
||||
@JsonSubTypes.Type(value = JvmMetricCondition.class, name = "JVM_METRIC")
|
||||
})
|
||||
public sealed interface AlertCondition permits
|
||||
RouteMetricCondition, ExchangeMatchCondition, AgentStateCondition,
|
||||
|
||||
Reference in New Issue
Block a user