package main import ( "log" "net/http" "os" "prompt-generator/internal/auth" "prompt-generator/internal/config" "prompt-generator/internal/db" "prompt-generator/internal/handlers" ) func main() { // Load .env file if exists loadEnvFile(".env") cfg := config.Load() // Initialize database if err := db.Init(cfg); err != nil { log.Fatalf("Failed to initialize database: %v", err) } // Auto migrate if err := db.AutoMigrate(); err != nil { log.Fatalf("Failed to migrate database: %v", err) } // Seed data if err := db.SeedData(); err != nil { log.Fatalf("Failed to seed data: %v", err) } // Initialize auth auth.Init(cfg.SessionSecret) // Initialize handlers handlers.Init(cfg) // Ensure prompts table exists for dev environments db.EnsurePromptsTable() // Setup routes mux := http.NewServeMux() // Static files with SPA-style routing for HTML pages mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path // Map clean URLs to .html files switch path { case "/dashboard": http.ServeFile(w, r, "frontend/dashboard.html") return case "/settings": http.ServeFile(w, r, "frontend/settings.html") return } // Default file server fs := http.FileServer(http.Dir("frontend")) fs.ServeHTTP(w, r) }) // Auth routes (no auth required) mux.HandleFunc("POST /api/auth/login", handlers.Login) mux.HandleFunc("POST /api/auth/logout", handlers.Logout) mux.HandleFunc("GET /api/auth/check", handlers.AuthCheck) // Protected API routes apiMux := http.NewServeMux() apiMux.HandleFunc("GET /api/tags", handlers.GetTags) apiMux.HandleFunc("POST /api/tags", handlers.CreateTag) apiMux.HandleFunc("PUT /api/tags/{id}", handlers.UpdateTag) apiMux.HandleFunc("DELETE /api/tags/{id}", handlers.DeleteTag) apiMux.HandleFunc("POST /api/tags/{id}/options", handlers.CreateTagOption) apiMux.HandleFunc("PUT /api/tag-options/{id}", handlers.UpdateTagOption) apiMux.HandleFunc("DELETE /api/tag-options/{id}", handlers.DeleteTagOption) apiMux.HandleFunc("GET /api/snippets", handlers.GetSnippets) apiMux.HandleFunc("POST /api/snippets", handlers.CreateSnippet) apiMux.HandleFunc("PUT /api/snippets/{id}", handlers.UpdateSnippet) apiMux.HandleFunc("DELETE /api/snippets/{id}", handlers.DeleteSnippet) apiMux.HandleFunc("GET /api/builder/sessions", handlers.GetBuilderSessions) apiMux.HandleFunc("POST /api/builder/sessions", handlers.CreateBuilderSession) apiMux.HandleFunc("GET /api/builder/sessions/{id}", handlers.GetBuilderSession) apiMux.HandleFunc("PUT /api/builder/sessions/{id}", handlers.UpdateBuilderSession) apiMux.HandleFunc("DELETE /api/builder/sessions/{id}", handlers.DeleteBuilderSession) apiMux.HandleFunc("GET /api/claude/sessions", handlers.GetClaudeSessions) apiMux.HandleFunc("GET /api/claude/sessions/{session_id}/prompts", handlers.GetClaudePrompts) apiMux.HandleFunc("GET /api/dashboard/projects", handlers.GetDashboardProjects) apiMux.HandleFunc("GET /api/dashboard/projects/{name}/sessions", handlers.GetDashboardSessions) apiMux.HandleFunc("GET /api/dashboard/prompts", handlers.GetDashboardPrompts) apiMux.HandleFunc("POST /api/suggestions", handlers.GetSuggestions) apiMux.HandleFunc("GET /api/settings", handlers.GetSettings) apiMux.HandleFunc("PUT /api/settings", handlers.UpdateSettings) // Wrap API routes with auth middleware mux.Handle("/api/", auth.AuthMiddleware(apiMux)) log.Printf("Server starting on :%s", cfg.ServerPort) if err := http.ListenAndServe(":"+cfg.ServerPort, mux); err != nil { log.Fatalf("Server failed: %v", err) } } func loadEnvFile(path string) { data, err := os.ReadFile(path) if err != nil { return // .env file is optional } lines := splitLines(string(data)) for _, line := range lines { if len(line) == 0 || line[0] == '#' { continue } for i := 0; i < len(line); i++ { if line[i] == '=' { key := line[:i] value := line[i+1:] // Remove quotes if len(value) >= 2 && (value[0] == '"' && value[len(value)-1] == '"') { value = value[1 : len(value)-1] } os.Setenv(key, value) break } } } } func splitLines(s string) []string { var lines []string start := 0 for i := 0; i < len(s); i++ { if s[i] == '\n' { lines = append(lines, s[start:i]) start = i + 1 } } if start < len(s) { lines = append(lines, s[start:]) } return lines }