4.6 KiB
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 atinternal/config/local.yml. Sections:logger,postgresql,telegram,providers.bybit. - Migrations: Embedded via
go:embedininternal/repository/postgresql/migrations/embed.go, applied automatically on startup viagolang-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 sincelastCheckedAt, usingselectCandleIntervalto pick the coarsest interval that fits in one Bybit request (≤ 1000 candles). Alerts trigger if any candle's High/Low crosses the target.lastCheckedAtis persisted toalerter_stateso missed candles are rechecked after restarts. - In-memory alert cache (
alertsCache): Keyed byAlertIDandInstrumentID. Only instruments with cached alerts have candles fetched. Cache is loaded from DB on startup viaLoadAlerts, and kept in sync viaAddAlert/RemoveAlertwhen the bot creates/removes alerts. - Circular dependency between
BotandAlerter: resolved by constructing both independently and injectingAlerterintoBotviabot.SetAlerter(al)after both are created.Botimplements thealerter.Notifierinterface (NotifyAlert), which theAlerteruses 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 forabove, candle Low forbelow. - Bot user state: Per-user
userState(protected bysync.Mutex) tracks multi-step flows (stepAddAlertPrice,stepEditAlertPrice). State is reset on completion, error, or/cancel. - Decimal arithmetic: Prices use
github.com/shopspring/decimalto avoid floating-point precision issues. Alert prices are stored astextin PostgreSQL. - Storage interface (
internal/repository/repository.go): Decouples usecase layer from PostgreSQL; implement this to swap databases.
Database schema
users— Telegram users (UUID PK, uniquetelegram_id bigint)currency— currency symbols (e.g. BTC, USDT); pre-seeded in migrationinstrument— trading pairs (base + quote currency FK); pre-seeded with BTC/USDT, ETH/USDT, SOL/USDTalert— price alerts per user/instrument withactiveflag andalert_conditionenum; deactivated when triggeredalerter_state— single-row table storinglast_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