feat(seo): add sitemap generator
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
chiMiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/mailer"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/oauth"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/realtime"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/response"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/shorturl"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -46,6 +48,7 @@ type Server struct {
|
||||
otherDocH *handler.OtherDocumentHandler
|
||||
transcriptionH *handler.TranscriptionHandler
|
||||
searchH *handler.SearchHandler
|
||||
sitemapH *handler.SitemapHandler
|
||||
shortURLH *handler.ShortURLHandler
|
||||
authH *handler.AuthHandler
|
||||
oauthH *handler.OAuthHandler
|
||||
@@ -89,6 +92,7 @@ func New(cfg *config.Config, logger *zap.Logger) *Server {
|
||||
magazineRepo := repository.NewMagazineRepo(mongoDB)
|
||||
otherDocRepo := repository.NewOtherDocumentRepo(mongoDB)
|
||||
transcriptionRepo := repository.NewTranscriptionRepo(mongoDB)
|
||||
sitemapRepo := repository.NewSitemapRepo(mongoDB)
|
||||
|
||||
s := &Server{
|
||||
cfg: cfg,
|
||||
@@ -106,6 +110,7 @@ func New(cfg *config.Config, logger *zap.Logger) *Server {
|
||||
otherDocH: handler.NewOtherDocumentHandler(otherDocRepo),
|
||||
transcriptionH: handler.NewTranscriptionHandler(transcriptionRepo),
|
||||
searchH: handler.NewSearchHandler(tsClient),
|
||||
sitemapH: handler.NewSitemapHandler(sitemapRepo),
|
||||
}
|
||||
|
||||
// URL shortener: Postgres (canonical) + Redis (queue + hot cache) + background workers.
|
||||
@@ -342,6 +347,29 @@ func (s *Server) Close() {
|
||||
s.logger.Info("all connections closed")
|
||||
}
|
||||
|
||||
// sitemapUsers — GET /api/v1/sitemap/users → { "urls": ["/u/handle", …] }.
|
||||
// Public-profile sitemap. Reads userRepo at request time (it's wired only
|
||||
// after Postgres init); degrades to an empty list when Postgres is down.
|
||||
func (s *Server) sitemapUsers(w http.ResponseWriter, r *http.Request) {
|
||||
if s.userRepo == nil {
|
||||
response.JSON(w, http.StatusOK, map[string]any{"urls": []string{}})
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
handles, err := s.userRepo.AllHandles(ctx)
|
||||
if err != nil {
|
||||
response.Error(w, http.StatusInternalServerError, "could not build user sitemap")
|
||||
return
|
||||
}
|
||||
urls := make([]string, 0, len(handles))
|
||||
for _, h := range handles {
|
||||
urls = append(urls, "/u/"+h)
|
||||
}
|
||||
response.JSON(w, http.StatusOK, map[string]any{"urls": urls})
|
||||
}
|
||||
|
||||
// authUnavailable is the 503 fallback used when Postgres is down and the
|
||||
// auth handlers couldn't be wired up. Keeps every /auth/* and /users/* URL
|
||||
// returning a structured error rather than 404.
|
||||
@@ -405,6 +433,12 @@ func (s *Server) setupRouter() {
|
||||
|
||||
// API v1
|
||||
r.Route("/api/v1", func(r chi.Router) {
|
||||
// Sitemap — flat list of public content URLs (consumed by the
|
||||
// frontend's daily-cached sitemap routes). Public, read-only.
|
||||
r.Get("/sitemap/content", s.sitemapH.GetContent)
|
||||
// Public user profiles (Postgres) — separate from Mongo content.
|
||||
r.Get("/sitemap/users", s.sitemapUsers)
|
||||
|
||||
// Books
|
||||
r.Route("/books", func(r chi.Router) {
|
||||
r.Get("/", s.bookH.ListBooks)
|
||||
|
||||
Reference in New Issue
Block a user