173d857dbb
- Add GET /api/claude/sessions/{session_id}/builder API for structure view
- Load builder session tags and snippets by Claude session ID
- Implement structure view in dashboard: shows tag selections and snippet details
- Add LoadSettings to persist LLM config changes across restarts
- Settings are now loaded from database on startup
Co-Authored-By: Claude <noreply@anthropic.com>
154 lines
4.4 KiB
Go
154 lines
4.4 KiB
Go
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()
|
|
|
|
// Load persisted settings from database
|
|
db.LoadSettings(cfg)
|
|
|
|
// 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/claude/sessions/{session_id}/builder", handlers.GetBuilderSessionByClaudeSession)
|
|
|
|
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
|
|
}
|