Files
tajniak81 d6956395c8 Rebrand CommGate to gsmnode and adopt new design system
Rename the whole project from CommGate to gsmnode and re-skin every
surface onto the new signal-green + ink design system (Space Grotesk /
IBM Plex Sans / JetBrains Mono, flat surfaces, two-arrow routing mark,
lowercase gsm+node wordmark).

- Web App + API panel: rewrite token layer, gn-* utilities, data-gsm-theme,
  new logo/favicon assets; both builds verified.
- Phone App (Flutter): green theme, new mark/wordmark widgets, adaptive
  launcher icons; rename Android applicationId/package to app.gsmnode.phone;
  bump AGP to 8.6.0 and google_fonts to 8.1.0; debug APK build verified.
- API Server (Go): panel routes, User-Agent, health service id, branding.
- Home Assistant Plugin: rename integration domain sms_gateway to gsmnode
  (folder, DOMAIN, services, entity ids, classes); py_compile verified.
- Update all READMEs; add .gitignore (excludes Design/, build artifacts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 08:53:14 +02:00

125 lines
5.5 KiB
Markdown

# gsmnode — Phone App (Flutter / Android)
Turns an Android phone into the SMS gateway endpoint. It registers with the API
Server, polls for pending outbound messages, sends them over the radio, reports
delivery state, and forwards incoming SMS to the server's inbox.
```
API Server ──(pending messages)──► Phone App ──► SmsManager (send)
▲ │
└──(status reports / inbox)──────────┘ ◄── BroadcastReceiver (incoming)
```
> The Phone App talks **only** to the API Server (never to PocketBase directly),
> using the device token issued at registration.
## Status: source scaffold
This folder contains the complete Dart app and the native Android (Kotlin) SMS
bridge, but **not** the generated Gradle/platform scaffolding. You generate that
once with `flutter create` after installing the toolchain (below).
## Prerequisites
1. **Flutter SDK** (stable) — https://docs.flutter.dev/get-started/install/windows
2. **JDK 17** (this machine currently has only JDK 8 — Android Gradle needs 17+)
3. **Android SDK** (via Android Studio or `flutter doctor --android-licenses`)
4. A **physical Android phone** with a SIM (the emulator can't send real SMS)
Verify with `flutter doctor` — resolve anything it flags before continuing.
## Generate platform scaffolding & wire in the native code
From this `Phone App/` folder:
```powershell
# 1. Generate the android/ Gradle project (keeps lib/ and pubspec.yaml)
flutter create . --org app.smsgateway --project-name sms_gateway_phone --platforms=android
# 2. Overlay the SMS-enabled manifest + Kotlin (overwrites the generated stubs)
Copy-Item -Recurse -Force android_overlay/* android/
# 3. Fetch packages
flutter pub get
```
`android_overlay/` mirrors the real `android/` paths, so step 2 drops:
- `app/src/main/AndroidManifest.xml` — SMS permissions + the `SmsReceiver`
- `app/src/main/kotlin/app/smsgateway/sms_gateway_phone/MainActivity.kt` — send bridge
- `app/src/main/kotlin/app/smsgateway/sms_gateway_phone/SmsReceiver.kt` — incoming bridge
If Gradle complains about SDK levels, set `minSdkVersion 23` (or higher) in
`android/app/build.gradle`.
## Run
```powershell
flutter devices # confirm your phone is listed
flutter run # build & install on the connected phone
```
1. On first launch, enter the **API Server URL**, your **email/password**, and a
**device name**, then tap *Sign in & register device*.
- Emulator → host: use `http://10.0.2.2:8080`.
- Physical phone → use the host's LAN IP, e.g. `http://10.2.1.x:8080`
(the same network as the phone; make sure the API Server is reachable).
2. On the home screen, **grant SMS & phone permissions**, then **Start gateway**.
3. Send a test message from the Web App → it appears in the activity log and is
delivered via the phone. Texts received by the phone show up in the Web App
**Inbox**.
## How it maps to the API
| Action | Endpoint |
|---|---|
| Login | `POST /api/auth/login` (JWT) |
| Register device | `POST /api/mobile/v1/device` → device token |
| Poll pending | `GET /api/mobile/v1/messages` (marks them `Processed`) |
| Report state | `PATCH /api/mobile/v1/messages/{id}` (`Sent`/`Failed`) |
| Incoming SMS | `POST /api/mobile/v1/inbox` |
| Heartbeat | `POST /api/mobile/v1/ping` |
Pulled items carry a `type` of `sms` or `call`. For `call` the app places a
native phone call via `TelecomManager.placeCall` (needs `CALL_PHONE` — covered by
the phone permission) instead of sending SMS, then reports `Sent`.
`TelecomManager.placeCall` is used rather than `startActivity(ACTION_CALL)` so the
call still goes through when the screen is locked / the app is backgrounded
(Android blocks background activity starts, but not telecom-routed calls).
## Code layout
```
lib/
main.dart entry, bootstraps services, picks first screen
config.dart default API base + poll/ping intervals
models/message.dart outbound message model
services/
storage.dart persisted settings/tokens (shared_preferences)
api_client.dart API Server HTTP client
sms_service.dart platform-channel bridge (send + incoming stream)
gateway_service.dart the poll → send → report loop + inbox forwarding
screens/
login_screen.dart login + device registration
home_screen.dart start/stop, permissions, activity log
android_overlay/ native Android files to copy after `flutter create`
```
## Background & delivery reports (implemented)
- **Foreground service** (`GatewayForegroundService.kt`): starting the gateway
launches an ongoing-notification foreground service + partial wakelock, so the
poll/send loop keeps running while the screen is off or the app is backgrounded.
- **Delivery reports**: `MainActivity.sendSms` attaches `sent`/`delivered`
PendingIntents; `SmsStatusReceiver` forwards the outcome (tagged with the
message id) to Dart, which reports `Delivered`/`Failed` to the API Server.
## Known next steps (not yet implemented)
- **Survive full task removal / long Doze**: the foreground service covers
screen-lock, but surviving the user swiping the app away or hours of Doze would
need a dedicated background Dart isolate (e.g. `flutter_background_service`).
- **Push wake-up (FCM)**: register an FCM token at registration so the server can
wake the device instead of polling. Requires a Firebase project +
`google-services.json` + server-side FCM sending in the API Server.
- **MMS / data SMS**: only text SMS is implemented.