diff --git a/README.md b/README.md index 69f3daf..7ca9513 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,26 @@ # Email-OpenClaw Bridge -Tự động xử lý email bằng OpenClaw AI theo luồng: +Bridge tự động xử lý email bằng OpenClaw AI theo luồng: -``` -Ingress (IMAP) → Safety Checks → External Rules → Apply Context → Dispatch (OpenClaw) → Callback → Egress (SMTP reply) +```text +Ingress (IMAP) → Safety Checks → External Rules → Dispatch (OpenClaw) → Callback → Egress (SMTP reply) ``` -## Tính năng +README này tập trung vào onboarding và vận hành cơ bản. Chi tiết kỹ thuật hiện hành được tách sang `docs/architecture/overview.md`. -- **IMAP IDLE** — theo dõi mailbox realtime, nhận email mới tức thì -- **Threading** — giữ nguyên email thread qua `In-Reply-To` / `References` -- **Idempotency** — chống duplicate theo `message_id` -- **Anti-loop & Whitelist** — bỏ qua email từ chính hệ thống, chỉ xử lý sender được phép -- **External Rules** — pipeline configurable: whitelist, blocklist, và rule metadata cho dispatch -- **Retry** — tối đa 3 lần với backoff 1s → 5s → 15s cho cả OpenClaw và SMTP -- **Stateful** — SQLite lưu trạng thái pipeline, không mất dữ liệu khi restart +## Tính năng chính -## Kiến trúc +- Theo dõi mailbox realtime bằng IMAP IDLE +- Giữ thread email qua `In-Reply-To` và `References` +- Chống duplicate theo `message_id` +- Chặn anti-loop và hỗ trợ whitelist/blocklist +- Gửi callback vào bridge rồi phản hồi lại qua SMTP +- Lưu trạng thái pipeline bằng SQLite để không mất tiến trình khi restart -``` -cmd/bridge/main.go Entrypoint -internal/ -├── config/ Đọc cấu hình từ .env -├── database/ SQLite + GORM, auto-migrate -├── logging/ Structured JSON logging (slog) -├── api/ HTTP server (Gin): health checks, webhook callback -├── mail/ IMAP ingress + SMTP egress -└── ai_client/ OpenClaw HTTP dispatch -``` - -## Yêu cầu +## Yêu cầu tối thiểu - Go 1.23+ -- Docker & Docker Compose (cho deploy) +- Docker và Docker Compose nếu chạy bằng container ## Quickstart @@ -43,7 +31,7 @@ cp .env.example .env # Sửa .env với thông tin IMAP/SMTP/OpenClaw thực tế ``` -### 2. Chạy local (development) +### 2. Chạy local ```bash go run ./cmd/bridge @@ -56,51 +44,39 @@ docker compose up -d docker logs -f claw-email-bridge ``` -## Cấu hình (.env) +## Cấu hình `.env` | Biến | Bắt buộc | Mô tả | |---|:---:|---| | `IMAP_HOST` | ✅ | IMAP server hostname | -| `IMAP_PORT` | ✅ | IMAP port (thường `993`) | +| `IMAP_PORT` | ✅ | IMAP port, thường là `993` | | `IMAP_USER` | ✅ | IMAP username | | `IMAP_PASS` | ✅ | IMAP password | | `SMTP_HOST` | ✅ | SMTP server hostname | -| `SMTP_PORT` | ✅ | SMTP port (thường `587`) | +| `SMTP_PORT` | ✅ | SMTP port, thường là `587` | | `SMTP_USER` | ✅ | SMTP username | | `SMTP_PASS` | ✅ | SMTP password | | `OPENCLAW_URL` | ✅ | OpenClaw API endpoint | -| `OPENCLAW_API_KEY` | | OpenClaw API key (nếu cần) | +| `OPENCLAW_API_KEY` | | OpenClaw API key nếu cần | | `BRIDGE_CALLBACK_TOKEN` | ✅ | Token xác thực webhook callback | -| `SYSTEM_EMAIL` | ✅ | Email của hệ thống (dùng cho anti-loop) | +| `SYSTEM_EMAIL` | ✅ | Email của bridge, dùng cho anti-loop | | `WHITELIST_EMAILS` | | Danh sách email được phép, phân cách bằng dấu phẩy | -| `IMAP_PROXY_URL` | | SOCKS5 proxy cho IMAP (vd: `socks5://user:pass@host:port`) | -| `LISTEN_ADDR` | | Địa chỉ bind HTTP server cục bộ (mặc định `:8080`) | -| `CALLBACK_BASE_URL` | | Base URL public để tạo `callback_url` gửi OpenClaw (mặc định theo `LISTEN_ADDR`, ví dụ `http://localhost:8080`) | +| `BLOCKLIST_EMAILS` | | Danh sách email bị chặn, phân cách bằng dấu phẩy | +| `IMAP_PROXY_URL` | | Proxy cho IMAP, hỗ trợ `socks5://`, `http://`, `https://` | +| `LISTEN_ADDR` | | Địa chỉ bind HTTP server, mặc định `:8080` | +| `CALLBACK_BASE_URL` | | Base URL public để tạo `callback_url`, mặc định suy ra từ `LISTEN_ADDR` | -## Health Checks +## Health checks | Endpoint | Mục đích | |---|---| -| `GET /healthz` | Liveness — process còn sống | -| `GET /readyz` | Readiness — DB writable + config hợp lệ | +| `GET /healthz` | Liveness check, xác nhận process còn sống | +| `GET /readyz` | Readiness check, xác nhận DB writable và config bắt buộc hợp lệ | -## Pipeline trạng thái +## Đọc thêm -``` -RECEIVED → AI_PROCESSING → CALLBACK_DONE → COMPLETED - ↓ ↓ ↓ - IGNORED FAILED SMTP_RETRYING → FAILED -``` - -## Công nghệ - -| Thành phần | Thư viện | -|---|---| -| HTTP Server | [gin-gonic/gin](https://github.com/gin-gonic/gin) | -| Database | [GORM](https://gorm.io) + [modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite) (pure Go, no CGO) | -| IMAP | [emersion/go-imap](https://github.com/emersion/go-imap) | -| Logging | [log/slog](https://pkg.go.dev/log/slog) (stdlib) | -| Config | [joho/godotenv](https://github.com/joho/godotenv) | +- [Technical overview](docs/architecture/overview.md) +- [Architecture Decision Records](docs/adr/README.md) ## License diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md new file mode 100644 index 0000000..eece8e6 --- /dev/null +++ b/docs/architecture/overview.md @@ -0,0 +1,101 @@ +# Technical Overview + +## Mục đích + +Tài liệu này là technical overview hiện hành của `Email-OpenClaw Bridge`. `README.md` chỉ giữ phần onboarding và vận hành cơ bản; phần này giữ các chi tiết kỹ thuật bền vững hơn về flow, package layout, state machine và công nghệ chính. + +## Luồng xử lý + +Bridge xử lý email theo pipeline sau: + +```text +Ingress (IMAP) → Safety Checks → External Rules → Dispatch (OpenClaw) → Callback → Egress (SMTP reply) +``` + +Các giai đoạn runtime chính: + +1. IMAP watcher theo dõi `INBOX` bằng IDLE và fetch email chưa đọc. +2. Safety checks loại bỏ mail từ chính hệ thống và chặn duplicate theo `message_id`. +3. External rules pipeline áp whitelist/blocklist và sinh `DispatchContext`. +4. Thread resolution gắn `thread_id` dựa trên quan hệ email đã biết. +5. Task được lưu vào SQLite với trạng thái pipeline hiện tại. +6. OpenClaw nhận request xử lý và callback về bridge. +7. Callback cập nhật `AIResponse`, sau đó bridge gửi phản hồi lại qua SMTP. + +## Package layout + +- `cmd/bridge` + - Entrypoint của process, wiring config, DB, IMAP watcher, HTTP router và SMTP egress. +- `internal/config` + - Đọc `.env`, chuẩn hóa default như `LISTEN_ADDR`, `CALLBACK_BASE_URL`, và validate biến bắt buộc. +- `internal/database` + - Khởi tạo SQLite qua GORM, định nghĩa `Task` model, repository helpers và health check DB. +- `internal/mail` + - Chứa IMAP ingress, thread resolution, proxy support cho IMAP, retry logic và SMTP egress. +- `internal/rules` + - External rules pipeline, whitelist/blocklist rules và rule metadata dùng cho dispatch. +- `internal/ai_client` + - HTTP client gọi OpenClaw và gửi metadata/callback information ra ngoài. +- `internal/api` + - HTTP router cho `healthz`, `readyz` và `POST /callback`. +- `internal/logging` + - Helper tạo structured logger theo `task_uuid`, `thread_id`, `message_id`. + +## Task state machine + +Task được lưu trong SQLite và đi qua các trạng thái sau: + +```text +RECEIVED → AI_PROCESSING → CALLBACK_DONE → COMPLETED + ↓ ↓ ↓ + IGNORED FAILED SMTP_RETRYING → FAILED +``` + +- `IGNORED` + - Mail bị anti-loop, duplicate, hoặc bị external rules reject. +- `RECEIVED` + - Task đã được lưu và sẵn sàng dispatch. +- `AI_PROCESSING` + - Request đã được gửi sang OpenClaw. +- `CALLBACK_DONE` + - Callback hợp lệ đã cập nhật `AIResponse`. +- `SMTP_RETRYING` + - Đang retry gửi email phản hồi. +- `COMPLETED` + - Toàn bộ pipeline kết thúc thành công. +- `FAILED` + - Hết retry hoặc gặp lỗi không recoverable. + +## HTTP và health behavior + +- `GET /healthz` + - Trả `200 {"status":"ok"}` nếu process đang sống. +- `GET /readyz` + - Trả `200` khi DB writable và `BRIDGE_CALLBACK_TOKEN` có mặt. + - Trả `503` nếu DB không writable hoặc config bắt buộc cho callback chưa sẵn sàng. +- `POST /callback` + - Yêu cầu header `X-Bridge-Token`. + - Nhận payload callback từ OpenClaw, cập nhật task và kích hoạt SMTP egress bất đồng bộ. + +## Công nghệ chính + +- Go + - Runtime chính, phù hợp với service nhỏ gọn và dễ deploy. +- SQLite + GORM + - Giữ state cục bộ đơn giản, không cần service DB riêng cho v1. +- `github.com/emersion/go-imap/v2` + - Hỗ trợ IMAP IDLE và xử lý mailbox theo flow hiện tại. +- `gin-gonic/gin` + - Cung cấp HTTP router tối giản cho health endpoints và callback. +- `log/slog` + - Structured logging chuẩn thư viện chuẩn của Go. + +## ADR liên quan + +- [ADR 0001: IMAP thread resolution prefers In-Reply-To and falls back to References](../adr/0001-imap-thread-resolution.md) +- [ADR 0002: Ingress uses a configurable external rules pipeline before dispatch](../adr/0002-external-rules-pipeline.md) +- [ADR index](../adr/README.md) + +## Tài liệu lịch sử + +- Historical design input: [docs/specs/2026-04-24-email-openclaw-bridge-design.md](../specs/2026-04-24-email-openclaw-bridge-design.md)