// Uygulama giriş noktası (serve fonksiyonu çalışır) // @title SafeQR API // @version 1.0 // @description QR kod yönetim sistemi API'si // @host localhost:8080 // @BasePath /api package main import ( "context" "log" "net/http" "os" "path/filepath" "time" firebase "firebase.google.com/go/v4" "github.com/Posinowa/SafeQR/internal/auth" "github.com/Posinowa/SafeQR/internal/contact" "github.com/Posinowa/SafeQR/internal/creditpacks" "github.com/Posinowa/SafeQR/internal/database" "github.com/Posinowa/SafeQR/internal/example" "github.com/Posinowa/SafeQR/internal/healthcheck" "github.com/Posinowa/SafeQR/internal/payment" "github.com/Posinowa/SafeQR/internal/qr" "github.com/Posinowa/SafeQR/internal/topic" "github.com/Posinowa/SafeQR/internal/usage" "github.com/Posinowa/SafeQR/internal/user" "github.com/Posinowa/SafeQR/pkg/logger" "github.com/Posinowa/SafeQR/pkg/swagger" "github.com/gorilla/mux" "github.com/joho/godotenv" "github.com/rs/cors" "go.uber.org/zap" "google.golang.org/api/option" ) // loggingMiddleware logs all requests and responses func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() log.Printf("REQUEST: %s %s", r.Method, r.URL.Path) // Create a response wrapper to capture the status code wrapper := newResponseWriterWrapper(w) // Call the next handler next.ServeHTTP(wrapper, r) // Log after request is complete log.Printf("RESPONSE: %s %s - Status: %d - Duration: %v", r.Method, r.URL.Path, wrapper.status, time.Since(start)) }) } // responseWriterWrapper captures the status code of HTTP responses type responseWriterWrapper struct { http.ResponseWriter status int } func newResponseWriterWrapper(w http.ResponseWriter) *responseWriterWrapper { return &responseWriterWrapper{w, http.StatusOK} } func (rw *responseWriterWrapper) WriteHeader(code int) { rw.status = code rw.ResponseWriter.WriteHeader(code) } func main() { // Ortam değişkenlerini yükle if err := godotenv.Load(); err != nil { log.Fatal("Error loading .env file") } // Logger başlat logger.InitLogger() defer logger.CloseLogger() ctx := context.Background() // Firebase App başlat opt := option.WithCredentialsFile("configs/credentials.json") app, err := firebase.NewApp(ctx, nil, opt) log.Printf("PayTR Configuration loaded - Merchant ID: %s, Callback URL: %s", os.Getenv("PAYTR_MERCHANT_ID"), os.Getenv("PAYTR_CALLBACK_URL")) if os.Getenv("GOOGLE_PROJECT_ID") == "" { logger.Log.Fatal("GOOGLE_PROJECT_ID ortam değişkeni yok") } if os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") == "" { logger.Log.Fatal("GOOGLE_APPLICATION_CREDENTIALS ortam değişkeni yok") } // Firestore bağlantısını başlat db, err := database.NewDatabase(ctx, os.Getenv("GOOGLE_PROJECT_ID"), os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) if err != nil { logger.Log.Fatal("Firebase App başlatılamadı", zap.Error(err)) } // Firebase Auth client başlat authClient, err := app.Auth(ctx) if err != nil { logger.Log.Fatal("Firebase Auth client başlatılamadı", zap.Error(err)) } defer db.Close() // Auth servisi başlat authService := auth.NewAuth(ctx, authClient, db) // Router oluştur router := mux.NewRouter() // CORS middleware corsHandler := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}, AllowedHeaders: []string{ "Authorization", "Content-Type", "Accept", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Origin", }, AllowCredentials: true, MaxAge: 300, // Debug modu aktif ederek CORS hatalarını görebilirsiniz Debug: true, }) router.Use(corsHandler.Handler) router.Use(loggingMiddleware) // Add logging middleware // Sağlık kontrolü router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) }).Methods("GET") // Contact modülü için mail konfigürasyonu contactMailConfig := contact.ContactMailConfig{ SMTPHost: os.Getenv("SMTP_HOST"), SMTPPort: 587, // Gmail için standart port SMTPUser: os.Getenv("SMTP_USER"), SMTPPassword: os.Getenv("SMTP_PASSWORD"), FromEmail: os.Getenv("SMTP_FROM_EMAIL"), ToEmails: []string{ "feyzanur788@gmail.com", "agirmanberat668@gmail.com", "yusufyilmaz.f@gmail.com", "sumeyyedilaradogan@gmail.com", }, } // Modül bazlı route tanımları healthcheck.SetupRouter(db) example.SetupRouter(db, router) user.SetupRouter(db, router, authService, authClient) usage.SetupRouter(db, router) payment.SetupRouter(db, router) //usage.SetupRouter(db, router) // usage isteği uygulamanın internal katmanında kullanılacak test amaçlı burada creditpacks.SetupRouter(db, router) qr.SetupRouter(db, router) topic.SetupRouter(db, router) contact.SetupRouter(db, router, contactMailConfig) // Swagger dokümantasyonunu ekle swagger.SetupSwagger(router) // Statik dosyaları serve et workDir, _ := os.Getwd() staticDir := filepath.Join(workDir, ".") router.PathPrefix("/").Handler(http.FileServer(http.Dir(staticDir))) // Sunucu başlat port := os.Getenv("PORT") if port == "" { port = "8080" } server := &http.Server{ Addr: ":" + port, Handler: router, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } log.Printf("Server starting on port 8080...") log.Println("Swagger UI: http://localhost:8080/swagger/index.html") logger.Log.Info("Server başlatılıyor", zap.String("port", port)) if err := server.ListenAndServe(); err != nil { logger.Log.Fatal("Sunucu başlatılamadı", zap.Error(err)) } }