Files
deploy-felhom-compose/TASK.md
T
2026-02-15 10:23:02 +01:00

8.9 KiB

TASK.md — Controller Refactoring: Template Split, Server Decomposition, Domain Rename

Goal: Improve code organization for maintainability and Claude Code efficiency. No new features — purely structural refactoring + one config rename.

Version bump: v0.3.0 (structural refactor milestone)


Task 1: Split templates.go → go:embed (HIGH PRIORITY)

The templates.go file contains ALL HTML templates and CSS as Go string constants. The file itself says: "As the UI grows, switch to go:embed for easier editing." With 7 templates + full CSS, it's time.

1.1 — Create template files directory

Create controller/internal/web/templates/ with individual files:

internal/web/templates/
├── layout.html          ← from layoutTmpl const
├── dashboard.html       ← from dashboardTmpl const
├── stacks.html          ← from stacksTmpl const  (the stacks list page, NOT the old dashboard list)
├── login.html           ← from loginTmpl const
├── logs.html            ← from logsTmpl const
├── deploy.html          ← from deployTmpl const
├── app_info.html        ← from appInfoTmpl const
└── style.css            ← from cssTemplate const

Each .html file should contain ONLY the template content (the {{define "name"}}...{{end}} block). Keep the existing template names (layout_start, layout_end, dashboard, stacks, login, etc.).

1.2 — Create embed.go

Create controller/internal/web/embed.go:

package web

import "embed"

//go:embed templates/*.html templates/*.css
var templateFS embed.FS

1.3 — Update template loading in server.go (or the new funcmap.go, see Task 2)

Replace the current loadTemplates() method that parses the allTemplates const:

func (s *Server) loadTemplates() {
    funcMap := template.FuncMap{ /* ... existing funcs ... */ }

    s.tmpl = template.Must(
        template.New("").Funcs(funcMap).ParseFS(templateFS, "templates/*.html"),
    )
}

CSS serving: Instead of the cssTemplate const, read from templateFS:

func (s *Server) serveCSSHandler(w http.ResponseWriter, r *http.Request) {
    data, err := templateFS.ReadFile("templates/style.css")
    if err != nil {
        http.Error(w, "CSS not found", 500)
        return
    }
    w.Header().Set("Content-Type", "text/css; charset=utf-8")
    w.Header().Set("Cache-Control", "public, max-age=3600")
    w.Write(data)
}

Register this handler for /static/style.css in ServeHTTP (replace the current inline CSS serving).

1.4 — Delete old string constants

Remove from templates.go:

  • const allTemplates = ...
  • const layoutTmpl = ...
  • const dashboardTmpl = ...
  • const stacksTmpl = ...
  • const loginTmpl = ...
  • const logsTmpl = ...
  • const deployTmpl = ...
  • const appInfoTmpl = ...
  • const cssTemplate = ...

After this, templates.go should either be empty (delete it) or contain only the felhom logo SVG constant if that's still embedded as a string (keep that one — it's small).

