Skip to content

Latest commit

 

History

History
141 lines (96 loc) · 5.52 KB

File metadata and controls

141 lines (96 loc) · 5.52 KB

Copilot Instructions for httpSMS

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)

Build, Test, and Lint Commands

API (Go)

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-tidy

Web (Nuxt/Vue)

cd 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:models

Android (Kotlin)

cd android

# Build
./gradlew build

# Debug APK
./gradlew assembleDebug

# Release APK
./gradlew assembleRelease

Docker (full stack)

# Start all services (PostgreSQL, Redis, API, Web)
docker compose up --build
# API at localhost:8000, Web at localhost:3000

Architecture

API — Layered Architecture with Event-Driven Processing

The 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 a RegisterRoutes() method and embeds a base handler struct 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 (prefixed gorm*).
  • Validators (pkg/validators/) — One validator per handler, return url.Values for 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.

Web — Nuxt 2 Static SPA

  • 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-decorator class syntax with @Component, @Prop, @Watch decorators.
  • API client: Axios configured in plugins/axios.ts with Firebase bearer token auth and x-api-key header support.
  • API models: TypeScript types in models/ are auto-generated from the Swagger spec via swagger-typescript-api.
  • Auth: Firebase Authentication (Email/Password, Google, GitHub) with auth and guest middleware for route guards.
  • Real-time: Pusher.js for live message updates.

Android — Task-Oriented, Event-Driven

  • No MVVM/Clean Architecture — uses a flat package structure with Activities, Services, BroadcastReceivers, and WorkManager tasks.
  • FCM integration: MyFirebaseMessagingService receives push notifications → schedules SendSmsWorker via WorkManager → fetches message from API → sends SMS.
  • Dual SIM support: Independent settings per SIM via Settings singleton (SharedPreferences).
  • HTTP client: OkHttp with x-api-key authentication against the API.
  • Encryption: AES-256/CFB with SHA-256 key derivation (Encrypter.kt).

Key Conventions

API (Go)

  • Error handling: Use github.com/palantir/stacktrace — wrap errors with stacktrace.Propagate(err, "context") or stacktrace.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 logger and tracer to constructors.
  • Code formatting: go-fumpt (not gofmt), enforced via pre-commit hooks.

Web (Vue/TypeScript)

  • Formatting: No semicolons, single quotes, 2-space indentation (Prettier + ESLint).
  • Component style: Class-based with vue-property-decorator, not Options API (though some pages use Vue.extend()).
  • Store pattern: Actions handle async API calls and commit mutations. Access store from components via this.$store.

Android (Kotlin)

  • API calls: Use HttpSmsApiService singleton (static create() factory). OkHttp client with x-api-key header.
  • Background work: Use WorkManager for tasks that must survive process death. Direct Thread { } for lightweight background ops.
  • State: Settings object (SharedPreferences singleton) for all persistent state.
  • Phone number formatting: Use libphonenumber for E.164 format validation.