# Textpipe SMS API Gateway - Implementation Plan ## Overview Build an Android SMS API Gateway with an embedded HTTP server (Ktor), dual SIM support, local message database, and background service. --- ## Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ MainActivity │ │ (Compose UI + Permissions) │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ TextpipeService │ │ (Foreground Service + Lifecycle) │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ TextpipeServer (Ktor CIO) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ │ │ /api/status │ │/api/sms/send│ │/api/sms/messages│ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ SimManager │ │ SmsSender │ │ SmsRepository │ │ (API Keys) │ │ (SmsManager)│ │ (Room + Send) │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────┐ │ AppDatabase (Room) │ │ sms_messages table │ └─────────────────────────────────┘ ``` --- ## Package Structure ``` sh.sar.textpipe/ ├── MainActivity.kt (modify) ├── TextpipeApplication.kt (create) ├── data/ │ ├── db/ │ │ ├── AppDatabase.kt │ │ ├── SmsMessageDao.kt │ │ └── SmsMessageEntity.kt │ ├── model/ │ │ └── ApiModels.kt │ └── repository/ │ └── SmsRepository.kt ├── server/ │ ├── TextpipeServer.kt │ ├── auth/ │ │ └── ApiKeyAuth.kt │ └── routes/ │ ├── SmsRoutes.kt │ └── StatusRoutes.kt ├── service/ │ ├── TextpipeService.kt │ ├── BootReceiver.kt │ ├── SmsReceiver.kt │ └── SmsSender.kt ├── sim/ │ └── SimManager.kt ├── root/ │ └── RootManager.kt └── ui/ ├── MainScreen.kt └── MainViewModel.kt ``` --- ## API Endpoints ### Authentication - API key in header: `Authorization: Bearer ` or `X-API-Key: ` - Each SIM slot has its own unique API key (auto-generated, persistent) - API key determines which SIM sends the message ### Endpoints | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/status` | No | Server health, SIM info, uptime | | POST | `/api/sms/send` | Yes | Send SMS | | GET | `/api/sms/messages` | Yes | List messages (optional `?type=sent\|received`) | | GET | `/api/sms/status/{id}` | Yes | Get specific message status | ### Request/Response Examples **POST /api/sms/send** ```json // Request { "to": "+1234567890", "text": "Hello World" } // Response { "id": 1, "status": "pending", "simSlot": 0 } ``` **GET /api/sms/messages** ```json [ { "id": 1, "type": "sent", "address": "+1234567890", "text": "Hello World", "simSlot": 0, "status": "delivered", "timestamp": 1707148800000, "deliveryTimestamp": 1707148805000 } ] ``` **GET /api/status** ```json { "running": true, "port": 8080, "uptime": 3600000, "sims": [ { "slot": 0, "carrier": "Carrier1", "number": "+1...", "hasApiKey": true }, { "slot": 1, "carrier": "Carrier2", "number": "+1...", "hasApiKey": true } ] } ``` --- ## Dependencies to Add ### libs.versions.toml additions ```toml [versions] ktor = "3.0.3" room = "2.6.1" kotlinxSerialization = "1.7.3" datastorePreferences = "1.1.1" ksp = "2.0.21-1.0.28" coroutines = "1.9.0" [libraries] ktor-server-core = { group = "io.ktor", name = "ktor-server-core", version.ref = "ktor" } ktor-server-cio = { group = "io.ktor", name = "ktor-server-cio", version.ref = "ktor" } ktor-server-content-negotiation = { group = "io.ktor", name = "ktor-server-content-negotiation", version.ref = "ktor" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" } ktor-server-status-pages = { group = "io.ktor", name = "ktor-server-status-pages", version.ref = "ktor" } ktor-server-cors = { group = "io.ktor", name = "ktor-server-cors", version.ref = "ktor" } room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" } [plugins] kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ``` --- ## Permissions Required ```xml ``` --- ## Implementation Order ### Phase 0: Build Configuration 1. `gradle/libs.versions.toml` - Add all new dependencies 2. `build.gradle.kts` (root) - Add KSP and serialization plugins 3. `app/build.gradle.kts` - Add dependencies and plugins 4. `AndroidManifest.xml` - Add permissions, services, receivers ### Phase 1: Data Layer 5. `data/model/ApiModels.kt` - Request/response data classes 6. `data/db/SmsMessageEntity.kt` - Room entity 7. `data/db/SmsMessageDao.kt` - Database operations 8. `data/db/AppDatabase.kt` - Room database ### Phase 2: Core Managers 9. `sim/SimManager.kt` - SIM detection, API key management 10. `root/RootManager.kt` - Root access and iptables port redirect ### Phase 3: SMS Operations 11. `service/SmsSender.kt` - Send SMS with delivery tracking 12. `data/repository/SmsRepository.kt` - Combine database + sending 13. `service/SmsReceiver.kt` - Receive incoming SMS ### Phase 4: HTTP Server 14. `server/auth/ApiKeyAuth.kt` - API key validation 15. `server/routes/StatusRoutes.kt` - Health check endpoint 16. `server/routes/SmsRoutes.kt` - SMS API endpoints 17. `server/TextpipeServer.kt` - Ktor server configuration ### Phase 5: Service Layer 18. `service/TextpipeService.kt` - Foreground service 19. `service/BootReceiver.kt` - Auto-start on boot 20. `TextpipeApplication.kt` - Application class ### Phase 6: UI Layer 21. `ui/MainViewModel.kt` - UI state management 22. `ui/MainScreen.kt` - Compose UI 23. `MainActivity.kt` - Update with permissions and new UI --- ## Key Technical Decisions ### HTTP Server - **Ktor CIO engine** (not Netty) - lighter weight for Android - Server runs on configurable port (default 8080) - For ports 80/443: Use iptables NAT redirect via `su` (don't run JVM as root) ### Dual SIM Support - `SubscriptionManager.getActiveSubscriptionInfoList()` for SIM detection - `SmsManager.createForSubscriptionId(subscriptionId)` for sending - API key maps to subscription ID, not slot index ### SMS Delivery Tracking - PendingIntents for sent confirmation and delivery reports - Update database status: pending → sent → delivered/failed - Multipart SMS via `sendMultipartTextMessage()` ### Background Persistence - Foreground service with persistent notification - `FOREGROUND_SERVICE_TYPE_SPECIAL_USE` for API 34+ - Boot receiver for auto-start ### API Key Storage - SharedPreferences (not DataStore) for synchronous reads - Key format: UUID, stored per SIM slot - Generated on first run, persistent across app updates --- ## Files to Create/Modify (22 total) | # | File | Action | |---|------|--------| | 1 | `gradle/libs.versions.toml` | Modify | | 2 | `build.gradle.kts` (root) | Modify | | 3 | `app/build.gradle.kts` | Modify | | 4 | `app/src/main/AndroidManifest.xml` | Modify | | 5 | `data/model/ApiModels.kt` | Create | | 6 | `data/db/SmsMessageEntity.kt` | Create | | 7 | `data/db/SmsMessageDao.kt` | Create | | 8 | `data/db/AppDatabase.kt` | Create | | 9 | `sim/SimManager.kt` | Create | | 10 | `root/RootManager.kt` | Create | | 11 | `service/SmsSender.kt` | Create | | 12 | `data/repository/SmsRepository.kt` | Create | | 13 | `service/SmsReceiver.kt` | Create | | 14 | `server/auth/ApiKeyAuth.kt` | Create | | 15 | `server/routes/StatusRoutes.kt` | Create | | 16 | `server/routes/SmsRoutes.kt` | Create | | 17 | `server/TextpipeServer.kt` | Create | | 18 | `service/TextpipeService.kt` | Create | | 19 | `service/BootReceiver.kt` | Create | | 20 | `TextpipeApplication.kt` | Create | | 21 | `ui/MainViewModel.kt` | Create | | 22 | `ui/MainScreen.kt` | Create | | 23 | `MainActivity.kt` | Modify | --- ## UI Features (Basic for now) - Server status indicator (Running/Stopped) - Port configuration input - Start/Stop toggle button - SIM cards list with: - Carrier name - Phone number (if available) - API key with copy button - Root port redirect toggle (if root available) - Battery optimization exemption button --- ## Out of Scope (Deferred) - WebUI for viewing messages in browser - Rate limiting - IP whitelisting - HTTPS/TLS (beyond port redirect) - Message scheduling - Webhook callbacks