httpSMS is a service that turns an Android phone into an SMS gateway via an HTTP API. This is a monorepo with three components:
api/— Go backend (Fiber, GORM, PostgreSQL)web/— Nuxt 2 frontend (Vue 2, Vuetify 2, TypeScript)android/— Native Android app (Kotlin)
cd api
# Development with hot-reload
air
# Build
go build -o ./tmp/main.exe .
# Run tests
go test ./...
# Run a single test
go test ./pkg/services/ -run TestMessageService
# Generate Swagger docs (required after changing API annotations)
swag init --requiredByDefault --parseDependency --parseInternal
# Pre-commit hooks run: go-fumpt, go-imports, go-lint, go-mod-tidycd web
# Install dependencies
pnpm install
# Development server (port 3000)
pnpm dev
# Lint (eslint + stylelint + prettier)
pnpm lint
# Auto-fix lint issues
pnpm lintfix
# Run tests (Jest)
pnpm test
# Static site generation (production build)
pnpm run generate
# Regenerate TypeScript API models from Swagger
pnpm api:modelscd android
# Build
./gradlew build
# Debug APK
./gradlew assembleDebug
# Release APK
./gradlew assembleRelease# Start all services (PostgreSQL, Redis, API, Web)
docker compose up --build
# API at localhost:8000, Web at localhost:3000The API uses a DI container (pkg/di/container.go) that lazily initializes all services as singletons. The layered architecture flows as:
Handlers → Services → Repositories → GORM/PostgreSQL
- Handlers (
pkg/handlers/) — Fiber HTTP handlers. Each has aRegisterRoutes()method and embeds a basehandlerstruct with standardized response methods (responseBadRequest,responseNotFound, etc.). - Services (
pkg/services/) — Business logic. Orchestrate repositories and dispatch events. - Repositories (
pkg/repositories/) — Data access via GORM. Interfaces defined alongside GORM implementations (prefixedgorm*). - Validators (
pkg/validators/) — One validator per handler, returnurl.Valuesfor field errors. - Entities (
pkg/entities/) — Domain models, auto-migrated by GORM.
Event system: Uses CloudEvents spec (cloudevents/sdk-go). Events defined in pkg/events/ (31 event types). Listeners in pkg/listeners/ process events either synchronously or via Google Cloud Tasks queue (emulator mode for local dev).
Entry point: main.go loads .env in local mode, creates the DI container, and starts Fiber on APP_PORT.
- State management: Single Vuex store (
store/index.ts) — actions make API calls via Axios, mutations update state, getters expose computed values. - Components: Use
vue-property-decoratorclass syntax with@Component,@Prop,@Watchdecorators. - API client: Axios configured in
plugins/axios.tswith Firebase bearer token auth andx-api-keyheader support. - API models: TypeScript types in
models/are auto-generated from the Swagger spec viaswagger-typescript-api. - Auth: Firebase Authentication (Email/Password, Google, GitHub) with
authandguestmiddleware for route guards. - Real-time: Pusher.js for live message updates.
- No MVVM/Clean Architecture — uses a flat package structure with Activities, Services, BroadcastReceivers, and WorkManager tasks.
- FCM integration:
MyFirebaseMessagingServicereceives push notifications → schedulesSendSmsWorkervia WorkManager → fetches message from API → sends SMS. - Dual SIM support: Independent settings per SIM via
Settingssingleton (SharedPreferences). - HTTP client: OkHttp with
x-api-keyauthentication against the API. - Encryption: AES-256/CFB with SHA-256 key derivation (
Encrypter.kt).
- Error handling: Use
github.com/palantir/stacktrace— wrap errors withstacktrace.Propagate(err, "context")orstacktrace.PropagateWithCode(). Never return bare errors. - Database queries: Always use GORM query builder with context propagation (
repository.db.WithContext(ctx)). No raw SQL. - Route registration: Each handler defines
RegisterRoutes()called from the DI container. Routes follow REST conventions under/v1/. - Middleware chain: HTTP Logger → OpenTelemetry → CORS → Request Logger → Bearer Auth → API Key Auth.
- Observability: All layers are instrumented with OpenTelemetry (Fiber, GORM, Redis). Pass
loggerandtracerto constructors. - Code formatting:
go-fumpt(notgofmt), enforced via pre-commit hooks.
- Formatting: No semicolons, single quotes, 2-space indentation (Prettier + ESLint).
- Component style: Class-based with
vue-property-decorator, not Options API (though some pages useVue.extend()). - Store pattern: Actions handle async API calls and commit mutations. Access store from components via
this.$store.
- API calls: Use
HttpSmsApiServicesingleton (staticcreate()factory). OkHttp client withx-api-keyheader. - Background work: Use WorkManager for tasks that must survive process death. Direct
Thread { }for lightweight background ops. - State:
Settingsobject (SharedPreferences singleton) for all persistent state. - Phone number formatting: Use
libphonenumberfor E.164 format validation.