Scope
Wire the ConversationStore (from #80) to HTTP handlers and mount them in cmd/conversationd. This replaces the 501 stubs created in #77 with real implementations.
Endpoints
| Method |
Path |
Description |
POST |
/conversations |
Create a new conversation. Body: {title?, metadata?}. Returns {id, created_at, ...}. |
GET |
/conversations/{id} |
Return conversation metadata. 404 if not found. |
DELETE |
/conversations/{id} |
Delete conversation and all its messages. 204 No Content. |
PUT |
/conversations/{id}/messages |
Append one or more messages to the conversation. Body: {messages: [{role, content[]}]}. Returns {next_seq}. |
GET |
/conversations/{id}/messages |
List messages. Query params: after_seq (uint64, default 0), limit (int, default 100). |
GET |
/healthz |
Liveness probe (mirrors internal/server pattern). |
GET |
/readyz |
Readiness probe (calls ConversationStore.Ping). |
Handler implementation
Create internal/convserver/handlers.go (mirrors internal/server/handlers.go):
type Handler struct {
svc convstore.ConversationStore
log *slog.Logger
maxBodyBytes int64
}
Error mapping follows the same pattern as internal/server:
convstore.ErrNotFound → 404
convstore.ErrConversationFull → 507 Insufficient Storage
- Unknown errors → 500 + log
Wire-up in cmd/conversationd
cmd/conversationd/main.go instantiates ConversationStore (Pebble or in-memory based on config), creates convserver.Handler, and serves on the configured listen address.
Unit tests
Test file: internal/convserver/handlers_test.go
Use the in-memory ConversationStore backend. Cover:
POST /conversations — creates with and without title/metadata
GET /conversations/{id} — found and not-found
DELETE /conversations/{id} — idempotent
PUT /conversations/{id}/messages — single and multi-message append; seq monotonicity
GET /conversations/{id}/messages — pagination via after_seq and limit
- Error paths: invalid JSON body, missing required fields, store-full
Acceptance criteria
Blocked by: #80, #78
Scope
Wire the
ConversationStore(from #80) to HTTP handlers and mount them incmd/conversationd. This replaces the501stubs created in #77 with real implementations.Endpoints
POST/conversations{title?, metadata?}. Returns{id, created_at, ...}.GET/conversations/{id}404if not found.DELETE/conversations/{id}204 No Content.PUT/conversations/{id}/messages{messages: [{role, content[]}]}. Returns{next_seq}.GET/conversations/{id}/messagesafter_seq(uint64, default 0),limit(int, default 100).GET/healthzinternal/serverpattern).GET/readyzConversationStore.Ping).Handler implementation
Create
internal/convserver/handlers.go(mirrorsinternal/server/handlers.go):Error mapping follows the same pattern as
internal/server:convstore.ErrNotFound→ 404convstore.ErrConversationFull→ 507 Insufficient StorageWire-up in cmd/conversationd
cmd/conversationd/main.goinstantiatesConversationStore(Pebble or in-memory based on config), createsconvserver.Handler, and serves on the configured listen address.Unit tests
Test file:
internal/convserver/handlers_test.goUse the in-memory
ConversationStorebackend. Cover:POST /conversations— creates with and without title/metadataGET /conversations/{id}— found and not-foundDELETE /conversations/{id}— idempotentPUT /conversations/{id}/messages— single and multi-message append; seq monotonicityGET /conversations/{id}/messages— pagination viaafter_seqandlimitAcceptance criteria
cmd/conversationd/healthzand/readyzpresent and correctmake presubmitpassesgo build ./cmd/conversationd/...succeeds with full implementation (no501stubs remain)Blocked by: #80, #78