diff --git a/DECISIONS.md b/DECISIONS.md
index 37bb8bf4..337926ee 100644
--- a/DECISIONS.md
+++ b/DECISIONS.md
@@ -2,11 +2,11 @@
> 本文件记录 lingniu-vehicle-ingest v2 的关键架构决策,后续每次重大调整追加条目(不删除旧条目)。
-## ADR-001 MQ 选型:Kafka
+## ADR-001 消息通道:Kafka
- **Status**: Accepted
- **Context**: 需要高吞吐、严格单车有序、成熟生态
- **Decision**: 使用 Kafka,分区 key = VIN
-- **Consequences**: 下游消费者需使用消费组 + 分区内顺序消费;不使用 RocketMQ 的事务/顺序特性
+- **Consequences**: 下游消费者需使用消费组 + 分区内顺序消费;生产链路只支持 Kafka。
## ADR-002 线上消息格式:Protobuf
- **Status**: Accepted
diff --git a/docs/module-data-flow.html b/docs/module-data-flow.html
index 104eb444..8bfe2c58 100644
--- a/docs/module-data-flow.html
+++ b/docs/module-data-flow.html
@@ -414,7 +414,7 @@ sequenceDiagram
participant Dispatcher as Dispatcher
participant Handler as Protocol Handler
Mapper
participant EventBus as DisruptorEventBus
- participant MQ as sink-kafka
Kafka Envelope
+ participant Kafka as sink-kafka
Kafka Envelope
participant Archive as sink-archive
ArchiveStore
participant History as vehicle-history-app
participant TDengine as tdengine-history-store
raw_frames + locations
@@ -430,12 +430,12 @@ sequenceDiagram
Handler->>Handler: 协议字段映射为内部字段
Dispatcher->>Handler: 绑定 rawArchiveKey / rawArchiveUri
Handler->>EventBus: VehicleEvent(Realtime / Location / Alarm / Login ...)
- EventBus->>MQ: 投递规整后的业务事件
- MQ->>MQ: EnvelopeMapper 转 Protobuf
- MQ->>History: Kafka event/raw topic,key=vin,单车有序
+ EventBus->>Kafka: 投递规整后的业务事件
+ Kafka->>Kafka: EnvelopeMapper 转 Protobuf
+ Kafka->>History: event/raw topic,key=vin,单车有序
History->>TDengine: 写 raw_frames、locations 和 raw parsed JSON
TDengine->>Consumer: 分页历史查询、原始帧追溯、位置查询
- MQ->>Consumer: Redis 热状态、指标统计、告警工单等下游消费
+ Kafka->>Consumer: Redis 热状态、指标统计、告警工单等下游消费
diff --git a/docs/operations/vehicle-ingest-tdengine-verification.md b/docs/operations/vehicle-ingest-tdengine-verification.md
index 0a7485b3..04b44a43 100644
--- a/docs/operations/vehicle-ingest-tdengine-verification.md
+++ b/docs/operations/vehicle-ingest-tdengine-verification.md
@@ -24,13 +24,12 @@ export TDENGINE_USERNAME=root
export TDENGINE_PASSWORD=''
export TDENGINE_MIN_IDLE=0
export TDENGINE_MAX_POOL_SIZE=32
-export EVENT_FILE_STORE_ENABLED=false
export TDENGINE_TELEMETRY_FIELDS_ENABLED=false
```
`TDENGINE_MIN_IDLE=0` 用于减少冷启动时 TDengine 连接重试日志。TDengine 地址稳定后,再按生产并发调大连接池。
-高吞吐生产验收默认关闭 `EVENT_FILE_STORE_ENABLED` 和 `TDENGINE_TELEMETRY_FIELDS_ENABLED`,验证 TDengine `raw_frames`、位置表和分页查询闭环。RAW 帧的 `parsedJson`、`metadataJson`、`rawUri` 直接进入 TDengine,GB32960 snapshot/fields 接口优先基于 `raw_frames` 中的结构化 JSON 返回结果;接入服务写出的原始 `.bin` 只作为冷备复核材料。需要兼容旧 `/api/event-history/records` 低层记录接口或逐字段趋势宽表时,再显式开启对应开关,并单独压测写入放大。
+高吞吐生产验收默认保持 `TDENGINE_TELEMETRY_FIELDS_ENABLED=false`,验证 TDengine `raw_frames`、位置表和分页查询闭环。RAW 帧的 `parsedJson`、`metadataJson`、`rawUri` 直接进入 TDengine,GB32960 snapshot/fields 接口基于 `raw_frames` 与当前解析器即时返回结构化结果;接入服务写出的原始 `.bin` 只作为冷备复核材料。需要逐字段趋势宽表时,再显式开启 `TDENGINE_TELEMETRY_FIELDS_ENABLED=true`,并单独压测写入放大。
## 构建
@@ -83,7 +82,6 @@ lsof -nP -iTCP:32960 -sTCP:LISTEN
```bash
HTTP_PORT=20200 \
KAFKA_CONSUMER_ENABLED=true \
-EVENT_FILE_STORE_ENABLED=false \
EVENT_FILE_STORE_PATH=./target/tdengine-verification/event-store \
TDENGINE_TELEMETRY_FIELDS_ENABLED=false \
java -jar modules/apps/vehicle-history-app/target/vehicle-history-app.jar
diff --git a/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/PortainerComposeResourceLimitsTest.java b/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/PortainerComposeResourceLimitsTest.java
index 77ab1871..773835cd 100644
--- a/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/PortainerComposeResourceLimitsTest.java
+++ b/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/PortainerComposeResourceLimitsTest.java
@@ -116,7 +116,9 @@ class PortainerComposeResourceLimitsTest {
.contains("TDengine `raw_frames`")
.doesNotContain("三个服务必须共用同一个 `SINK_ARCHIVE_PATH`")
.doesNotContain("再回读共享 archive")
- .doesNotContain("读取共享 archive 中的原始 `.bin`");
+ .doesNotContain("读取共享 archive 中的原始 `.bin`")
+ .doesNotContain("EVENT_FILE_STORE_ENABLED")
+ .doesNotContain("/api/event-history/records");
assertThat(splitRunbook)
.contains("TDengine `raw_frames`")
.doesNotContain("must share the same `SINK_ARCHIVE_PATH`")
@@ -124,6 +126,22 @@ class PortainerComposeResourceLimitsTest {
.doesNotContain("shared volume mounted to all three services");
}
+ @Test
+ void architectureDocsNameKafkaInsteadOfGenericMq() throws IOException {
+ String decisions = Files.readString(repositoryRoot().resolve("DECISIONS.md"));
+ String dataFlow = Files.readString(repositoryRoot().resolve("docs/module-data-flow.html"));
+
+ assertThat(decisions)
+ .contains("生产链路只支持 Kafka")
+ .doesNotContain("MQ 选型")
+ .doesNotContain("RocketMQ");
+ assertThat(dataFlow)
+ .contains("participant Kafka as sink-kafka")
+ .doesNotContain("participant MQ")
+ .doesNotContain("->>MQ")
+ .doesNotContain("MQ->>");
+ }
+
@Test
void splitRunbookKeepsAnalyticsAsJt808MetricRuntimeOnly() throws IOException {
String splitRunbook = Files.readString(repositoryRoot()