Unified Reaction Automation Design

Date: 2026-05-10
Status: Approved (conversation-level), pending file review gate

1. Goal

Thiết kế lại automation theo hướng reaction engine thống nhất:

  • telemetry từ thiết bị là trigger đầu vào
  • hệ thống đánh giá điều kiện trên một hoặc nhiều nguồn telemetry
  • khi điều kiện khớp, hệ thống thực hiện một hoặc nhiều reaction
  • alert chỉ là một loại action trong automation, không còn là subsystem cấu hình riêng

Mục tiêu sản phẩm:

  • user cấu hình rule trên màn Automation
  • một rule có thể đọc telemetry từ nhiều device khác nhau
  • một rule có thể tạo alert, bật/tắt nhiều thiết bị, hoặc kết hợp cả hai
  • rule chỉ trigger khi state chuyển pha, không spam action ở mọi gói telemetry
  • rule có thể chạy recovery actions khi điều kiện quay về bình thường

2. Scope

In scope

  • thay mô hình automation rule hiện tại từ 1 condition + 1 action sang n conditions + n actions
  • hỗ trợ AND hoặc OR ở cấp rule
  • hỗ trợ source telemetry từ nhiều device khác nhau trong cùng organization
  • hỗ trợ trigger actionsrecovery actions
  • thêm action type alert
  • đánh giá rule dựa trên latest endpoint snapshot còn hiệu lực
  • thêm runtime state để hỗ trợ edge-triggering và cooldown
  • xây màn authoring/list/detail/execution history cho automation rules
  • loại alert-config khỏi feature scope mới

Out of scope

  • expression logic có ngoặc như (A and B) or C
  • scheduler/time-based automation
  • cross-organization automation
  • priority engine hoặc conflict resolution nâng cao giữa nhiều rules
  • migration dữ liệu từ alert-config
  • action types ngoài alertdevice_command

3. Current State

Repo hiện có 3 mảnh tách rời:

  • telemetry đã lưu telemetry và đang tự check threshold để tạo alert
  • automation đã có endpoint-based rule engine nhưng mới hỗ trợ 1 condition + 1 action
  • alert-config đang giữ cấu hình threshold ở scope organization, pond, device

Điểm không còn phù hợp với hướng sản phẩm mới:

  • alert đang là một flow riêng thay vì một reaction type
  • runtime evaluation hiện gắn với event của một source endpoint, chưa hỗ trợ multi-device snapshot evaluation
  • rule model hiện còn gắn farmId, trong khi yêu cầu mới chỉ cần cùng organization
  • UI automation hiện mới là khung cơ bản, chưa phải màn authoring thực thụ

4. Decisions Already Locked In

Các quyết định đã được chốt trong buổi brainstorming:

  1. Alert không còn là subsystem cấu hình riêng; nó là một action type trong automation
  2. alert-config bị loại khỏi feature scope mới
  3. User cấu hình feature ở một màn Automation mới, không gộp vào AlertConfig
  4. Rule là edge-triggered: chỉ chạy khi state chuyển từ normal -> triggered
  5. Rule có recovery actions khi state chuyển từ triggered -> normal
  6. Bản đầu chỉ làm scope cấu hình theo device-level telemetry sources, không làm inheritance organization/pond/device
  7. Một rule hỗ trợ n actions, và action list có thể trộn alert với device command
  8. Một rule hỗ trợ nhiều conditions với AND hoặc OR
  9. Conditions có thể lấy từ nhiều devices khác nhau
  10. Multi-device evaluation dùng latest snapshot miễn còn trong freshness window
  11. freshness window là hằng số toàn hệ thống, không cho user chỉnh
  12. Mọi source/target devices trong rule phải cùng organization
  13. Rule có cooldown mặc định do hệ thống set, user có thể sửa
  14. Nếu nhiều rules cùng điều khiển một target endpoint, lệnh chạy sau thắng

5. Options Considered

Option A: Mở rộng automation hiện tại thành reaction engine thống nhất

Giữ module automation làm trung tâm, nhưng reshape data model, DTO, engine, và UI để support:

  • multi-condition
  • multi-action
  • trigger/recovery phases
  • alert action
  • runtime state

