Full pipeline: IMAP ingress -> OpenClaw dispatch -> callback -> SMTP reply. SQLite stateful storage with idempotency, threading, and retry logic. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
92 lines
3.2 KiB
Markdown
92 lines
3.2 KiB
Markdown
# Checkpoint 001 — Project Scaffold
|
|
|
|
**Ngày:** 2026-04-24
|
|
**Trạng thái:** ✅ Hoàn thành
|
|
**Verify:** `go build ./...` thành công, không lỗi
|
|
|
|
---
|
|
|
|
## Việc đã làm
|
|
|
|
### 1. Khởi tạo Go module
|
|
```
|
|
go mod init github.com/thuanle/claw-email
|
|
```
|
|
|
|
### 2. Tạo cấu trúc thư mục
|
|
|
|
```
|
|
claw-email/
|
|
├── cmd/bridge/main.go # Entrypoint
|
|
├── internal/
|
|
│ ├── config/config.go # Đọc .env, validate required vars
|
|
│ ├── database/
|
|
│ │ ├── database.go # Open SQLite + auto-migrate + health check
|
|
│ │ └── models.go # Task model (đầy đủ schema từ requirements)
|
|
│ ├── logging/logger.go # Structured JSON logging (slog)
|
|
│ ├── api/router.go # Gin router: /healthz, /readyz
|
|
│ ├── mail/mail.go # [stub] IMAP ingress + SMTP egress
|
|
│ └── ai_client/client.go # [stub] OpenClaw HTTP dispatch
|
|
├── .env.example
|
|
├── .gitignore
|
|
├── Dockerfile # Multi-stage, CGO_ENABLED=0
|
|
├── docker-compose.yml # Named volume cho SQLite
|
|
├── go.mod / go.sum
|
|
└── requirements.md
|
|
```
|
|
|
|
### 3. Kết nối SQLite + auto-migrate bảng `tasks`
|
|
- Driver: `github.com/glebarez/sqlite` (pure Go, wraps `modernc.org/sqlite`)
|
|
- WAL mode enabled
|
|
- Auto-migrate bảng `tasks` khi khởi động
|
|
- Health check: `SELECT 1`
|
|
|
|
### 4. Module config (.env)
|
|
- Dùng `github.com/joho/godotenv` load `.env`
|
|
- Validate tất cả biến bắt buộc, trả lỗi rõ ràng nếu thiếu
|
|
- Parse `WHITELIST_EMAILS` (comma-separated)
|
|
- Default `LISTEN_ADDR=:8080`
|
|
|
|
### 5. Structured Logging
|
|
- Dùng `log/slog` (Go stdlib 1.21+), JSON handler ra stdout
|
|
- Helper `TaskLogger(taskUUID, threadID, messageID)` — mọi log liên quan task đều có context
|
|
|
|
### 6. API endpoints (Gin)
|
|
- `GET /healthz` → `200 {"status":"ok"}` (liveness)
|
|
- `GET /readyz` → kiểm tra DB writable + config token (readiness)
|
|
|
|
### 7. Docker
|
|
- **Dockerfile**: Multi-stage, `golang:1.23-alpine` → `alpine:3.20`, `CGO_ENABLED=0`
|
|
- **docker-compose.yml**: Named volume `bridge-data:/app/data`, `env_file: .env`
|
|
|
|
---
|
|
|
|
## Quyết định thiết kế
|
|
|
|
| Quyết định | Lý do |
|
|
|---|---|
|
|
| `glebarez/sqlite` thay vì `gorm.io/driver/sqlite` | Pure Go, không cần CGO → Docker build đơn giản |
|
|
| `log/slog` thay vì zap/logrus | Stdlib, zero dependency, đủ dùng |
|
|
| `gin-gonic/gin` | Đúng requirements, nhẹ, phổ biến |
|
|
| WAL mode SQLite | Tăng throughput đọc concurrent |
|
|
| `internal/` layout | Chuẩn Go, ngăn import từ bên ngoài |
|
|
|
|
## Dependencies (go.mod)
|
|
|
|
```
|
|
github.com/gin-gonic/gin v1.12.0
|
|
github.com/glebarez/sqlite v1.11.0 (→ modernc.org/sqlite)
|
|
github.com/joho/godotenv v1.5.1
|
|
gorm.io/gorm v1.31.1
|
|
```
|
|
|
|
---
|
|
|
|
## Tiếp theo (chưa implement)
|
|
|
|
1. IMAP Ingress — IDLE, anti-loop, whitelist, idempotency, threading
|
|
2. OpenClaw Dispatch — HTTP POST, retry 3 lần (1s/5s/15s)
|
|
3. Callback handler — webhook xác thực token, cập nhật task
|
|
4. SMTP Egress — gửi reply, In-Reply-To/References, retry
|
|
5. Integration tests — 6 scenarios từ requirements
|