Files
dsutanto 1c7b78b580
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / build (push) Canceled after 0s
ai-dev: graceful shutdown, tests, stdlib context, lint/CI, error logging
- T1: SIGTERM/SIGINT → client.Disconnect(250) → os.Exit(0)
- T2: 11 tests with miniredis mock (handleMessage, getEnv, parseInt, randomString)
- T3: golang.org/x/net/context → stdlib context, math/rand → math/rand/v2
- T4: .golangci.yml + .github/workflows/ci.yml
- T5: Redis SETEX error log includes key and memberID
- Dockerfile: add git for go mod tidy
2026-09-03 12:52:21 +07:00

5.2 KiB

Repository Guidelines

Project Overview

MQTT presence service written in Go. Subscribes to an MQTT topic (presence), parses incoming messages (memberID;...), and stores presence data in Redis with a TTL. Purpose: real-time member presence tracking for the Backone platform (port of a Django/Python original).

Architecture & Data Flow

MQTT Broker ──publish──▶ MQTT Client (paho.mqtt)
                              │
                              ▼
                        handleMessage()
                        - parse memberID from payload (split on ";")
                        - truncate memberID to 50 chars
                        - build JSON {mqtt, ts}
                        - SETEX to Redis key "presence:<memberID>"
                              │
                              ▼
                           Redis

Single goroutine architecture. main() connects Redis, connects MQTT, subscribes on connect, then blocks forever (select {}). All message handling is synchronous in the MQTT callback.

Key Directories

backone-manage-go/
├── mqtt_presence_redis_go/     # ALL source code lives here
│   ├── mqtt_presence_redis_go.go  # Single-file application (package main)
│   ├── go.mod / go.sum
│   └── Dockerfile
├── .gitignore
└── README.md

No subpackages, no internal/, no cmd/. The entire application is one .go file.

Development Commands

# Build
cd mqtt_presence_redis_go && go build -o mqtt_presence_redis_go mqtt_presence_redis_go.go

# Run locally (requires MQTT broker + Redis running)
cd mqtt_presence_redis_go && go run mqtt_presence_redis_go.go

# Docker build
cd mqtt_presence_redis_go && docker build -t mqtt-presence-redis-go .

# No Makefile, no CI pipeline, no lint config

Code Conventions & Common Patterns

Configuration

  • All config via environment variables — no config files, no viper/yaml.
  • Pattern: getEnv("ENV_KEY", "default") helper at package level.
  • Env vars: MQTT_HOST, MQTT_PORT, MQTT_USER, MQTT_PASS, MQTT_TOPIC_PRESENCE, MQTT_REDIS_HOST, MQTT_REDIS_PORT, MQTT_REDIS_DB, MQTT_REDIS_PREFIX, MQTT_REDIS_SETEX, MQTT_REDIS_PASSWORD.

Naming

  • Package-level vars: camelCase (e.g. mqttHost, redisPrefix).
  • Functions: camelCase (e.g. handleMessage, getEnv, parseInt, randomString).
  • Constants: no const block used; inline defaults.
  • File naming: <package_name>.go matches module directory.

Error Handling

  • log.Fatalf for startup failures (Redis ping, MQTT connect).
  • log.Printf + return for runtime errors (message handling).
  • No custom error types; no error wrapping.

Dependencies

  • github.com/eclipse/paho.mqtt.golang — MQTT client
  • github.com/go-redis/redis/v8 — Redis client
  • golang.org/x/net/context — context (stdlib context preferred in Go 1.7+)

Patterns

  • No interfaces, no DI, no dependency injection.
  • No middleware, no routing — single topic subscription.
  • No graceful shutdown handling (select {} blocks forever).
  • math/rand for client ID (not crypto/rand) — acceptable for non-security use.
  • JSON marshaling via map[string]interface{} — no typed struct for presence data.

Important Files

File Purpose
mqtt_presence_redis_go/mqtt_presence_redis_go.go Entire application
mqtt_presence_redis_go/go.mod Module: git.proit.id/dsutanto/backone-manage-go/mqtt_presence_redis_go, Go 1.24.3
mqtt_presence_redis_go/Dockerfile Multi-stage build: golang:1.24-alpine → alpine:3.20

Runtime/Tooling Preferences

  • Go 1.24.3 (specified in go.mod and Dockerfile)
  • No package manager beyond go mod
  • No linter configured (no .golangci.yml)
  • No formatter config (standard gofmt assumed)
  • No CI/CD — deployment via Docker only
  • Redis 8 client (go-redis/v8) — requires Redis 6+ for SETEX
  • MQTT 3.1.1 via paho client

Testing & QA

  • No tests exist. No *_test.go files anywhere.
  • No test framework configured.
  • No coverage tooling, no test scripts.
  • If adding tests: use standard testing package. Table-driven tests for handleMessage message parsing logic. Mock Redis with miniredis or go-redis/mock. Mock MQTT with a test broker or interface-based mock.

Key Observations for AI Assistants

  1. Single-file architecture — all changes go in mqtt_presence_redis_go.go. No cross-file imports to track.
  2. No tests — any refactor carries risk. Consider adding tests for handleMessage before significant changes.
  3. No graceful shutdown — select {} means no signal handling, no MQTT disconnect on SIGTERM. Docker sends SIGTERM then SIGKILL.
  4. golang.org/x/net/context is used instead of stdlib context — this is a legacy import; stdlib context is standard since Go 1.7.
  5. Payload parsing is fragile: splits on ;, takes first element, truncates to 50 chars. No validation of payload format.
  6. Redis key pattern: presence:<memberID> with configurable prefix and TTL (default 86400s / 24h).
  7. The comment about Django indicates this is a port — check Python original for behavioral reference if behavior questions arise.