Pros

  • khớp trực tiếp với mental model sản phẩm
  • tận dụng được endpoint model, dispatch path, và execution audit hiện có
  • giảm số subsystem runtime song song

Cons

  • cần đổi shape entity/API đáng kể
  • cần bỏ tư duy farm-scoped single-event rule đang có

Option B: Tạo module reaction mới đứng cạnh automation

Giữ automation cũ cho device command, thêm module khác để orchestration alert và multi-source evaluation.

Pros

  • ít đụng entity cũ hơn trong ngắn hạn

Cons

  • tạo hai engine chồng chéo
  • UI/user model là một hệ thống nhưng backend lại là hai hệ thống
  • khó maintain về lâu dài

Option C: Giữ rule model cũ, thêm lớp composite service bên ngoài

Chỉ vá xung quanh engine hiện tại để mô phỏng multi-condition/multi-action.

Pros

  • sửa ít code nhất lúc đầu

Cons

  • runtime behavior sẽ nhanh chóng rối
  • khó audit, khó test, khó mở rộng
  • không giải quyết tận gốc state machine và snapshot evaluation

6. Selected Design

Chọn Option A: biến automation thành reaction engine thống nhất của toàn hệ thống.

Nguyên tắc cốt lõi:

  • telemetry ingestion chỉ ingest và phát tín hiệu reevaluate
  • automation là nơi duy nhất quyết định hệ thống sẽ “phản ứng” thế nào
  • alert là action type chứ không phải config subsystem riêng
  • rule scope là organization, không còn farm
  • evaluation dựa trên latest endpoint snapshot cộng với runtime state bền vững

7. Domain Architecture

7.1. Rule Scope

Rule thuộc về một organization.

Rule không bị ràng bởi farmId hay pondId. Một rule có thể:

  • lấy source A ở khu vực này
  • lấy source B ở khu vực khác
  • điều khiển target C ở khu vực khác nữa

Miễn là tất cả entities cùng organization và user có quyền author rule.

Điều này thay thế assumption cũ trong automation hiện tại là mọi source/target phải cùng farm.

7.2. Conditions

Mỗi rule có:

  • conditionOperator: AND | OR
  • conditions[]

Mỗi condition gồm:

  • sourceDeviceEndpointId
  • operator: <, <=, >, >=, =, !=
  • thresholdValue
  • sequenceOrder

Condition luôn đánh giá trên latest value của endpoint nguồn, không đọc trực tiếp từ raw telemetry field nữa. Mapping từ raw telemetry sang endpoint value tiếp tục đi qua endpoint normalizer hiện có.

7.3. Actions

Mỗi rule có hai nhóm action:

  • triggerActions[]
  • recoveryActions[]

Action bản đầu hỗ trợ hai loại:

  • alert
  • device_command

Mỗi action có:

  • type
  • phase: trigger | recovery
  • sequenceOrder
  • isEnabled
  • payload

Payload theo type:

  • alert
    • severity: info | warning | critical
    • titleTemplate
    • messageTemplate
  • device_command
    • targetDeviceEndpointId
    • targetValue

Thiết kế payload-based này cho phép sau này thêm webhook, ticket, notification-only mà không phải đổi shape rule tổng thể.

7.4. Runtime State

Mỗi rule cần một runtime state bền vững:

  • currentState: normal | triggered
  • lastEvaluatedAt
  • lastStateChangedAt
  • lastTriggerExecutionAt
  • lastRecoveryExecutionAt
  • lastEvaluationSummary

lastEvaluationSummary là JSON snapshot gọn phục vụ audit/debug:

  • condition results theo từng source
  • aggregate result
  • freshness failures nếu có

7.5. Latest Snapshot Model

Để evaluate multi-device rules, hệ thống cần latest value theo endpoint.

Thiết kế thêm automation_endpoint_latest_values với key theo deviceInstanceEndpointId.

Mỗi row gồm:

  • deviceInstanceEndpointId
  • organizationId
  • value
  • observedAt
  • sourceTelemetryId
  • updatedAt

Redis cache có thể được thêm sau để tăng tốc, nhưng DB row này là source of truth của phase đầu.

8. Data Model Changes

8.1. automation_rules

