crypto_alert_bot/CLAUDE.md
2026-02-26 16:30:56 +03:00

4.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# Run the app (requires CONFIG_PATH env var)
make run
# or explicitly:
CONFIG_PATH=./internal/config/local.yml go run ./cmd/app/main.go

# Build binary
go build -o crypto_alert_bot ./cmd/app/main.go

# Start PostgreSQL via Docker
docker compose up -d

# Create a new migration (NAME=migration_name)
make migrate_create NAME=add_alerts_user_id
# Edit the generated .up.sql and .down.sql in internal/repository/postgresql/migrations/
# Migrations run automatically on startup — no manual migrate up needed

There are no tests in this codebase.

Architecture

Go Telegram bot that monitors cryptocurrency prices from Bybit and notifies users when price thresholds are hit.

Layer structure (clean architecture)

cmd/app/main.go              → entrypoint: wires config, logger, storage, usecase, bot, alerter
internal/config/             → Config struct loaded from YAML via CONFIG_PATH env var
internal/entities/           → domain types: User, Pair, Price, Alert, Candle (no business logic)
internal/provider/           → Provider interface + Bybit REST implementation
internal/repository/         → Storage interface + PostgreSQL implementation (pgxpool)
internal/usecase/            → business logic; depends on repository.Storage interface
internal/service/alerter/    → background price-checking service; fires and disables alerts
internal/bot/telegram/       → Telegram bot: command handlers, inline keyboards, multi-step flows
internal/logger/             → wraps charmbracelet/log returning *slog.Logger

Key design decisions

  • Config: YAML at $CONFIG_PATH. Local dev config at internal/config/local.yml. Sections: logger, postgresql, telegram, providers.bybit.
  • Migrations: Embedded via go:embed in internal/repository/postgresql/migrations/embed.go, applied automatically on startup via golang-migrate.
  • Alerter service (internal/service/alerter/): Runs a goroutine on a 1-minute ticker. On each tick, it fetches OHLC candles (not live price) for the gap since lastCheckedAt, using selectCandleInterval to pick the coarsest interval that fits in one Bybit request (≤ 1000 candles). Alerts trigger if any candle's High/Low crosses the target. lastCheckedAt is persisted to alerter_state so missed candles are rechecked after restarts.
  • In-memory alert cache (alertsCache): Keyed by AlertID and InstrumentID. Only instruments with cached alerts have candles fetched. Cache is loaded from DB on startup via LoadAlerts, and kept in sync via AddAlert/RemoveAlert when the bot creates/removes alerts.
  • Circular dependency between Bot and Alerter: resolved by constructing both independently and injecting Alerter into Bot via bot.SetAlerter(al) after both are created. Bot implements the alerter.Notifier interface (NotifyAlert), which the Alerter uses to send Telegram messages when an alert fires.
  • Alert condition auto-detection: When a user sets a target price, the condition (above/below) is inferred automatically — if target ≥ current ask → above, else → below. Candle High is checked for above, candle Low for below.
  • Bot user state: Per-user userState (protected by sync.Mutex) tracks multi-step flows (stepAddAlertPrice, stepEditAlertPrice). State is reset on completion, error, or /cancel.
  • Decimal arithmetic: Prices use github.com/shopspring/decimal to avoid floating-point precision issues. Alert prices are stored as text in PostgreSQL.
  • Storage interface (internal/repository/repository.go): Decouples usecase layer from PostgreSQL; implement this to swap databases.

Database schema

  • users — Telegram users (UUID PK, unique telegram_id bigint)
  • currency — currency symbols (e.g. BTC, USDT); pre-seeded in migration
  • instrument — trading pairs (base + quote currency FK); pre-seeded with BTC/USDT, ETH/USDT, SOL/USDT
  • alert — price alerts per user/instrument with active flag and alert_condition enum; deactivated when triggered
  • alerter_state — single-row table storing last_alert_check timestamptz; persists the timestamp across restarts so the alerter can fetch candles for any missed interval

Bot commands / flows

  • /start — register user
  • /instruments (or "Instruments" button) — list available trading pairs
  • /add_alert (or "Add Alert" button) — multi-step: select instrument → enter price → alert created
  • /my_alerts (or "My Alerts" button) — list active alerts with inline Edit/Remove buttons
  • /cancel — abort current multi-step flow