71 lines
4.6 KiB
Markdown
71 lines
4.6 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# 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
|