diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..eb2a835
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,25 @@
+version: 2
+updates:
+ - package-ecosystem: 'uv'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
+ day: 'monday'
+ time: '09:00'
+ timezone: 'Europe/Istanbul'
+ open-pull-requests-limit: 5
+ groups:
+ minor-patch:
+ update-types:
+ - 'minor'
+ - 'patch'
+ labels:
+ - 'dependencies'
+
+ - package-ecosystem: 'github-actions'
+ directory: '/'
+ schedule:
+ interval: 'monthly'
+ labels:
+ - 'dependencies'
+ - 'ci'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..bb32efb
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,36 @@
+name: CI
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+concurrency:
+ group: ci-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ test:
+ name: Lint · Test
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - uses: actions/checkout@v7
+
+ - uses: astral-sh/setup-uv@v7
+ with:
+ python-version: '3.12'
+ enable-cache: true
+
+ - name: Install dependencies
+ run: uv sync --frozen
+
+ - name: Lint (ruff)
+ run: uvx ruff check .
+
+ - name: Test (pytest)
+ run: uv run --frozen pytest -q
diff --git a/pyproject.toml b/pyproject.toml
index 4676b3b..f9e7591 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -29,3 +29,7 @@ build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/avimsin"]
+
+[tool.ruff.lint]
+# Errors only (pyflakes + syntax/runtime pycodestyle checks); style is not enforced.
+select = ["E4", "E7", "E9", "F"]
diff --git a/src/avimsin/alerts/watcher.py b/src/avimsin/alerts/watcher.py
index fc2bfd8..7f480b5 100644
--- a/src/avimsin/alerts/watcher.py
+++ b/src/avimsin/alerts/watcher.py
@@ -77,7 +77,7 @@ def detect_signals(
def format_signal(signal: Signal, threshold: int) -> str:
"""Sinyali Telegram mesajına çevirir."""
lines = [
- f"🏹 Avımsın sinyali",
+ "🏹 Avımsın sinyali",
f"Coin: {signal.coin}",
f"{len(signal.wallets)}/{threshold} smart wallet'a token girişi:",
"Transfer tabanlı gösterge; doğrulanmış swap/alım değildir.",
diff --git a/src/avimsin/scoring/engine.py b/src/avimsin/scoring/engine.py
index 32ef695..ff1a5b3 100644
--- a/src/avimsin/scoring/engine.py
+++ b/src/avimsin/scoring/engine.py
@@ -8,7 +8,7 @@
from dataclasses import dataclass
-from ..collectors.transfers import ZERO_ADDRESS, TransferEvent
+from ..collectors.transfers import ZERO_ADDRESS
from ..filters.base import WalletHistory
diff --git a/tests/fake_evm.py b/tests/fake_evm.py
index f40e39c..3af06cf 100644
--- a/tests/fake_evm.py
+++ b/tests/fake_evm.py
@@ -12,7 +12,6 @@
import httpx
from avimsin.chains.base import TRANSFER_TOPIC
-from avimsin.collectors.transfers import ZERO_ADDRESS
CHAIN_ID = 4663