admin reachable on server

This commit is contained in:
Trey t
2025-11-27 23:47:29 -06:00
parent 469f21a833
commit e6f05b2368
3 changed files with 66 additions and 66 deletions

View File

@@ -101,9 +101,45 @@ ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"] CMD ["node", "server.js"]
# Default production stage (for Dokku - runs API) # Default production stage (for Dokku - runs API + Admin)
FROM go-base AS production FROM node:20-alpine AS production
# Install runtime dependencies
RUN apk add --no-cache ca-certificates tzdata curl
# Create non-root user
RUN addgroup -g 1000 app && adduser -u 1000 -G app -s /bin/sh -D app
WORKDIR /app
# Copy Go binaries
COPY --from=builder /app/api /app/api
COPY --from=builder /app/worker /app/worker
# Copy templates directory
COPY --from=builder /app/templates /app/templates
# Copy migrations and seeds
COPY --from=builder /app/migrations /app/migrations
COPY --from=builder /app/seeds /app/seeds
# Copy admin panel standalone build
COPY --from=admin-builder /app/.next/standalone /app/admin
COPY --from=admin-builder /app/.next/static /app/admin/.next/static
COPY --from=admin-builder /app/public /app/admin/public
# Copy start script
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
# Create uploads directory
RUN mkdir -p /app/uploads && chown -R app:app /app
USER app
EXPOSE 5000 EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD curl -f http://localhost:${PORT:-5000}/api/health/ || exit 1 CMD curl -f http://localhost:${PORT:-5000}/api/health/ || exit 1
CMD ["/app/api"]
CMD ["/app/start.sh"]

View File

@@ -2,9 +2,9 @@ package admin
import ( import (
"net/http" "net/http"
"net/http/httputil"
"net/url"
"os" "os"
"path/filepath"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
@@ -252,75 +252,32 @@ func SetupRoutes(router *gin.Engine, db *gorm.DB, cfg *config.Config, deps *Depe
} }
} }
// Serve admin panel static files // Proxy admin panel requests to Next.js server
setupStaticFiles(router) setupAdminProxy(router)
} }
// setupStaticFiles configures serving the admin panel static files // setupAdminProxy configures reverse proxy to the Next.js admin panel
func setupStaticFiles(router *gin.Engine) { func setupAdminProxy(router *gin.Engine) {
// Determine the static files directory // Get admin panel URL from env, default to localhost:3000
// Check multiple possible locations adminURL := os.Getenv("ADMIN_PANEL_URL")
possiblePaths := []string{ if adminURL == "" {
"admin/out", // Development: from project root adminURL = "http://127.0.0.1:3000"
"./admin/out", // Development: relative
"/app/admin/out", // Docker: absolute path
} }
var staticDir string target, err := url.Parse(adminURL)
for _, path := range possiblePaths { if err != nil {
if _, err := os.Stat(path); err == nil {
staticDir = path
break
}
}
if staticDir == "" {
// Admin panel not built yet, skip static file serving
return return
} }
// Serve static files at /admin/* proxy := httputil.NewSingleHostReverseProxy(target)
router.GET("/admin/*filepath", func(c *gin.Context) {
filePath := c.Param("filepath")
// Clean the path // Handle all /admin/* requests
filePath = strings.TrimPrefix(filePath, "/") router.Any("/admin/*filepath", func(c *gin.Context) {
if filePath == "" { proxy.ServeHTTP(c.Writer, c.Request)
filePath = "index.html" })
}
fullPath := filepath.Join(staticDir, filePath) // Also handle /admin without trailing path
router.Any("/admin", func(c *gin.Context) {
// Check if file exists c.Redirect(http.StatusMovedPermanently, "/admin/")
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
// For SPA routing, serve index.html for non-existent paths
// But only if it's not a file request (no extension or .html)
ext := filepath.Ext(filePath)
if ext == "" || ext == ".html" {
// Try to find the specific page's index.html
pagePath := filepath.Join(staticDir, filePath, "index.html")
if _, err := os.Stat(pagePath); err == nil {
c.File(pagePath)
return
}
// Fall back to root index.html
c.File(filepath.Join(staticDir, "index.html"))
return
}
c.Status(http.StatusNotFound)
return
}
// If it's a directory, serve index.html
info, _ := os.Stat(fullPath)
if info.IsDir() {
indexPath := filepath.Join(fullPath, "index.html")
if _, err := os.Stat(indexPath); err == nil {
c.File(indexPath)
return
}
}
c.File(fullPath)
}) })
} }

7
start.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Start Next.js admin panel in background on port 3000
cd /app/admin && node server.js &
# Start Go API on port 5000 (Dokku's default)
/app/api