Files
claw-email/docs/superpowers/plans/2026-04-27-callback-base-url.md
T
thuanleandClaude Opus 4.7 c55a27d710
CI / fmt (pull_request) Failing after 4m52s
CI / test (pull_request) Successful in 10m50s
feat(mail): wire resolveThreadID into processMessage
- Add references variable to extract References header
- Replace manual inReplyTo handling with resolveThreadID call
- Maintain existing body parsing functionality
- Includes proper lambda function for database lookups

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 05:07:40 +07:00

173 lines
4.5 KiB
Markdown

# Callback Base URL Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Separate server bind address from callback URL generation and default callback base to localhost when unset.
**Architecture:** Keep `LISTEN_ADDR` only for HTTP server binding. Add `CALLBACK_BASE_URL` in config, default to `http://localhost` when empty, and build dispatch callback URL from this base plus `/callback`.
**Tech Stack:** Go, stdlib `net/url` + `strings`, existing project packages.
---
### Task 1: Add callback base URL config with localhost fallback
**Files:**
- Modify: `internal/config/config.go`
- Test: `internal/config/config_test.go` (create)
- [ ] **Step 1: Write the failing tests**
```go
func TestLoad_DefaultCallbackBaseURL_WhenUnset(t *testing.T) {
t.Setenv("CALLBACK_BASE_URL", "")
setRequiredEnv(t)
cfg, err := Load()
require.NoError(t, err)
require.Equal(t, "http://localhost", cfg.CallbackBaseURL)
}
func TestLoad_UsesCallbackBaseURL_WhenSet(t *testing.T) {
t.Setenv("CALLBACK_BASE_URL", "https://bridge.example.com")
setRequiredEnv(t)
cfg, err := Load()
require.NoError(t, err)
require.Equal(t, "https://bridge.example.com", cfg.CallbackBaseURL)
}
```
- [ ] **Step 2: Run tests to verify failure**
Run: `go test ./internal/config -run CallbackBaseURL -v`
Expected: FAIL because `Config` has no `CallbackBaseURL` field yet.
- [ ] **Step 3: Write minimal implementation**
```go
type Config struct {
// ...existing fields...
CallbackBaseURL string
}
cfg := &Config{
// ...existing env reads...
CallbackBaseURL: os.Getenv("CALLBACK_BASE_URL"),
}
if cfg.CallbackBaseURL == "" {
cfg.CallbackBaseURL = "http://localhost"
}
```
- [ ] **Step 4: Run tests to verify pass**
Run: `go test ./internal/config -run CallbackBaseURL -v`
Expected: PASS.
- [ ] **Step 5: Commit**
```bash
git add internal/config/config.go internal/config/config_test.go
git commit -m "feat(config): add callback base URL with localhost default"
```
### Task 2: Build callback URL from callback base URL
**Files:**
- Modify: `internal/ai_client/client.go`
- Test: `internal/ai_client/client_test.go` (create)
- [ ] **Step 1: Write the failing tests**
```go
func TestBuildCallbackURL_DefaultLocalhostBase(t *testing.T) {
got := buildCallbackURL("http://localhost")
require.Equal(t, "http://localhost/callback", got)
}
func TestBuildCallbackURL_TrimsTrailingSlash(t *testing.T) {
got := buildCallbackURL("https://bridge.example.com/")
require.Equal(t, "https://bridge.example.com/callback", got)
}
```
- [ ] **Step 2: Run tests to verify failure**
Run: `go test ./internal/ai_client -run BuildCallbackURL -v`
Expected: FAIL because helper function does not exist.
- [ ] **Step 3: Write minimal implementation**
```go
func buildCallbackURL(base string) string {
base = strings.TrimRight(base, "/")
return base + "/callback"
}
// in Dispatch:
callbackURL := buildCallbackURL(d.cfg.CallbackBaseURL)
```
- [ ] **Step 4: Run tests to verify pass**
Run: `go test ./internal/ai_client -run BuildCallbackURL -v`
Expected: PASS.
- [ ] **Step 5: Commit**
```bash
git add internal/ai_client/client.go internal/ai_client/client_test.go
git commit -m "fix(ai-client): use callback base URL for callback endpoint"
```
### Task 3: Update environment docs/examples
**Files:**
- Modify: `.env.example`
- Modify: `README.md`
- [ ] **Step 1: Add config key to `.env.example`**
```dotenv
LISTEN_ADDR=:8080
CALLBACK_BASE_URL=http://localhost
```
- [ ] **Step 2: Document purpose in README**
```md
- `LISTEN_ADDR`: local bind address for HTTP server (e.g. `:8080`)
- `CALLBACK_BASE_URL`: public base URL used to build callback endpoint; defaults to `http://localhost` when unset
```
- [ ] **Step 3: Run full test suite**
Run: `go test ./...`
Expected: PASS.
- [ ] **Step 4: Commit**
```bash
git add .env.example README.md
git commit -m "docs: document callback base URL configuration"
```
### Task 4: Prepare PR
**Files:**
- No code changes expected
- [ ] **Step 1: Push branch**
Run: `git push -u origin <branch-name>`
Expected: branch published.
- [ ] **Step 2: Open PR with summary and test evidence**
Include:
- Problem: callback URL incorrectly built from listen addr
- Fix: separate `CALLBACK_BASE_URL` with localhost fallback
- Tests: `go test ./internal/config -run CallbackBaseURL -v`, `go test ./internal/ai_client -run BuildCallbackURL -v`, `go test ./...`