feat: initpage com sync Go + auth + frontend em web/

This commit is contained in:
2026-10-21 18:06:25 -03:00
commit 17b81a808a
24 changed files with 4807 additions and 0 deletions

97
cmd/server/main.go Normal file
View File

@@ -0,0 +1,97 @@
package main
import (
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/alexedwards/scs/v2"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/joho/godotenv"
"golang.org/x/time/rate"
"github.com/weltonmoura/initpage/internal/config"
"github.com/weltonmoura/initpage/internal/db"
"github.com/weltonmoura/initpage/internal/handlers"
mw "github.com/weltonmoura/initpage/internal/middleware"
"github.com/weltonmoura/initpage/internal/sync"
)
func main() {
_ = godotenv.Load()
cfg := config.Load()
dbConn, err := db.Init(cfg.DBPath)
if err != nil {
log.Fatal(err)
}
defer dbConn.Close()
sessionManager := scs.New()
sessionManager.Lifetime = 24 * time.Hour
sessionManager.Cookie.HttpOnly = true
sessionManager.Cookie.SameSite = http.SameSiteLaxMode
sessionManager.Cookie.Secure = strings.HasPrefix(cfg.AppOrigin, "https://")
authH := &handlers.Auth{DB: dbConn, SM: sessionManager, Cfg: cfg}
syncH := &sync.Sync{DB: dbConn}
rl := mw.NewIPRateLimiter(rate.Every(time.Minute/10), 10) // ~10 req/min
rl.Cleanup()
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RealIP)
r.Use(sessionManager.LoadAndSave)
base := strings.TrimRight(cfg.BasePath, "/")
r.Route(base+"/api", func(api chi.Router) {
api.Group(func(g chi.Router) {
g.Use(mw.RateLimit(rl))
g.Post("/auth/register", authH.Register)
g.Post("/auth/login", authH.Login)
})
api.Post("/auth/logout", authH.Logout)
api.Get("/auth/me", authH.Me)
api.Group(func(g chi.Router) {
g.Use(mw.AuthRequired(sessionManager))
g.Use(mw.LoadUserID(sessionManager))
g.Get("/sync", syncH.Get)
g.Put("/sync", syncH.Put)
})
})
// servir frontend
workDir, _ := os.Getwd()
webDir := filepath.Join(workDir, "web")
fileServer := http.FileServer(http.Dir(webDir))
r.Get(base, func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join(webDir, "index.html"))
})
r.Get(base+"/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join(webDir, "index.html"))
})
r.Get(base+"/*", func(w http.ResponseWriter, r *http.Request) {
// strip base path
p := strings.TrimPrefix(r.URL.Path, base)
if p == "" {
p = "/"
}
// tenta servir arquivo
full := filepath.Join(webDir, filepath.Clean(strings.TrimPrefix(p, "/")))
if st, err := os.Stat(full); err == nil && !st.IsDir() {
http.StripPrefix(base, fileServer).ServeHTTP(w, r)
return
}
http.ServeFile(w, r, filepath.Join(webDir, "index.html"))
})
log.Printf("Servidor rodando em :%s base=%s", cfg.Port, base)
log.Fatal(http.ListenAndServe(":"+cfg.Port, r))
}