본문으로 건너뛰기

ADR-002: Recon Service Boundary

Status

Accepted

Date

2026-04-22

Context

middle_server contains a heavy SMS reconciliation capability set:

  • Pushbullet device management
  • SMS whitelist management
  • recharge template management
  • AI-assisted regex generation
  • SMS ingestion and task-state progression
  • missing-message backfill
  • Telegram SMS ingestion
  • manual review APIs
  • automatic order matching
  • back-office top-info counters

In servers_v2, we need to migrate this capability without:

  • turning admin_service into a new leftover monolith
  • letting the admin frontend call multiple backend services directly
  • violating the single money writer rule

Decision

We will introduce a dedicated recon_service plus recon_worker.

Ownership:

  • admin_service remains the only back-office HTTP entrypoint for bo/admin.
  • recon_service owns SMS reconciliation domain data and APIs.
  • recon_worker owns long-running listeners, polling loops, parsing, matching, and admin-refresh signaling.
  • wallet_service remains the only money writer.

Call flow:

  • bo/admin -> admin_service -> recon_service
  • recon_service does not directly mutate money state
  • final approval still flows through admin_service and wallet_service

Compatibility rules:

  • existing back-office routes such as /api/admin/pushbullet/* and /api/admin/shooter/* remain externally stable
  • admin legacy token and session semantics stay at the admin_service edge
  • top-info counters such as sms_need_check_cnt continue to be aggregated by admin_service

Consequences

Positive:

  • clear domain ownership
  • clean separation between reconciliation and money mutation
  • front-end remains largely unchanged
  • worker lifecycle and health can be independently managed

Negative:

  • requires one more internal service and worker runtime
  • requires admin compatibility adapter routes and a new internal client

Constraints

  • recon_worker health must be based on freshness of successful loop progress, not just process liveness
  • no production cutover is complete while /shooter/device/* and other related legacy routes remain unclassified