feat(seo): add sitemap generator

This commit is contained in:
Krispire Admin
2026-06-15 13:28:15 +05:30
parent 438258ade0
commit bbe491ae13
4 changed files with 299 additions and 0 deletions
+34
View File
@@ -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)