Reshape bảng hiện tại:

  • giữ:
    • id
    • organizationId
    • name
    • description
    • status
    • cooldownSeconds
    • createdBy
    • updatedBy
    • createdAt
    • updatedAt
  • bỏ:
    • farmId
    • triggerMode
  • thêm:
    • conditionOperator

Mặc định:

  • status = draft
  • cooldownSeconds = 300

300s là default hệ thống cho phase đầu. User có thể override theo rule.

8.2. automation_rule_conditions

Giữ bảng riêng, nhưng semantics đổi thành many conditions per rule.

Fields:

  • id
  • ruleId
  • sourceDeviceEndpointId
  • operator
  • thresholdValue
  • sequenceOrder

Không cần thêm phase ở condition vì trigger/recovery được quyết định bằng state transition của toàn rule, không phải bởi condition set riêng.

8.3. automation_rule_actions

Bảng hiện tại phải được reshape từ single target action sang polymorphic action row.

Fields:

  • id
  • ruleId
  • phase: trigger | recovery
  • actionType: alert | device_command
  • sequenceOrder
  • isEnabled
  • payload jsonb

Không giữ targetDeviceEndpointIdtargetValue ở top-level cột chung nữa, vì alert không có các field đó. Chúng được chuyển vào payload của device_command.

8.4. automation_rule_runtime_states

Thêm bảng mới:

  • id
  • ruleId
  • currentState
  • lastEvaluatedAt
  • lastStateChangedAt
  • lastTriggerExecutionAt
  • lastRecoveryExecutionAt
  • lastEvaluationSummary
  • createdAt
  • updatedAt

Mỗi rule có tối đa một row state.

8.5. automation_endpoint_latest_values

Thêm bảng mới:

  • id
  • deviceInstanceEndpointId
  • organizationId
  • value
  • observedAt
  • sourceTelemetryId
  • createdAt
  • updatedAt

Mục đích:

  • lấy snapshot cho multi-device evaluation
  • kiểm tra freshness
  • tạo audit trail tối thiểu cho evaluation input

8.6. automation_rule_executions

Bảng execution hiện có được giữ lại nhưng mở rộng semantics thành phase execution envelope.

Một execution record cần lưu:

  • ruleId
  • phase
  • triggeredAt
  • status: succeeded | partial_failed | failed | skipped
  • evaluationSnapshot
  • actionResults
  • failureReason

Không cần tạo command ledger mới trong spec này; phase đầu chỉ cần execution envelope đủ để audit reaction behavior. Nếu reliability core được mở rộng tiếp, command ledger có thể được thêm như phase riêng.

9. Runtime Flow

9.1. Telemetry Ingestion

TelemetryService tiếp tục:

  1. validate source device
  2. persist telemetry
  3. normalize raw payload thành endpoint events
  4. update automation_endpoint_latest_values
  5. yêu cầu automation reevaluate các rules liên quan

TelemetryService không còn tự check threshold để tạo alert nữa.

9.2. Rule Re-evaluation Trigger

Mỗi endpoint event mới là một tín hiệu để reevaluate các active rules có tham chiếu tới endpoint đó trong conditions.

Flow:

  • tìm rules active có ít nhất một condition trỏ tới endpoint mới cập nhật
  • load toàn bộ conditions của từng rule
  • lấy latest snapshot của mọi source endpoints cần thiết
  • nếu có source quá cũ so với freshness window, mark condition đó là stale

9.3. Freshness Policy

freshness window là hằng số toàn hệ thống:

  • 300 seconds

Condition chỉ được evaluate khi latest snapshot của source còn trong cửa sổ này.

Hành vi:

  • với AND: nếu một condition stale, aggregate result là false
  • với OR: stale condition không tự tạo true; rule chỉ true nếu có ít nhất một condition evaluate true từ dữ liệu fresh

Mọi stale reason phải được ghi vào lastEvaluationSummary.

9.4. State Transition

Aggregate evaluation của rule cho ra một boolean isTriggered.

State machine:

  • normal + false => stay normal
  • normal + true => transition to triggered, chạy triggerActions
  • triggered + true => stay triggered
  • triggered + false => transition to normal, chạy recoveryActions

Đây là cơ chế edge-triggered mà user đã chốt.