1.5 — Verify the build

  • go build ./cmd/controller/ must succeed
  • go:embed requires Go 1.16+ (we're on 1.22, fine)
  • Templates are still compiled into the binary — zero runtime file dependencies (same as before)
  • Verify that the HTML files actually include the {{define "name"}}...{{end}} wrappers (ParseFS needs them to register template names)

Important notes

  • The <link rel="stylesheet" href="/static/style.css"> in layout.html already exists, so CSS loading via the /static/style.css route should already work — just make sure the handler reads from embed.FS instead of serving the const.
  • The felhom logo SVG can stay as a Go const (it's small) or move to templates/felhom-logo.svg and be served from embed.FS too. Either approach is fine.

Task 2: Split server.go into focused files (MEDIUM PRIORITY)

Currently server.go handles: Server struct, auth/sessions, page handlers, template FuncMap, asset serving, and HTTP routing. Split into:

2.1 — Create auth.go

Move from server.go to internal/web/auth.go:

  • type session struct
  • const sessionCookieName, const sessionMaxAge
  • RequireAuth() middleware method
  • loginHandler(), loginPostHandler(), logoutHandler()
  • createSession(), isValidSession(), cleanupSessions()
  • renderLogin() helper

2.2 — Create handlers.go

Move from server.go to internal/web/handlers.go:

  • baseData() helper
  • dashboardHandler()
  • stacksHandler()
  • deployPageHandler()
  • deployPagePostHandler() (if it exists as separate handler)
  • appDetailHandler()
  • logsPageHandler()

2.3 — Create funcmap.go

Move from server.go to internal/web/funcmap.go:

  • The entire template.FuncMap definition from loadTemplates()
  • Extract it as a standalone function: func (s *Server) templateFuncMap() template.FuncMap
  • Then loadTemplates() becomes a clean 3-liner calling templateFuncMap() + ParseFS

2.4 — Keep in server.go

After the split, server.go should contain only:

  • type Server struct
  • func NewServer()
  • func (s *Server) loadTemplates() (now a 3-liner)
  • func (s *Server) ServeHTTP() (HTTP routing dispatch)
  • func (s *Server) render() helper
  • Static file/asset serving handlers (serveStaticFile, serveCSSHandler, serveLogoHandler)

2.5 — Verify the split

All files are in package web — no import changes needed within the package. The Server struct and all its methods are accessible across files in the same package.

Run go build ./cmd/controller/ to verify everything compiles.


Task 3: Rename controller domain from dashboard.* to felhom.* (LOW PRIORITY)

3.1 — Update controller's docker-compose.yml

In controller/docker-compose.yml, change the Traefik label:

# OLD:
- "traefik.http.routers.controller.rule=Host(`dashboard.${DOMAIN}`)"
# NEW:
- "traefik.http.routers.controller.rule=Host(`felhom.${DOMAIN}`)"

3.2 — Update docker-setup.sh

In controller/scripts/docker-setup.sh, update print_summary() output:

  • Any reference to dashboard.${BASE_DOMAIN}felhom.${BASE_DOMAIN}

Also check install_controller() if it generates compose files or prints URLs.

3.3 — Update controller.yaml.example

If there's any reference to dashboard.* in the example config or comments, update to felhom.*.

3.4 — Update documentation

In CLAUDE.md build/deploy workflow sections, update any dashboard. references to felhom..

3.5 — Cloudflare Tunnel public hostname (MANUAL — not code)

Reminder for Viktor: After deploying, manually update the Cloudflare Tunnel public hostname in the Zero Trust dashboard:

  • Old: dashboard.demo-felhom.eu → Traefik
  • New: felhom.demo-felhom.eu → Traefik

3.6 — Pi-hole DNS (MANUAL — not code)

Reminder for Viktor: If there's a pi-hole local DNS record for dashboard.demo-felhom.eu, update it to felhom.demo-felhom.eu (or rely on the wildcard *.demo-felhom.eu record).


Task 4: Update documentation

4.1 — README.md

  • Update directory structure to show internal/web/templates/ directory
  • Update "Tech stack" section: "Templates: go:embed HTML files" instead of "Go string constants"
  • Mention the felhom.* subdomain for the controller
  • Update file tree showing the new files (embed.go, auth.go, handlers.go, funcmap.go)

4.2 — CLAUDE.md

  • Update workspace layout to reflect the new internal/web/ file structure
  • Update "Tech stack" section
  • Update any dashboard.* references to felhom.*
  • Note the go:embed pattern for future template additions

4.3 — CONTEXT.md

  • Add session entry documenting the refactoring
  • Note: templates moved from Go string constants to go:embed HTML files
  • Note: server.go split into auth.go, handlers.go, funcmap.go
  • Note: controller domain changed from dashboard.* to felhom.*
  • Update version to v0.3.0

4.4 — BUILDING.md

  • Update the structure check in build.sh verification section if needed (the internal/web/templates/ directory should exist now)

Implementation order

  1. Task 1 (templates.go → go:embed) — do this first, biggest impact
  2. Task 2 (server.go split) — do this second, leverages the cleaner templates
  3. Task 3 (domain rename) — small, do last
  4. Task 4 (docs) — update after all code changes

Verification checklist

  • go build ./cmd/controller/ compiles successfully
  • All 7 HTML templates render correctly (login, dashboard, stacks, deploy, app_info, logs, layout)
  • CSS loads at /static/style.css
  • Felhom logo SVG loads at /static/felhom-logo.svg
  • App logos/screenshots still serve from /assets/
  • Auth (login/logout/session) works unchanged
  • Stack operations (start/stop/deploy) work unchanged
  • Controller accessible at felhom.demo-felhom.eu (after CF tunnel update)
  • No broken links or template errors in browser console
  • Build + push via build.sh works
  • Deploy on demo-felhom works