refactor: rewrite backend in Go, replacing Python FastAPI

Port the FastAPI backend to Go 1.26, preserving all API functionality:
- auth (register/login/guest/logout/profile/history) with JWT + bcrypt
- scripts (list/detail) backed by embedded sample_data.json
- games (create/join/start/chat/phase/clue/vote/state/replay) + WebSocket
- rule-based NPC agent plus DeepSeek/Ollama AI backends
- SQLite persistence via modernc.org/sqlite (pure Go, no cgo)

Frontend and documents are unchanged.
This commit is contained in:
gmh01
2026-08-03 11:39:53 +08:00
parent c176c04aab
commit 7614e79d12
43 changed files with 2498 additions and 1462 deletions
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"log"
"net/http"
"github.com/go-chi/chi/v5"
"mmgame/internal/database"
"mmgame/internal/handlers"
)
func main() {
if err := database.Init(); err != nil {
log.Fatalf("database init failed: %v", err)
}
r := chi.NewRouter()
r.Use(cors)
r.Get("/api/health", handlers.Health)
// auth
r.Post("/api/auth/register", handlers.Register)
r.Post("/api/auth/login", handlers.Login)
r.Post("/api/auth/guest", handlers.GuestLogin)
r.Post("/api/auth/logout", handlers.Logout)
r.Get("/api/auth/profile", handlers.GetProfile)
r.Put("/api/auth/profile", handlers.UpdateProfile)
r.Get("/api/auth/history", handlers.GetHistory)
// scripts
r.Get("/api/scripts", handlers.ListScripts)
r.Get("/api/scripts/{script_id}", handlers.GetScript)
// games
r.Post("/api/games/create", handlers.CreateGame)
r.Route("/api/games/{game_id}", func(rr chi.Router) {
rr.Post("/join", handlers.JoinGame)
rr.Post("/start", handlers.StartGame)
rr.Post("/chat", handlers.SendChat)
rr.Post("/phase/advance", handlers.AdvancePhase)
rr.Post("/clue/{clue_id}/reveal", handlers.RevealClue)
rr.Post("/vote", handlers.SubmitVote)
rr.Post("/vote/end", handlers.EndVote)
rr.Get("/state", handlers.GetGameState)
rr.Get("/replay", handlers.GetReplay)
})
r.Get("/api/games/ws/{game_id}", handlers.GameWebSocket)
log.Println("MMGame Go backend running on http://localhost:8000")
log.Fatal(http.ListenAndServe(":8000", r))
}
func cors(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
if origin == "" {
origin = "*"
}
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}