90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
package api
|
|
|
|
import (
|
|
"io/fs"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/mish/dealspace/lib"
|
|
)
|
|
|
|
// NewRouter creates the main router with all routes registered.
|
|
func NewRouter(db *lib.DB, cfg *lib.Config, store lib.ObjectStore, websiteFS fs.FS, portalFS fs.FS) *chi.Mux {
|
|
r := chi.NewRouter()
|
|
h := NewHandlers(db, cfg, store)
|
|
|
|
// Global middleware
|
|
r.Use(LoggingMiddleware)
|
|
r.Use(CORSMiddleware)
|
|
r.Use(RateLimitMiddleware(120)) // 120 req/min per IP
|
|
|
|
// Health check (unauthenticated)
|
|
r.Get("/health", h.Health)
|
|
|
|
// Chat endpoint (unauthenticated, for Aria chatbot)
|
|
r.Post("/api/chat", h.ChatHandler)
|
|
r.Options("/api/chat", h.ChatHandler)
|
|
|
|
// Auth endpoints (unauthenticated)
|
|
r.Post("/api/auth/login", h.Login)
|
|
r.Post("/api/setup", h.Setup)
|
|
|
|
// Auth endpoints (need token for logout/me)
|
|
r.Group(func(r chi.Router) {
|
|
r.Use(AuthMiddleware(db, cfg.JWTSecret))
|
|
r.Post("/api/auth/logout", h.Logout)
|
|
r.Get("/api/auth/me", h.Me)
|
|
})
|
|
|
|
// API routes (authenticated)
|
|
r.Route("/api", func(r chi.Router) {
|
|
r.Use(AuthMiddleware(db, cfg.JWTSecret))
|
|
|
|
// Tasks (cross-project)
|
|
r.Get("/tasks", h.GetAllTasks)
|
|
|
|
// Projects
|
|
r.Get("/projects", h.GetAllProjects)
|
|
r.Post("/projects", h.CreateProject)
|
|
r.Get("/projects/{projectID}/detail", h.GetProjectDetail)
|
|
|
|
// Workstreams
|
|
r.Post("/projects/{projectID}/workstreams", h.CreateWorkstream)
|
|
|
|
// Entries
|
|
r.Get("/projects/{projectID}/entries", h.ListEntries)
|
|
r.Post("/projects/{projectID}/entries", h.CreateEntry)
|
|
r.Put("/projects/{projectID}/entries/{entryID}", h.UpdateEntry)
|
|
r.Delete("/projects/{projectID}/entries/{entryID}", h.DeleteEntry)
|
|
|
|
// Task inbox (per-project)
|
|
r.Get("/projects/{projectID}/tasks", h.GetMyTasks)
|
|
|
|
// Requests
|
|
r.Get("/requests/{requestID}", h.GetRequestDetail)
|
|
|
|
// File upload/download
|
|
r.Post("/projects/{projectID}/objects", h.UploadObject)
|
|
r.Get("/projects/{projectID}/objects/{objectID}", h.DownloadObject)
|
|
})
|
|
|
|
// Portal app routes (serve templates, auth checked client-side via JS)
|
|
r.Get("/app", func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/app/tasks", http.StatusFound)
|
|
})
|
|
r.Get("/app/login", h.ServeLogin)
|
|
r.Get("/app/setup", h.ServeSetup)
|
|
r.Get("/app/tasks", h.ServeAppTasks)
|
|
r.Get("/app/projects", h.ServeAppProjects)
|
|
r.Get("/app/projects/{id}", h.ServeAppProject)
|
|
r.Get("/app/requests/{id}", h.ServeAppRequest)
|
|
|
|
// Marketing website (embedded static files) — serves at root, must be last
|
|
if websiteFS != nil {
|
|
websiteHandler := http.FileServerFS(websiteFS)
|
|
r.Handle("/*", websiteHandler)
|
|
}
|
|
|
|
return r
|
|
}
|