9.5. Cooldown

Cooldown mặc định:

  • 300 seconds

Cooldown chỉ áp dụng cho phase tương ứng:

  • chặn triggerActions nếu vừa trigger quá gần
  • chặn recoveryActions nếu vừa recovery quá gần

Cooldown không thay state transition logic. Nó chỉ chặn re-execution của cùng phase trong khoảng thời gian ngắn bất thường.

9.6. Action Execution

Actions trong mỗi phase chạy tuần tự theo sequenceOrder.

Quy tắc:

  • nếu một action fail, engine vẫn chạy action sau
  • action result được ghi riêng cho từng action
  • execution tổng thể có thể là:
    • succeeded
    • partial_failed
    • failed
    • skipped

9.7. Conflict Behavior

Nếu nhiều rules gửi command tới cùng target endpoint:

  • runtime không chặn
  • không làm priority engine
  • command chạy sau thắng

Audit phải phản ánh rõ command nào được gửi ở thời điểm nào để hỗ trợ debug sau này.

10. Alert And Device Command Behavior

10.1. Alert Action

alert action tái sử dụng luồng tạo alert/notification hiện có của devices module.

Nó phải tạo ra cùng loại user-visible artifact mà hệ thống đang dùng cho alert hiện nay:

  • severity
  • title
  • message
  • data context

Payload template có thể render các biến:

  • {{ruleName}}
  • {{phase}}
  • {{source.<endpointId>.value}}
  • {{source.<endpointId>.observedAt}}

Bản đầu không cần template engine quá phức tạp; string interpolation đủ dùng.

10.2. Device Command Action

device_command action tiếp tục dùng dispatch path hiện có của device endpoint control.

Trước khi dispatch, engine phải kiểm tra:

  • target endpoint tồn tại
  • target endpoint isEnabled
  • target endpoint isWritable
  • target device thuộc cùng organization
  • target device không ở trạng thái retired hoặc maintenance nếu hệ thống hiện đã có check tương tự

10.3. Recovery Action Semantics

Recovery actions không bị suy diễn tự động từ trigger actions.

User phải cấu hình rõ:

  • trigger phase làm gì
  • recovery phase làm gì

Ví dụ:

  • trigger:
    • tạo critical alert
    • bật quạt 1
    • bật quạt 2
  • recovery:
    • tạo info alert
    • tắt quạt 1
    • tắt quạt 2

11. API Design

11.1. Rule DTO Shape

Create/update DTO cần đổi sang aggregate shape:

type RuleConditionDto = {
  sourceDeviceEndpointId: string;
  operator: '<' | '<=' | '>' | '>=' | '=' | '!=';
  thresholdValue: number | boolean | string;
  sequenceOrder: number;
};

type AlertActionPayloadDto = {
  severity: 'info' | 'warning' | 'critical';
  titleTemplate: string;
  messageTemplate: string;
};

type DeviceCommandActionPayloadDto = {
  targetDeviceEndpointId: string;
  targetValue: number | boolean | string;
};

type RuleActionDto = {
  actionType: 'alert' | 'device_command';
  sequenceOrder: number;
  isEnabled: boolean;
  payload: AlertActionPayloadDto | DeviceCommandActionPayloadDto;
};

type CreateReactionRuleDto = {
  name: string;
  description?: string;
  conditionOperator: 'AND' | 'OR';
  cooldownSeconds?: number;
  conditions: RuleConditionDto[];
  triggerActions: RuleActionDto[];
  recoveryActions: RuleActionDto[];
};

11.2. Endpoints

  • GET /api/v1/automation/rules
  • GET /api/v1/automation/rules/:id
  • POST /api/v1/automation/rules
  • PUT /api/v1/automation/rules/:id
  • POST /api/v1/automation/rules/:id/activate
  • POST /api/v1/automation/rules/:id/pause
  • GET /api/v1/automation/rules/:id/executions

List response nên include:

  • summary thông tin rule
  • condition count
  • trigger action count
  • recovery action count
  • current runtime state
  • last executed at

11.3. Validation Rules

