diff --git a/internal/httpapi/handlers/topics.go b/internal/httpapi/handlers/topics.go index d1e81c8..fda0edb 100644 --- a/internal/httpapi/handlers/topics.go +++ b/internal/httpapi/handlers/topics.go @@ -16,9 +16,12 @@ import ( type TopicsHandler struct { store *store.TopicStore + camps *store.CampStore } -func NewTopicsHandler(s *store.TopicStore) *TopicsHandler { return &TopicsHandler{store: s} } +func NewTopicsHandler(s *store.TopicStore, c *store.CampStore) *TopicsHandler { + return &TopicsHandler{store: s, camps: c} +} // GET /api/topics?status=...&visibility=...&limit=...&offset=... // @@ -75,7 +78,26 @@ func (h *TopicsHandler) Get(w http.ResponseWriter, r *http.Request) { http.Error(w, "not found", http.StatusNotFound) // 404 not 403 — hide existence return } - writeJSON(w, http.StatusOK, t) + // Enrich with camps so an agent can locate their own allocation in one + // round-trip. Camps are 0 rows pre-signup_close, 3 rows after — small + // enough that inlining costs nothing. Arguments are deliberately NOT + // inlined (potentially large; agents who need the transcript should + // hit GET /api/topics/{id}/arguments via dialectic_list_arguments). + // + // Backward-compatible: existing callers reading the original Topic + // fields keep working; new callers can read `camps` alongside. + camps, cErr := h.camps.ListByTopic(r.Context(), id) + if cErr != nil { + camps = nil // best-effort; metadata still useful + } + // Marshal Topic into a map and add `camps` as a sibling field rather + // than wrapping under "topic" — that would break every existing + // consumer that reads e.g. response.title / response.status directly. + buf, _ := json.Marshal(t) + out := map[string]any{} + _ = json.Unmarshal(buf, &out) + out["camps"] = camps + writeJSON(w, http.StatusOK, out) } type createTopicBody struct { diff --git a/internal/httpapi/routes.go b/internal/httpapi/routes.go index 5a2347e..ce19ca0 100644 --- a/internal/httpapi/routes.go +++ b/internal/httpapi/routes.go @@ -60,7 +60,7 @@ func Mount(cfg *config.Config, db *sqlx.DB, version string) http.Handler { verdictStore := store.NewVerdictStore(db) health := handlers.NewHealthHandler(db, version) - topicsH := handlers.NewTopicsHandler(topicStore) + topicsH := handlers.NewTopicsHandler(topicStore, campStore) signupsH := handlers.NewSignupsHandler(topicStore, signupStore) argsH := handlers.NewArgumentsHandler(topicStore, campStore, roundStore, argStore) announcer := fabric.NewAnnouncer(cfg.FabricSystemAPIKey)