package api import ( "net/http" "task/internal/command" "task/internal/project" "task/internal/ticket" ) // Server is the daemon HTTP API. type Server struct { store ticket.Store timeStore ticket.TimeStore projects project.Store history command.Executor hub *hub mux *http.ServeMux } // New constructs the API server. func New(store ticket.Store, timeStore ticket.TimeStore, projects project.Store, history command.Executor) *Server { s := &Server{ store: store, timeStore: timeStore, projects: projects, history: history, hub: newHub(), mux: http.NewServeMux(), } s.routes() return s } // Handler returns the root HTTP handler with auth middleware. func (s *Server) Handler() http.Handler { return s.withAuth(s.mux) } func (s *Server) routes() { s.mux.HandleFunc("GET /v1/health", s.handleHealth) s.mux.HandleFunc("GET /v1/projects", s.handleListProjects) s.mux.HandleFunc("POST /v1/projects", s.handleEnsureProject) s.mux.HandleFunc("DELETE /v1/projects/{id}", s.handleDeleteProject) s.mux.HandleFunc("GET /v1/projects/{id}/meta", s.handleGetMeta) s.mux.HandleFunc("PUT /v1/projects/{id}/meta", s.handleSaveMeta) s.mux.HandleFunc("GET /v1/projects/{id}/mcp-token", s.handleMCPTokenStatus) s.mux.HandleFunc("POST /v1/projects/{id}/mcp-token", s.handleMCPTokenCreate) s.mux.HandleFunc("DELETE /v1/projects/{id}/mcp-token", s.handleMCPTokenRevoke) s.mux.HandleFunc("GET /v1/tickets", s.handleListTickets) s.mux.HandleFunc("GET /v1/tickets/{id}", s.handleGetTicket) s.mux.HandleFunc("POST /v1/tickets", s.handleCreateTicket) s.mux.HandleFunc("PATCH /v1/tickets/{id}", s.handleUpdateTicket) s.mux.HandleFunc("DELETE /v1/tickets/{id}", s.handleDeleteTicket) s.mux.HandleFunc("POST /v1/tickets/{id}/move", s.handleMoveTicket) s.mux.HandleFunc("GET /v1/time", s.handleListTime) s.mux.HandleFunc("GET /v1/time/by-ticket/{ticketId}", s.handleListTimeByTicket) s.mux.HandleFunc("GET /v1/time/sum/{ticketId}", s.handleSumTime) s.mux.HandleFunc("POST /v1/time", s.handleAddTime) s.mux.HandleFunc("PATCH /v1/time/{id}", s.handleUpdateTime) s.mux.HandleFunc("DELETE /v1/time/{id}", s.handleRemoveTime) s.mux.HandleFunc("GET /v1/timer", s.handleGetTimer) s.mux.HandleFunc("PUT /v1/timer", s.handleSetTimer) s.mux.HandleFunc("GET /v1/history", s.handleHistoryStatus) s.mux.HandleFunc("POST /v1/undo", s.handleUndo) s.mux.HandleFunc("POST /v1/redo", s.handleRedo) s.mux.HandleFunc("POST /v1/sync/pull", s.handleSyncPull) s.mux.HandleFunc("POST /v1/sync/push", s.handleSyncPush) s.mux.HandleFunc("GET /v1/events", s.handleEvents) } func (s *Server) handleHealth(w http.ResponseWriter, _ *http.Request) { writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) } func (s *Server) notify(projectID string) { s.hub.publish(Event{Type: "changed", ProjectID: projectID}) }