main.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "net/http"
  6. "github.com/go-chi/chi/v5"
  7. chimiddleware "github.com/go-chi/chi/v5/middleware"
  8. "github.com/go-chi/cors"
  9. "golang.org/x/time/rate"
  10. "github.com/photoplaces/backend/internal/config"
  11. "github.com/photoplaces/backend/internal/handlers"
  12. "github.com/photoplaces/backend/internal/middleware"
  13. "github.com/photoplaces/backend/internal/repository"
  14. "github.com/photoplaces/backend/internal/services"
  15. )
  16. func main() {
  17. cfg := config.Load()
  18. ctx := context.Background()
  19. pool, err := repository.NewPool(ctx, cfg.DatabaseURL)
  20. if err != nil {
  21. log.Fatalf("database connection: %v", err)
  22. }
  23. defer pool.Close()
  24. userRepo := repository.NewUserRepo(pool)
  25. placeRepo := repository.NewPlaceRepo(pool)
  26. serviceRepo := repository.NewServiceRepo(pool)
  27. reviewRepo := repository.NewReviewRepo(pool)
  28. bookingRepo := repository.NewBookingRepo(pool)
  29. tagRepo := repository.NewTagRepo(pool)
  30. featureRepo := repository.NewFeatureRepo(pool)
  31. authSvc := services.NewAuthService(userRepo, cfg.JWTSecret, cfg.JWTRefreshSecret)
  32. placeSvc := services.NewPlaceService(placeRepo)
  33. authHandler := handlers.NewAuthHandler(authSvc)
  34. userHandler := handlers.NewUserHandler(userRepo)
  35. placeHandler := handlers.NewPlaceHandler(placeSvc)
  36. serviceHandler := handlers.NewServiceHandler(serviceRepo, tagRepo)
  37. reviewHandler := handlers.NewReviewHandler(reviewRepo)
  38. bookingHandler := handlers.NewBookingHandler(bookingRepo, placeRepo)
  39. tagHandler := handlers.NewTagHandler(tagRepo, featureRepo)
  40. wsHub := handlers.NewWSHub()
  41. uploadHandler, err := handlers.NewUploadHandler(cfg.S3Endpoint, cfg.S3AccessKey, cfg.S3SecretKey, cfg.S3Bucket, false)
  42. if err != nil {
  43. log.Fatalf("upload handler: %v", err)
  44. }
  45. rl := middleware.NewRateLimiter(rate.Limit(60), 60)
  46. r := chi.NewRouter()
  47. r.Use(chimiddleware.Logger)
  48. r.Use(chimiddleware.Recoverer)
  49. r.Use(chimiddleware.RequestID)
  50. r.Use(cors.Handler(cors.Options{
  51. AllowedOrigins: cfg.AllowedOrigins,
  52. AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE", "OPTIONS"},
  53. AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-Refresh-Token"},
  54. AllowCredentials: true,
  55. MaxAge: 300,
  56. }))
  57. r.Use(rl.Middleware())
  58. r.Route("/api/v1", func(r chi.Router) {
  59. r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
  60. w.Write([]byte(`{"status":"ok"}`))
  61. })
  62. // Public auth
  63. r.Post("/auth/register", authHandler.Register)
  64. r.Post("/auth/login", authHandler.Login)
  65. r.Post("/auth/refresh", authHandler.Refresh)
  66. // Public reviews (read)
  67. r.Get("/reviews", reviewHandler.List)
  68. // Public tags & features
  69. r.Get("/tags", tagHandler.ListTags)
  70. r.Get("/features", tagHandler.ListFeatures)
  71. // Public services (read)
  72. r.Get("/services", serviceHandler.List)
  73. r.Get("/services/{id}", serviceHandler.GetByID)
  74. // Public places (read)
  75. r.Get("/places", placeHandler.List)
  76. r.Get("/places/{id}", placeHandler.GetByID)
  77. // WebSocket visitor dots
  78. r.Get("/ws/visitors", wsHub.HandleWS)
  79. // Authenticated
  80. r.Group(func(r chi.Router) {
  81. r.Use(middleware.AuthMiddleware(authSvc))
  82. r.Get("/auth/me", authHandler.Me)
  83. // Users
  84. r.Patch("/users/me", userHandler.UpdateMe)
  85. // Upload
  86. r.Post("/upload/presigned-url", uploadHandler.PresignedURL)
  87. // Bookings
  88. r.Post("/bookings", bookingHandler.Create)
  89. r.Get("/bookings/me", bookingHandler.ListMy)
  90. r.Patch("/bookings/{id}/cancel", bookingHandler.Cancel)
  91. // Reviews
  92. r.Post("/reviews", reviewHandler.Create)
  93. // Services
  94. r.Post("/services", serviceHandler.Create)
  95. r.Patch("/services/{id}", serviceHandler.Update)
  96. r.Delete("/services/{id}", serviceHandler.Delete)
  97. // Place creation
  98. r.Post("/places", placeHandler.Create)
  99. r.Patch("/places/{id}", placeHandler.Update)
  100. r.Delete("/places/{id}", placeHandler.Delete)
  101. })
  102. // Public user profile
  103. r.Get("/users/{id}", userHandler.GetProfile)
  104. // Moderator / Admin
  105. r.Group(func(r chi.Router) {
  106. r.Use(middleware.AuthMiddleware(authSvc))
  107. r.Use(middleware.RoleMiddleware("moderator", "superadmin"))
  108. r.Post("/places/{id}/moderate", placeHandler.Moderate)
  109. r.Get("/admin/users", userHandler.AdminListUsers)
  110. r.Patch("/admin/users/{id}", userHandler.AdminUpdateUser)
  111. r.Patch("/admin/bookings/{id}/confirm", bookingHandler.Confirm)
  112. r.Post("/admin/tags", tagHandler.CreateTag)
  113. r.Delete("/admin/tags", tagHandler.DeleteTag)
  114. r.Post("/admin/features", tagHandler.CreateFeature)
  115. r.Delete("/admin/features", tagHandler.DeleteFeature)
  116. })
  117. })
  118. port := cfg.ServerPort
  119. log.Printf("Starting server on :%s", port)
  120. if err := http.ListenAndServe(":"+port, r); err != nil {
  121. log.Fatal(err)
  122. }
  123. }