Files
paliad/internal/handlers/dashboard.go
m 460736ad1e refactor(t-paliad-092): rename Go module path patholo → paliad
F-6 from t-paliad-074 architecture audit. The Gitea repo was renamed
m/patholo → mAi/paliad → m/paliad, but go.mod still declared
`mgit.msbls.de/m/patholo` and every internal import echoed the
pre-rebrand name.

Sweep:
- go.mod: module path → mgit.msbls.de/m/paliad
- All *.go files: imports rewritten via sed
- README.md, docs/design-kanzlai-integration.md: mAi/paliad → m/paliad
- Frontend issue-reference comments (mAi/paliad#N → m/paliad#N) in
  i18n.ts, theme.ts, sidebar.ts, app.ts, Sidebar.tsx, PWAHead.tsx,
  global.css

Verified: go build/vet/test ./... clean, bun run build clean,
no remaining mgit.msbls.de/m/patholo or mAi/paliad references
outside docs that intentionally describe the rename history.
2026-04-30 16:46:31 +02:00

66 lines
2.0 KiB
Go

package handlers
import (
"net/http"
"mgit.msbls.de/m/paliad/internal/auth"
)
// GET /api/dashboard — returns the DashboardData JSON for the logged-in user.
// Returns 503 if DATABASE_URL is unset.
func handleDashboardAPI(w http.ResponseWriter, r *http.Request) {
if !requireDB(w) {
return
}
uid, ok := requireUser(w, r)
if !ok {
return
}
data, err := dbSvc.dashboard.Get(r.Context(), uid)
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, data)
}
// GET /dashboard — protected shell page. The client boots, reads the initial
// payload inlined by the server into window.__PALIAD_DASHBOARD__, and renders
// without a second round-trip (audit §2.3: no skeleton→fetch waterfall).
func handleDashboardPage(w http.ResponseWriter, r *http.Request) {
uid, hasUser := auth.UserIDFromContext(r.Context())
var payload []byte
if hasUser && dbSvc != nil {
// Best-effort server-render. If the DB read fails we still serve the
// shell; the client will show the inline error state instead of the
// zero-count cards.
if data, err := dbSvc.dashboard.Get(r.Context(), uid); err == nil {
payload = mustJSON(data)
}
}
serveDashboardShell(w, r, payload)
}
// handleRootPage is the public `/` route. Unauthenticated visitors get the
// marketing landing; authenticated users get a 302 to /dashboard so `/` feels
// like a no-op they can bookmark.
func handleRootPage(w http.ResponseWriter, r *http.Request) {
if hasValidSession(r) {
http.Redirect(w, r, "/dashboard", http.StatusFound)
return
}
http.ServeFile(w, r, "dist/index.html")
}
// hasValidSession returns true when the session cookie carries a signed,
// unexpired Supabase JWT. Verification is the same one Middleware uses —
// forged or tampered cookies never reach the authenticated branch.
func hasValidSession(r *http.Request) bool {
cookie, err := r.Cookie(auth.SessionCookieName)
if err != nil || cookie.Value == "" {
return false
}
_, err = authClient.VerifyToken(cookie.Value)
return err == nil
}