Skip to content

Architecture and Data Flow

KrugarValdes edited this page Jan 19, 2026 · 1 revision

Architecture and Data Flow

This document explains how the SMS Router Android client intercepts SMS messages, applies Clean Architecture boundaries, and forwards payloads to Mattermost or Telegram webhooks with delivery logging and retries.

Overview

The SMS Router follows a three-layer structure:

  • Presentation: Android components (BroadcastReceiver, Compose screens) + permission handling.
  • Domain: Core business use cases, models, and retry orchestration.
  • Data: API services, mappers, repositories, Room database, SharedPreferences.

Key capabilities:

  • Intercept SMS via high-priority BroadcastReceiver.
  • Support multiple webhooks (Mattermost, Telegram) per SIM card.
  • Persist delivery state with Room and expose live updates via Compose UI.
  • Apply automatic retry with a 60-second overall timeout.
  • Provide configuration UI for per-SIM routing parameters.

Architecture Overview

architecture-overview.svg

The flow separates presentation, domain, and data modules to keep dependencies directional (UI → Domain → Data) and maintain testability.

Core Components

SmsReceiver

Entry point registered for Telephony.Sms.Intents.SMS_RECEIVED_ACTION.

Responsibility Description
SMS Detection Listens for broadcast and prioritizes early interception
Message Extraction Reassembles multipart SMS (GSM 7-bit / UCS-2)
SIM Identification Reads subscription ID, operator name, and phone number
Data Packaging Builds SmsData domain model (sender, body, SIM metadata)
Async Dispatch Launches coroutine on IO dispatcher to avoid blocking receiver

ForwardSmsUseCase

Central coordinator that drives logging, configuration lookup, webhook invocation, and status updates.

Processing flow:

  1. Generate SMS ID (sender + timestamp) for tracking.
  2. Insert initial log entry with IN_PROGRESS status.
  3. Retrieve SIM-specific configuration (webhook URL, secret, type, Telegram chat ID).
  4. Register retry callback so UI reflects intermediate attempts.
  5. Delegate actual HTTP call to the forwarding repository.
  6. Update log to DELIVERED or ERROR depending on result.

SmsApiService

HTTP layer built on Ktor with structured retry logic.

Parameter Value Purpose
Max Attempts 3 Initial request + 2 retries
Overall Timeout 60 seconds Ensures forwarding concludes quickly
Retry Tracking In-memory map keyed by SMS ID Maintains attempt counts
Callback Invoked per retry Notifies UI/log repository

SmsDataDtoMapper

Maps domain models into webhook-specific DTOs:

Webhook Payload Structure Required Fields
Mattermost { "text": "message" } text
Telegram { "chat_id": "id", "text": "message" } chat_id, text

Complete Data Flow

data-flow.svg

  1. Android broadcasts incoming SMS.
  2. SmsReceiver builds SmsData and hands it to the domain layer.
  3. ForwardSmsUseCase logs and orchestrates forwarding.
  4. SettingsRepository provides per-SIM configuration.
  5. SmsDataDtoMapper creates webhook payload.
  6. SmsApiService sends HTTP POST with retries.
  7. Retry callbacks and final states persist via SmsLogsRepository.
  8. Compose UI observes log flow for real-time status.

Repository Implementations

SettingsRepository

Stores SIM routing data in SharedPreferences (JSON serialized per SIM):

Property Description
simId Unique identifier (subscription ID)
simName Display label (carrier/operator)
webhookUrl Destination endpoint
secretKey Bearer token for Authorization header
webhookType Enum (MATTERMOST, TELEGRAM)
chatId Telegram-specific chat identifier

Repository exposes reactive flows for UI plus CRUD helpers for configuration screens.

SmsLogsRepository

Backed by Room database smsrouter-db with table sms_logs to persist delivery history.

Field Purpose
id Primary key (SMS ID)
sender Originating phone number
message SMS body
simType Operator/SIM label
timestamp Epoch millis
status IN_PROGRESS, DELIVERED, ERROR
errorDetails Optional error message
retryCount Attempts performed

Repository converts entities to domain models and emits a StateFlow consumed by the Messages UI.

Security and Authorization

  • All webhook calls include Authorization: Bearer <secretKey>.
  • Optional cleartext traffic allowed for local testing; production should enforce HTTPS.
  • Dangerous permissions required at runtime: RECEIVE_SMS, READ_SMS, READ_PHONE_STATE, READ_PHONE_NUMBERS, INTERNET.
  • Receiver priority is set high (999) to ensure messages reach the app before the default SMS client.

Dependency Injection

Koin DI module wires:

Component Scope Depends On
HttpClient Singleton Ktor configuration
SmsApiService Singleton HttpClient
SmsDataDtoMapper Singleton None (stateless)
SmsForwardingRepository Singleton SmsApiService, SmsDataDtoMapper
SettingsRepository Singleton Android Context
AppDatabase + SmsLogDao Singleton Android Context
SmsLogsRepository Singleton SmsLogDao
SimCardProvider Singleton Context + SubscriptionManager

Domain Models

SmsData

Property Description
sender Originating phone number
operatorName Carrier label from SIM
messageBody Full concatenated SMS text
recipientPhoneNumber Device phone number for the SIM
simId Unique SIM identifier

Error Handling and Retry

  • Retry counters reside in an in-memory map keyed by SMS ID.
  • Each failure increments the counter; callbacks update UI/log.
  • Successful delivery clears the counter; final failure persists the attempt count in Room.
  • A supervisor-backed coroutine scope ensures retries do not crash the receiver.
  • 60-second global timeout stops retry attempts early if exceeded.

Platform Considerations

  • SIM Enumeration: Requires READ_PHONE_STATE; settings screen re-requests permission when operators swap SIM cards.
  • Multipart SMS: Receiver concatenates parts according to GSM/UCS-2 encoding limits before forwarding.
  • Battery Optimization: Devices should whitelist the app from battery savers so broadcasts arrive instantly.

Development Guidelines

Adding New Webhook Types

  1. Extend WebhookType enum.
  2. Create DTO implementing the mapper contract.
  3. Update SmsDataDtoMapper and associated tests.
  4. Add configuration fields and UI elements for the new webhook settings.

Troubleshooting

Issue Check Resolution
SMS not forwarding Verify per-SIM configuration (URL, secret) Update settings and retry
Telegram failures Ensure chatId is populated Provide valid chat ID
Retries exhausted Inspect logs UI for error details Resolve upstream issue, resend
Permission denied Confirm runtime permissions granted Request missing permission

Use Logcat tags (ForwardSmsUseCase, SmsApiService) and the Messages UI for live diagnostics.

Clone this wiki locally