A community based topic aggregation platform built on atproto
1package main
2
3import (
4 "database/sql"
5 "fmt"
6 "log"
7 "net/http"
8 "os"
9
10 "github.com/go-chi/chi/v5"
11 "github.com/go-chi/chi/v5/middleware"
12 _ "github.com/lib/pq"
13 "github.com/pressly/goose/v3"
14 "gorm.io/driver/postgres"
15 "gorm.io/gorm"
16
17 "Coves/internal/api/routes"
18 "Coves/internal/atproto/carstore"
19 "Coves/internal/core/repository"
20 "Coves/internal/core/users"
21 postgresRepo "Coves/internal/db/postgres"
22)
23
24func main() {
25 dbURL := os.Getenv("DATABASE_URL")
26 if dbURL == "" {
27 dbURL = "postgres://postgres:password@localhost:5432/coves?sslmode=disable"
28 }
29
30 db, err := sql.Open("postgres", dbURL)
31 if err != nil {
32 log.Fatal("Failed to connect to database:", err)
33 }
34 defer db.Close()
35
36 if err := db.Ping(); err != nil {
37 log.Fatal("Failed to ping database:", err)
38 }
39
40 if err := goose.SetDialect("postgres"); err != nil {
41 log.Fatal("Failed to set goose dialect:", err)
42 }
43
44 if err := goose.Up(db, "internal/db/migrations"); err != nil {
45 log.Fatal("Failed to run migrations:", err)
46 }
47
48 r := chi.NewRouter()
49
50 r.Use(middleware.Logger)
51 r.Use(middleware.Recoverer)
52 r.Use(middleware.RequestID)
53
54 // Initialize GORM
55 gormDB, err := gorm.Open(postgres.New(postgres.Config{
56 Conn: db,
57 }), &gorm.Config{
58 DisableForeignKeyConstraintWhenMigrating: true,
59 PrepareStmt: true, // Enable prepared statements for better performance
60 })
61 if err != nil {
62 log.Fatal("Failed to initialize GORM:", err)
63 }
64
65 // Initialize repositories
66 userRepo := postgresRepo.NewUserRepository(db)
67 _ = users.NewUserService(userRepo) // TODO: Use when UserRoutes is fixed
68
69 // Initialize carstore for ATProto repository storage
70 carDirs := []string{"./data/carstore"}
71 repoStore, err := carstore.NewRepoStore(gormDB, carDirs)
72 if err != nil {
73 log.Fatal("Failed to initialize repo store:", err)
74 }
75
76 repositoryRepo := postgresRepo.NewRepositoryRepo(db)
77 repositoryService := repository.NewService(repositoryRepo, repoStore)
78
79 // Mount routes
80 // TODO: Fix UserRoutes to accept *UserService
81 // r.Mount("/api/users", routes.UserRoutes(userService))
82 r.Mount("/", routes.RepositoryRoutes(repositoryService))
83
84 r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
85 w.WriteHeader(http.StatusOK)
86 w.Write([]byte("OK"))
87 })
88
89 port := os.Getenv("PORT")
90 if port == "" {
91 port = "8080"
92 }
93
94 fmt.Printf("Server starting on port %s\n", port)
95 log.Fatal(http.ListenAndServe(":"+port, r))
96}