d6956395c8
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>
155 lines
5.4 KiB
Markdown
155 lines
5.4 KiB
Markdown
# gsmnode — API Server
|
|
|
|
Go service that is the **single trusted entry point** in front of PocketBase.
|
|
The Web App and Phone App talk only to this server; it performs all PocketBase
|
|
access as a superuser and enforces ownership in application logic.
|
|
|
|
```
|
|
Web App ─┐
|
|
├─► API Server (:8080) ─► PocketBase (10.2.1.10:8028)
|
|
Phone App ─┘
|
|
```
|
|
|
|
The server root (`GET /`) serves a gsmnode-branded **web panel**: a live health
|
|
readout plus a quick reference of both API audiences. Open
|
|
http://localhost:8080/ in a browser to check the server at a glance.
|
|
|
|
The panel is a **Vue 3 + Tailwind v4** app in [`panel/`](panel/), built into
|
|
`internal/api/dist` and embedded into the Go binary at compile time:
|
|
|
|
```powershell
|
|
cd panel
|
|
npm install
|
|
npm run build # outputs to ../internal/api/dist
|
|
cd ..; go build -o api-server.exe ./cmd/server # embeds the fresh dist
|
|
```
|
|
|
|
For panel development with hot reload (proxies `/api` to a running server on
|
|
`:8080`): `cd panel; npm run dev` → http://localhost:5174.
|
|
|
|
## Requirements
|
|
|
|
- Go 1.26+ (`go version`)
|
|
- A reachable PocketBase v0.23+ instance and its **superuser** credentials
|
|
- Node 18+ (only for the setup scripts)
|
|
|
|
## 1. Configure
|
|
|
|
```powershell
|
|
Copy-Item .env.example .env
|
|
# edit .env: set PB_ADMIN_EMAIL, PB_ADMIN_PASSWORD, and a strong JWT_SECRET
|
|
```
|
|
|
|
| Variable | Purpose | Default |
|
|
|---|---|---|
|
|
| `API_ADDR` | Listen address | `:8080` |
|
|
| `POCKETBASE_URL` | PocketBase base URL | `http://10.2.1.10:8028` |
|
|
| `PB_ADMIN_EMAIL` / `PB_ADMIN_PASSWORD` | PocketBase superuser login | — (required) |
|
|
| `JWT_SECRET` | Signs client JWTs | dev placeholder |
|
|
| `JWT_ACCESS_TTL` | Access-token lifetime | `24h` |
|
|
| `CORS_ALLOW_ORIGINS` | Comma list, or `*` | `*` |
|
|
|
|
## 2. Set up PocketBase collections
|
|
|
|
Creates/updates `devices`, `messages`, `inbox`, `webhooks` (the default `users`
|
|
auth collection is reused). Idempotent.
|
|
|
|
```powershell
|
|
$env:POCKETBASE_URL="http://10.2.1.10:8028"
|
|
$env:PB_ADMIN_EMAIL="admin@example.com"
|
|
$env:PB_ADMIN_PASSWORD="your-password"
|
|
node scripts/setup-pocketbase.mjs
|
|
```
|
|
|
|
Create a login user:
|
|
|
|
```powershell
|
|
node scripts/create-user.mjs user@example.com "user-password" "Display Name"
|
|
```
|
|
|
|
## 3. Run
|
|
|
|
```powershell
|
|
./scripts/Run-ApiServer.ps1
|
|
# or: go run ./cmd/server
|
|
```
|
|
|
|
Health check: `GET http://localhost:8080/api/health`.
|
|
|
|
## API
|
|
|
|
### Authentication scheme
|
|
|
|
- **Client API** (`/api/...`): `Authorization: Bearer <JWT>` from `/api/auth/login`.
|
|
Used by the Web App and integrators.
|
|
- **Mobile API** (`/api/mobile/...`): `Authorization: Bearer <device_token>`
|
|
returned by device registration. Used by the Phone App.
|
|
|
|
### Client / 3rd-party endpoints
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/health` | Readiness probe (public) |
|
|
| `POST` | `/api/auth/login` | `{email, password}` → JWT + user |
|
|
| `POST` | `/api/auth/refresh` | New JWT (auth) |
|
|
| `GET` | `/api/auth/me` | Current user |
|
|
| `GET` | `/api/devices` | List your devices |
|
|
| `DELETE` | `/api/devices/{id}` | Remove a device |
|
|
| `POST` | `/api/messages` | Enqueue SMS `{phone_numbers[], text_message, device_id?, sim_number?, schedule_at?}` |
|
|
| `POST` | `/api/calls` | Enqueue a phone call `{phone_number, device_id?}` |
|
|
| `GET` | `/api/messages` | List messages (`?status=&device_id=&type=&page=&per_page=`) |
|
|
| `GET` | `/api/messages/{id}` | Message state |
|
|
| `GET` | `/api/inbox` | Received SMS |
|
|
| `GET` | `/api/webhooks` | List webhooks |
|
|
| `POST` | `/api/webhooks` | Register `{event, url, device_id?}` |
|
|
| `DELETE` | `/api/webhooks/{id}` | Delete webhook |
|
|
|
|
### Mobile / device endpoints
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `POST` | `/api/mobile/v1/device` | Register device (auth: **user JWT**) → returns `auth_token` |
|
|
| `POST` | `/api/mobile/v1/ping` | Heartbeat (auth: device token) |
|
|
| `GET` | `/api/mobile/v1/messages` | Pull pending messages; marks them `Processed` |
|
|
| `PATCH` | `/api/mobile/v1/messages/{id}` | Report `{status, error?}` (`Sent`/`Delivered`/`Failed`) |
|
|
| `POST` | `/api/mobile/v1/inbox` | Report received SMS `{phone_number, message, received_at?}` |
|
|
|
|
### Message lifecycle
|
|
|
|
`Pending` → (device pulls) `Processed` → `Sent` → `Delivered`, or `Failed`.
|
|
|
|
Calls are stored as messages with `type: "call"` (SMS is `type: "sms"`) and flow
|
|
through the same pull/report pipeline. The device dials the number natively and
|
|
reports `Sent` (a call has no delivery report) or `Failed`.
|
|
|
|
### Webhook events
|
|
|
|
`sms:received`, `sms:sent`, `sms:delivered`, `sms:failed`. Delivered as
|
|
`POST {event, device_id, payload, created_at}` to the registered URL.
|
|
|
|
## Quick smoke test
|
|
|
|
```powershell
|
|
# log in
|
|
$login = curl -s -X POST http://localhost:8080/api/auth/login `
|
|
-H "Content-Type: application/json" `
|
|
-d '{"email":"user@example.com","password":"user-password"}' | ConvertFrom-Json
|
|
$token = $login.access_token
|
|
|
|
# register a device (as the phone app would)
|
|
curl -s -X POST http://localhost:8080/api/mobile/v1/device `
|
|
-H "Authorization: Bearer $token" -H "Content-Type: application/json" `
|
|
-d '{"device_id":"test-1","name":"Test Phone","platform":"android"}'
|
|
```
|
|
|
|
## Project layout
|
|
|
|
```
|
|
cmd/server/main.go entry point, wiring, graceful shutdown
|
|
internal/config env/.env configuration
|
|
internal/pb PocketBase REST client (superuser)
|
|
internal/auth JWT issue/verify, device token generation
|
|
internal/api router, middleware, handlers
|
|
scripts/ PocketBase setup + run helpers
|
|
```
|