Backend validation phải enforce:

  • conditions không được rỗng
  • trigger actions có thể rỗng nếu user chỉ muốn recovery-only? Không cho phase đầu
  • recovery actions được phép rỗng
  • mọi source endpoints phải readable
  • mọi target endpoints trong device_command phải writable
  • mọi source/target devices phải cùng organization của rule
  • alert action không được mang payload của device_command và ngược lại

Bản đầu chốt thêm:

  • triggerActions phải có ít nhất một action
  • recoveryActions có thể rỗng

12. Frontend Design

12.1. Screen Strategy

Tạo màn Automation Rules thực thụ, không dùng màn AlertConfig.

Màn cần có:

  • list rules
  • create/edit wizard
  • rule detail
  • execution history

12.2. Authoring Flow

Wizard 5 bước:

  1. Rule info
  2. Conditions
  3. Trigger actions
  4. Recovery actions
  5. Review and activate

Lý do dùng wizard:

  • rule shape đủ phức tạp
  • conditions và actions là nested collections
  • cần review toàn rule trước khi activate

12.3. UX Constraints

UI phải giúp user:

  • thêm nhiều conditions từ nhiều devices
  • chọn AND hoặc OR
  • thêm nhiều actions theo thứ tự
  • phân biệt rõ trigger với recovery
  • preview human-readable text của rule trước khi lưu

Màn list cần hiển thị:

  • rule name
  • status
  • condition summary
  • trigger/recovery action counts
  • last state
  • last execution time

13. Permissions

Permissions có thể tiếp tục nằm dưới namespace automation.

Phase đầu cần đủ các quyền:

  • automation:read:*
  • automation:create:*
  • automation:update:*
  • automation:activate:*
  • automation:pause:*

Nếu repo hiện chưa có namespace này đầy đủ, implementation phải thêm cho đồng bộ thay vì reuse sai namespace của device.

14. Error Handling And Audit

Hệ thống phải ghi được:

  • condition nào stale
  • source nào thiếu latest snapshot
  • action nào fail
  • target nào bị reject vì không writable hoặc khác organization
  • phase nào đã chạy
  • state transition nào xảy ra

Không được fail toàn rule chỉ vì một action fail. Fail được cô lập ở action result và phản ánh lên execution envelope.

15. Testing Strategy

15.1. Unit Tests

  • rule validation cho DTO mới
  • aggregate condition evaluation với AND
  • aggregate condition evaluation với OR
  • stale snapshot handling
  • state transition logic
  • cooldown logic theo từng phase
  • action execution ordering
  • alert payload validation
  • device command payload validation

15.2. Service Tests

  • telemetry update làm refresh latest endpoint snapshot
  • event mới reevaluate đúng set rules liên quan
  • normal -> triggered chạy trigger actions đúng một lần
  • triggered -> normal chạy recovery actions đúng một lần
  • multi-device rule dùng latest values từ nhiều sources
  • rule không trigger nếu source khác organization
  • conflict runtime giữ semantics last command wins

15.3. Frontend Tests

  • wizard render đúng từng step
  • add/remove/reorder conditions
  • add/remove/reorder actions
  • validation khi thiếu trigger action
  • serialization đúng DTO shape backend cần

16. Implementation Notes

Các thay đổi cốt lõi cần phản ánh trong code:

  • bỏ checkThresholds() khỏi runtime path của telemetry
  • bỏ assumption farmId trong automation rule model và engine
  • reshape DTO/service/controller/entity của automation thành aggregate rule model
  • tái sử dụng alert creation path thay vì giữ alert-config

AlertConfigPage và các service liên quan không còn là target của feature mới. Chúng có thể bị loại khỏi navigation hoặc dọn hẳn tùy implementation phase, nhưng không còn được coi là source of truth cho reaction behavior.

17. Done Criteria

Feature được coi là xong khi:

  • user tạo được rule có nhiều conditions và nhiều actions
  • rule hỗ trợ AND/OR
  • rule trigger theo edge-transition, không spam ở mọi telemetry packet
  • rule chạy recovery actions khi quay về normal
  • alert hoạt động như một action type trong automation
  • device command hoạt động như một action type trong automation
  • multi-device latest snapshot evaluation hoạt động với freshness window = 300s
  • không còn threshold alert runtime path riêng ngoài automation
  • test backend/frontend tương ứng đều pass