From 7ca52f88a2b1772e72887cf04d18fb1cfbdd681e Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 16 Feb 2026 16:26:12 +0100 Subject: [PATCH] Bug fixes from v0.6.2 code scan --- TASK.md | 372 ++++++++++++++++++-------------------------------------- 1 file changed, 115 insertions(+), 257 deletions(-) diff --git a/TASK.md b/TASK.md index e319be1..bc967e6 100644 --- a/TASK.md +++ b/TASK.md @@ -1,316 +1,174 @@ -# TASK: Create CLAUDE.md + cleanup + statusIcon fix (felhom.eu repo) +# TASK: Bug fixes from v0.6.2 code scan ## Context -The `felhom.eu` repo lacks a CLAUDE.md with build instructions for the hub, has no `.gitignore` (so `hub.exe` got committed), and has a statusIcon rendering bug on the hub dashboard. +Comprehensive code scan of felhom-controller v0.6.2 found 4 minor bugs across templates, shell scripts, and Go code. None are critical, but all should be fixed for correctness. -**Current state:** Hub v0.1.2 running on k3s. Controller v0.6.2 on demo node. +**Current state:** Controller v0.6.2 running on demo-felhom.eu. -All changes in this task are in the **felhom.eu repo** only. +All changes in this task are in the **deploy-felhom-compose** repo only. --- -## Task 1: Create CLAUDE.md +## Bug 1: Missing `require_arg` for `--hdd-path` in docker-setup.sh -Create `CLAUDE.md` in the repo root (`E:\git\felhom.eu\CLAUDE.md`) with the following content. -Use the controller's `CLAUDE.md` (in `deploy-felhom-compose`) as a style reference. +**File:** `scripts/docker-setup.sh` -The CLAUDE.md should include these sections: +**Problem:** The `--hdd-path` flag parsing doesn't use `require_arg` validation like all other flags do. Under `set -u`, if `--hdd-path` is the last argument and has no value, `$2` is unbound and the script crashes with a cryptic bash error instead of a friendly message. -### Project overview - -This repo (`felhom.eu`) contains: -- **Website** (`website/`) — Static HTML pages at felhom.eu, served via k3s nginx + git-sync sidecar -- **Hub** (`hub/`) — Go application (felhom-hub) — centralized dashboard for monitoring customer controllers, runs on k3s at hub.felhom.eu -- **K8s manifests** (`manifests/`) — k3s deployment manifests for all felhom-system services - -See `README.md` for full architecture, DNS, email, and SEO documentation. -See `TASK.md` for the current task to implement (if it exists). - -### Code quality rules - -Same as controller CLAUDE.md: -- Always double-check generated code for bugs, logic issues, syntax errors -- Handle edge cases without overcomplicating -- Add debug capabilities for troubleshooting -- Ask for more input rather than guessing - -### Workspace layout - -``` -E:\git\felhom.eu\ (or /e/git/felhom.eu/ in Git Bash) -├── hub/ # felhom-hub Go application -│ ├── cmd/hub/ # Entry point (main.go) -│ ├── internal/ -│ │ ├── api/ # Report ingestion API -│ │ ├── store/ # SQLite storage + queries -│ │ └── web/ # Dashboard UI -│ │ ├── server.go # Server, routing, template funcs -│ │ ├── embed.go # go:embed for templates -│ │ └── templates/ # HTML templates + CSS -│ ├── configs/ # Example config files -│ ├── Dockerfile -│ ├── Makefile -│ └── go.mod -├── manifests/ # k3s deployment manifests -│ ├── hub.yaml # Hub deployment (hub.felhom.eu) -│ ├── webpage.yaml # Website + FileBrowser + git-sync -│ ├── contact-mailer.yaml # Contact form email sender -│ ├── healthchecks.yaml # Healthchecks (status.felhom.eu) -│ └── umami.yaml # Analytics (stats.felhom.eu) -├── website/ # Static HTML pages (felhom.eu) -│ ├── index.html -│ ├── alkalmazasok.html -│ ├── ... (all Hungarian, UTF-8 with BOM) -│ └── assets/ # Logos, screenshots, OG images -├── CLAUDE.md # This file -├── README.md # Full project documentation -└── TASK.md # Current task (if exists) -``` - -Related repos (same parent directory): -``` -E:\git\deploy-felhom-compose\ # felhom-controller Go app + deploy scripts -E:\git\app-catalog-felhom.eu\ # Docker Compose templates per app -E:\git\homelab-manifests\ # k3s cluster manifests (dooplex.hu services) -E:\git\misc-scripts\ # Helper scripts (build scripts, repo collector) -``` - -All repos hosted at `gitea.dooplex.hu/admin/`. - -### SSH access - -SSH key-based authentication configured. No password prompts. - -| Host | IP | User | Role | -|------|----|------|------| -| Build server (k3s node) | 192.168.0.180 | kisfenyo | Build + push images, kubectl | -| Demo node | 192.168.0.162 | kisfenyo | Test deployment (demo-felhom.eu) | - -**Note:** `kubectl` on the build server requires `sudo` (k3s kubeconfig permissions). - -### Build & deploy workflow — Hub - -After making code changes to `hub/`, you **MUST** build, push, and deploy the new image. -Do NOT leave code changes uncommitted or undeployed. - -#### Step 1: Commit and push changes +**Current code** (in the argument parsing `while` loop): ```bash -cd /e/git/felhom.eu -git add -A && git commit -m "" && git push +--hdd-path) HDD_PATH="$2"; shift 2 ;; ``` -#### Step 2: Build + push the container image on the build server - -The build server (192.168.0.180) has the build toolchain. The build script lives at -`~/build/felhom-hub/build.sh` on the build server (NOT in this repo). - -First, check the current running version: -```bash -ssh kisfenyo@192.168.0.180 "sudo kubectl get deploy -n felhom-system hub -o jsonpath='{.spec.template.spec.containers[0].image}'" -``` - -Then build with the next version (e.g., if current is 0.1.2, use 0.1.3): -```bash -ssh kisfenyo@192.168.0.180 "cd ~/build/felhom-hub && ./build.sh --push" -``` - -The build script: -- Pulls latest code from Gitea (`git pull` on the felhom.eu repo) -- Copies `hub/` source to a clean build workspace -- Builds Docker image with version + build-time ldflags -- Pushes to `gitea.dooplex.hu/admin/felhom-hub:` and `:latest` - -#### Step 3: Deploy to k3s +**Fix:** Add `require_arg` call, matching the pattern used by all other flags: ```bash -ssh kisfenyo@192.168.0.180 "sudo kubectl set image -n felhom-system deploy/hub hub=gitea.dooplex.hu/admin/felhom-hub:" +--hdd-path) + require_arg "$1" "${2:-}" + HDD_PATH="$2"; shift 2 ;; ``` -#### Step 4: Verify the deployment - -```bash -ssh kisfenyo@192.168.0.180 "sudo kubectl get pods -n felhom-system -l app=hub && echo '---' && sudo kubectl logs -n felhom-system -l app=hub --tail 10" -``` - -Should show pod Running and `[INFO] felhom-hub starting` in logs. - -#### Build workflow summary - -| Step | Command | Where | -|------|---------|-------| -| 1. Commit + push | `git add -A && git commit && git push` | Local (this repo) | -| 2. Build + push image | `ssh 192.168.0.180 "cd ~/build/felhom-hub && ./build.sh --push"` | Build server | -| 3. Deploy | `ssh 192.168.0.180 "sudo kubectl set image -n felhom-system deploy/hub hub=...:"` | Build server (kubectl) | -| 4. Verify | `ssh 192.168.0.180 "sudo kubectl get pods -n felhom-system -l app=hub"` | Build server | - -### Build & deploy workflow — Website - -The website auto-deploys via git-sync sidecar. Just push to `main`: - -```bash -cd /e/git/felhom.eu -git add -A && git commit -m "" && git push -``` - -Changes are live within 1-2 minutes. No build step needed. - -For emergency edits, use FileBrowser at `https://files.felhom.eu`. - -### Build & deploy workflow — K8s Manifests - -Manifests are applied manually: - -```bash -ssh kisfenyo@192.168.0.180 "sudo kubectl apply -f /home/kisfenyo/git/felhom.eu/manifests/.yaml" -``` - -Remember to `git pull` on the build server first if you pushed changes locally. - -### Tech stack (Hub) - -- **Language:** Go 1.24+ -- **Web framework:** stdlib `net/http` + `html/template` -- **Database:** SQLite via `modernc.org/sqlite` (pure Go, no CGo) -- **Auth:** bcrypt password hash + basic auth -- **Deployment:** Docker container on k3s (felhom-system namespace) -- **Storage:** Longhorn PVC at `/data/` (SQLite DB) -- **Config:** YAML file mounted via k8s ConfigMap at `/etc/felhom-hub/hub.yaml` - -### Key patterns - -- Hub receives reports from customer controllers via `POST /api/v1/report` (Bearer token auth) -- Dashboard shows all customers in a table with status, CPU, memory, disk, containers, backup age -- Customer detail page shows system info, report history, full JSON report -- Status logic: OK (report < 30m), WARN (30m-1h or health=warn), DOWN (> 1h or health=fail) -- SQLite timestamps may vary in format — use `parseSQLiteTime()` for robust parsing -- Auto-refresh: dashboard and detail pages refresh every 60 seconds via `` -- Geo-restricted to Hungary via nginx ingress annotation - -### File encoding - -All HTML files in `website/` are **UTF-8 with BOM**. Ensure your editor preserves this. -Hub Go source files are standard UTF-8 (no BOM). +**Verification:** Search for other flags in the same `while` loop — they all use `require_arg`. Confirm `require_arg` is defined earlier in the script (it is). --- -## Task 2: Create .gitignore +## Bug 2: Implicit `event` variable in `stackAction()` (layout.html) -Create `.gitignore` in the repo root with appropriate entries: +**File:** `controller/internal/web/templates/layout.html` -```gitignore -# Go binaries -hub/hub -hub/hub.exe -hub/bin/ +**Problem:** The `stackAction` JavaScript function references `event.currentTarget` to get the clicked button, but `event` is never passed as a parameter. It relies on the implicit global `window.event` object, which is non-standard and deprecated. Works in Chrome/Firefox today but is not guaranteed. -# Build artifacts -*.exe -*.dll -*.so -*.dylib +**Current code:** -# Test and coverage -*.test -*.out -coverage.html - -# IDE -.idea/ -.vscode/ -*.swp -*.swo -*~ - -# OS -.DS_Store -Thumbs.db - -# Temporary files -*.tmp -*.bak +```javascript +async function stackAction(name, action) { + const btn = event.currentTarget; ``` -## Task 3: Remove hub.exe from git history +**Fix — Step 1:** Change the function signature to accept `event`: -After creating `.gitignore`, remove the committed binary: - -```bash -git rm --cached hub/hub.exe +```javascript +async function stackAction(event, name, action) { + const btn = event.currentTarget; ``` -This removes it from tracking but the `.gitignore` prevents re-adding. No need to rewrite -history — just remove from current tree. +**Fix — Step 2:** Update ALL `onclick` call sites in the same file that call `stackAction` to pass `event` as the first argument. Search for `stackAction(` in the template — each call looks like: -Also check for any other binaries that shouldn't be tracked: -```bash -find hub/ -name "*.exe" -o -name "hub" -type f -executable +```html +onclick="stackAction('{{.Name}}', 'start')" ``` -## Task 4: Fix hub statusIcon rendering +Change each to: -**File:** `hub/internal/web/server.go` +```html +onclick="stackAction(event, '{{.Name}}', 'start')" +``` -**Problem:** `statusIcon()` returns HTML entities (`🟢`), but Go's `html/template` -auto-escapes them to literal text (`&#x1F7E2;`). Additionally, emoji don't respond to -CSS `color` — but the templates already apply `style="color: {{statusColor .OverallStatus}}"`. +There are multiple call sites (start, stop, restart buttons in the stacks section). Update **all** of them. -**Fix:** Change `statusIcon()` to return `●` (U+25CF, BLACK CIRCLE) — a plain Unicode character -that responds to CSS color styling. The existing `statusColor()` function handles color differentiation. +**Verification:** Search the entire file for `stackAction(` — every call site must pass `event` as the first argument. No other functions in the codebase call `stackAction`. + +--- + +## Bug 3: Missing separator in page title (layout.html) + +**File:** `controller/internal/web/templates/layout.html` + +**Problem:** The `` tag concatenates `.Title` and "Felhom.eu" with no separator, rendering as e.g. `"VezérlőpultFelhom.eu"` instead of `"Vezérlőpult — Felhom.eu"`. + +**Current code:** + +```html +<title>{{.Title}}Felhom.eu +``` + +**Fix:** + +```html +{{.Title}} — Felhom.eu +``` + +Uses em dash (U+2014) with spaces on both sides. This is a single-character change in the template. + +**Edge case:** If `.Title` is empty, the title becomes ` — Felhom.eu` (leading space + dash). Check if any handler sets an empty `.Title`. If so, consider using a conditional: + +```html +{{if .Title}}{{.Title}} — {{end}}Felhom.eu +``` + +Check all handlers that call `render()` or `renderTemplate()` — if every handler always sets a non-empty `.Title`, the simple fix (without conditional) is fine. + +--- + +## Bug 4: `nextPruneLabel` edge case on Sunday before 4am (funcmap.go) + +**File:** `controller/internal/web/funcmap.go` + +**Problem:** The `nextPruneLabel` function calculates when the next weekly prune (Sunday 4:00) will occur. On Sunday before 4am, `daysUntilSunday` computes to 0, but the function returns the date in `"2006-01-02"` format instead of `"ma"` (Hungarian for "today"). Every other "today" scenario in the codebase uses the `"ma"` label. + +**Current code:** ```go -// BEFORE (broken): -func statusIcon(status string) string { - switch status { - case "ok": - return "🟢" // green circle - case "warn": - return "🟡" // yellow circle - case "down", "fail": - return "🔴" // red circle - default: - return "⚪" // white circle - } -} - -// AFTER (works with CSS color): -func statusIcon(status string) string { - return "●" +daysUntilSunday := (7 - int(now.Weekday())) % 7 +if daysUntilSunday == 0 && now.Hour() >= 4 { + daysUntilSunday = 7 } +next := time.Date(now.Year(), now.Month(), now.Day()+daysUntilSunday, 4, 0, 0, 0, now.Location()) +return next.Format("2006-01-02") ``` -No template changes needed — `statusColor()` already provides the correct color per status. +The logic breakdown: +- Sunday, hour >= 4: `daysUntilSunday` = 0 → set to 7 (next week). Correct. +- Sunday, hour < 4: `daysUntilSunday` = 0 → stays 0, returns today's date as `"2006-01-02"`. Should return `"ma"`. +- Any other day: `daysUntilSunday` > 0 → returns future date. Correct. -**Verification:** -1. Dashboard: colored dot (green/yellow/red) before customer name, no `&#x` text -2. Customer detail: colored dot in header -3. Colors match status (green=OK, yellow=WARN, red=DOWN) +**Fix:** + +```go +daysUntilSunday := (7 - int(now.Weekday())) % 7 +if daysUntilSunday == 0 { + if now.Hour() >= 4 { + daysUntilSunday = 7 // Already ran today, next week + } else { + return "ma" // Today (Sunday), hasn't run yet + } +} +next := time.Date(now.Year(), now.Month(), now.Day()+daysUntilSunday, 4, 0, 0, 0, now.Location()) +return next.Format("2006-01-02") +``` + +**Verification:** Mentally walk through all cases: +- Monday–Saturday: `daysUntilSunday` is 1–6, returns future date ✓ +- Sunday 03:00: returns `"ma"` ✓ +- Sunday 04:00: `daysUntilSunday` = 7, returns next Sunday ✓ +- Sunday 23:00: `daysUntilSunday` = 7, returns next Sunday ✓ --- ## Build & Deploy -After all changes, commit and deploy hub v0.1.3: +After all fixes, commit and deploy as v0.6.3: ```bash # 1. Commit -cd /e/git/felhom.eu -git add -A && git commit -m "add CLAUDE.md, .gitignore, fix statusIcon rendering" && git push +cd /e/git/deploy-felhom-compose +git add -A && git commit -m "fix: require_arg for --hdd-path, explicit event in stackAction, title separator, nextPruneLabel Sunday edge case" && git push -# 2. Build -ssh kisfenyo@192.168.0.180 "cd ~/build/felhom-hub && ./build.sh 0.1.3 --push" +# 2. Build (only needed for bugs 2-4 which affect the controller binary/templates) +ssh kisfenyo@192.168.0.180 "cd ~/build/felhom-controller && ./build.sh 0.6.3 --push" -# 3. Deploy -ssh kisfenyo@192.168.0.180 "sudo kubectl set image -n felhom-system deploy/hub hub=gitea.dooplex.hu/admin/felhom-hub:0.1.3" +# 3. Deploy to demo node +ssh kisfenyo@192.168.0.162 "docker pull gitea.dooplex.hu/admin/felhom-controller:0.6.3 && cd /opt/docker && docker compose up -d" # 4. Verify -ssh kisfenyo@192.168.0.180 "sudo kubectl rollout status -n felhom-system deploy/hub && sudo kubectl logs -n felhom-system -l app=hub --tail 5" +ssh kisfenyo@192.168.0.162 "docker logs felhom-controller --tail 5" ``` ## Post-deploy checklist -- [ ] `hub.felhom.eu` shows colored `●` dot, not `🟢` text -- [ ] `hub.exe` no longer in repo (`git ls-files hub/hub.exe` returns empty) -- [ ] `CLAUDE.md` exists in repo root -- [ ] `.gitignore` exists in repo root \ No newline at end of file +- [ ] Page title shows separator: "Vezérlőpult — Felhom.eu" (check browser tab) +- [ ] Stack start/stop/restart buttons still work (Bug 2 didn't break onclick handlers) +- [ ] `docker-setup.sh --hdd-path` without value shows friendly error (test locally) +- [ ] Backup page shows "ma" on Sunday before 4am (only testable at that time, or adjust system clock) \ No newline at end of file