feat: add stats page

This commit is contained in:
Krispire Admin
2026-05-31 14:54:15 +05:30
parent d3ad443fde
commit 72f4e6527c
14 changed files with 750 additions and 36 deletions
+32
View File
@@ -50,6 +50,8 @@ type Server struct {
bookmarkH *handler.BookmarkHandler
collectionH *handler.CollectionHandler
profileH *handler.ProfileHandler
feedbackH *handler.FeedbackHandler
statsH *handler.StatsHandler
// Auth state (nil when Postgres is unavailable — /auth and /users return 503)
authIssuer *auth.Issuer
@@ -164,6 +166,14 @@ func (s *Server) initAuth(cfg *config.Config, logger *zap.Logger) {
s.bookmarkH = handler.NewBookmarkHandler(bookmarkSvc)
s.collectionH = handler.NewCollectionHandler(collectionSvc, postRepo, issuer, userRepo)
s.profileH = handler.NewProfileHandler(userRepo, postRepo, collectionRepo)
// Feedback + stats — share Postgres with the rest of /api/v1 and
// the existing mailer instance.
feedbackRepo := repository.NewFeedbackRepo(s.pg)
statsRepo := repository.NewStatsRepo(s.pg)
feedbackSvc := service.NewFeedbackService(feedbackRepo, mail, cfg.FeedbackAdminEmails, logger)
s.feedbackH = handler.NewFeedbackHandler(feedbackSvc)
s.statsH = handler.NewStatsHandler(statsRepo, feedbackRepo)
}
// initShortener wires Postgres + Redis + the shorturl handler/workers.
@@ -276,6 +286,14 @@ func (s *Server) setupRouter() {
w.Write([]byte(`{"status":"ok"}`))
})
// Public ops snapshot — aggregate counts + recent feedback rendered
// as HTML. Lives outside /api/v1 because it returns HTML, not JSON.
// Currently unauthenticated by product decision; gate here if that
// ever needs to change.
if s.statsH != nil {
r.Get("/stats", s.statsH.Render)
}
// API v1
r.Route("/api/v1", func(r chi.Router) {
// Books
@@ -601,6 +619,20 @@ func (s *Server) setupRouter() {
}
})
// --- Feedback ---
// OptionalAuth so authed callers' user_id is captured
// automatically (handler reads middleware.UserID), and
// anonymous callers are still accepted (they supply
// contact_email instead).
r.Group(func(r chi.Router) {
if s.feedbackH == nil {
r.HandleFunc("/feedback", s.authUnavailable)
return
}
r.Use(middleware.OptionalAuth(s.authIssuer, s.userRepo))
r.Post("/feedback", s.feedbackH.Submit)
})
// Push Notifications
r.Route("/notifications", func(r chi.Router) {
// TODO: register push notification handlers