Skip to content

Conversation

@eduardolat
Copy link
Owner

@eduardolat eduardolat commented Oct 6, 2025

Summary by CodeRabbit

  • New Features

    • Configurable path prefix for hosting under a subpath via env var; app links, redirects, and static assets honor it.
    • Replaced SweetAlert2 with a new lightweight in-app dialog system.
  • Documentation

    • Rebranded to “UFO Backup”; updated README, community landing page, redirects, and automated docs deploy to Cloudflare Pages.
    • Added sponsor/support updates.
  • Chores

    • Expanded formatter ignore list; updated asset scanning for styles/scripts.
  • Tests

    • Added validation and path-prefix utility tests.

eduardolat and others added 29 commits February 22, 2025 17:42
Introduces configurable path prefix to serve application under subpath (e.g., /pgbackweb)
Implements validation for path prefixes in environment variables
Updates all redirects and routes to use the configured path prefix

This allows deploying the app at a custom URL path while maintaining correct functionality.
Updates tests to properly manage global state:
- Uses defer pattern to restore original values after tests
- Resets sync.Once to allow multiple SetPathPrefix calls in tests
- Removes shouldSkip field from test cases as it's no longer needed
Refactors URL handling to allow serving the app from a subdirectory.
Updates all static file paths and dashboard navigation links to use a utility function that prepends the configured path prefix when generating URLs.
Consistently uses the pathutil.BuildPath function to build URLs across various web components instead of hardcoding them.
Replaces string concatenation with fmt.Sprintf for building URLs
This ensures consistent and more secure path handling across all dashboard operations like delete, edit, duplicate, etc.
Introduces consistent use of pathutil.BuildPath function for building URLs
Adds proper path prefixing to image paths in support project data
Improves URL generation across various dashboard components

WIP on feature/path-prefix
Adds support for path prefix configuration
…configuration to include init-dialogs.js for content scanning
@coderabbitai
Copy link

coderabbitai bot commented Oct 6, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds configurable PBW_PATH_PREFIX support with validation and a pathutil; updates startup, router, and many view files to build routes from the prefix. Replaces SweetAlert2 with a custom dialog module. Adds docs site, redirects, deploy workflow, README rebrand, sponsor updates, and minor static asset/config tweaks.

Changes

Cohort / File(s) Summary
Env & validation
internal/config/env.go, internal/config/env_validate.go, internal/validate/path_prefix.go, internal/validate/path_prefix_test.go, .env.example
Adds PBW_PATH_PREFIX env var, validation rules and tests, and documents the variable in the example.
Path util
internal/util/pathutil/pathutil.go, internal/util/pathutil/pathutil_test.go
New package to Set/Get/BuildPath with sync.Once and tests; centralizes path-prefix handling.
Bootstrap & routing
cmd/app/main.go, internal/view/router.go, internal/view/web/router.go
Calls SetPathPrefix at startup, introduces base router group using the prefix, mounts static/api/web routes under that base.
Static assets & global exposure
internal/view/static/static_fs.go, internal/view/web/layout/common.go, internal/view/web/component/logotype.go
Static file path building via BuildPath, injects window.PBW_PATH_PREFIX, and updates logo/static references for prefix.
Middleware, redirects & auth
internal/view/middleware/*.go, internal/view/web/auth/*.go, internal/view/web/layout/*, internal/view/web/router.go
Replaces literal redirect/route strings with pathutil.BuildPath across auth, middleware, and layout links; adds autofocus in some forms.
Views: dashboard, lists, actions
internal/view/web/dashboard/** (backups, databases, destinations, executions, restorations, webhooks, profile, ...)
Systematic replacement of literal URLs with pathutil.BuildPath(...) for links, forms, HTMX targets, redirects, and button actions.
Dialogs & HTMX integration
internal/view/static/js/app.js, internal/view/static/js/init-dialogs.js, internal/view/static/js/init-htmx.js, internal/view/static/js/init-sweetalert2.js (removed), internal/view/static/css/partials/sweetalert2.css (removed), internal/view/static/css/style.css, tailwind.config.ts
Removes SweetAlert2, adds custom initDialogs module, updates HTMX handlers to use customAlert/customConfirm, updates Tailwind content to include new JS.
Docs, redirects & CI deploy
.github/workflows/docs-deploy.yaml, docs/index.html, docs/_redirects, README.md
Adds Cloudflare Pages deploy workflow, new docs landing page and redirects, README rebranding/copy edits.
Misc
.prettierignore, assets/support-project-v1.json, internal/view/static/static_fs.go
Ignore build assets; sponsor JSON reordered/added; static file versioned paths now prefix-aware.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Start as App Start
  participant Env as Env Loader
  participant Val as validate.PathPrefix
  participant PU as pathutil
  participant Router as Router Init
  participant Browser as Client

  Start->>Env: read PBW_PATH_PREFIX
  Env->>Val: validate prefix
  Val-->>Env: result
  Start->>PU: SetPathPrefix(value)
  Router->>PU: GetPathPrefix()
  Router->>Browser: serve routes under prefix (static, api, web)
Loading
sequenceDiagram
  autonumber
  participant User as User
  participant UI as HTMX trigger
  participant Dialog as customConfirm
  participant Server as Backend

  User->>UI: click destructive action
  UI->>Dialog: window.customConfirm(text)
  alt confirmed
    Dialog-->>UI: {isConfirmed: true}
    UI->>Server: HTMX request (DELETE/POST)
    Server-->>UI: response
  else dismissed
    Dialog-->>UI: {isDismissed: true}
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

In burrows deep I tweak each trail,
I stitch a prefix to every rail.
Sweet alerts hopped off the lawn,
New dialogs greet the dawn.
Docs take flight — UFO Backup, hop on! 🚀🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.19% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The provided title clearly describes the primary intent of the pull request, which is merging the develop branch into main for the v0.5.1-rc.1 release, and it is concise, unambiguous, and free of extraneous details.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8282d9b and 9a2b0e2.

📒 Files selected for processing (1)
  • .github/workflows/docs-deploy.yaml (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (3)
internal/view/web/component/support_project.inc.js (1)

72-103: Consider cloning the data object before mutation.

The method mutates the input data object by reassigning its properties (lines 75, 83, 89, 95). If the original data object is referenced elsewhere, this could lead to unexpected side effects.

If data immutability is a concern, apply this diff to clone the data first:

 processData(data) {
+  const clonedData = JSON.parse(JSON.stringify(data));
   // Add path prefix to all image URLs
-  if (data.referralLinks) {
-    data.referralLinks = data.referralLinks.map((link) => ({
+  if (clonedData.referralLinks) {
+    clonedData.referralLinks = clonedData.referralLinks.map((link) => ({
       ...link,
       logo: this.prefixImagePath(link.logo),
     }));
   }

-  if (data.sponsors) {
-    if (data.sponsors.gold) {
-      data.sponsors.gold = data.sponsors.gold.map((sponsor) => ({
+  if (clonedData.sponsors) {
+    if (clonedData.sponsors.gold) {
+      clonedData.sponsors.gold = clonedData.sponsors.gold.map((sponsor) => ({
         ...sponsor,
         logo: this.prefixImagePath(sponsor.logo),
       }));
     }
-    if (data.sponsors.silver) {
-      data.sponsors.silver = data.sponsors.silver.map((sponsor) => ({
+    if (clonedData.sponsors.silver) {
+      clonedData.sponsors.silver = clonedData.sponsors.silver.map((sponsor) => ({
         ...sponsor,
         logo: this.prefixImagePath(sponsor.logo),
       }));
     }
-    if (data.sponsors.bronze) {
-      data.sponsors.bronze = data.sponsors.bronze.map((sponsor) => ({
+    if (clonedData.sponsors.bronze) {
+      clonedData.sponsors.bronze = clonedData.sponsors.bronze.map((sponsor) => ({
         ...sponsor,
         logo: this.prefixImagePath(sponsor.logo),
       }));
     }
   }

-  return data;
+  return clonedData;
 }
internal/util/pathutil/pathutil_test.go (2)

58-59: Fragile state manipulation breaks encapsulation.

Directly resetting unexported package variables (pathPrefix and pathPrefixOnce) is fragile and breaks encapsulation. This pattern works only because the test is in the same package, but it makes the tests brittle and harder to maintain.

Consider exposing a ResetForTesting() function in the pathutil package (build-tagged for test files only) or restructuring to avoid global state where possible.

Example approach with a test-only reset function in pathutil.go:

//go:build test
// +build test

package pathutil

func ResetForTesting() {
	pathPrefixOnce = sync.Once{}
	pathPrefix = ""
}

Then in the test:

 		t.Run(tt.name, func(t *testing.T) {
-			originalPrefix := pathPrefix
-			pathPrefixOnce = sync.Once{}
+			defer ResetForTesting()
 			SetPathPrefix(tt.prefix)
-			defer func() {
-				pathPrefixOnce = sync.Once{}
-				pathPrefix = originalPrefix
-			}()

 			result := BuildPath(tt.path)

76-76: Apply the same encapsulation improvement here.

Similar to the previous comment on TestBuildPath, consider using a ResetForTesting() function instead of directly manipulating unexported variables.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cafda5 and 8282d9b.

⛔ Files ignored due to path filters (3)
  • assets/logos/hetzner-horizontal.png is excluded by !**/*.png
  • assets/logos/hetzner.png is excluded by !**/*.png
  • internal/view/static/libs/sweetalert2/sweetalert2-11.13.1.min.js is excluded by !**/*.min.js
📒 Files selected for processing (68)
  • .env.example (1 hunks)
  • .github/workflows/docs-deploy.yaml (1 hunks)
  • .prettierignore (1 hunks)
  • README.md (5 hunks)
  • assets/support-project-v1.json (2 hunks)
  • cmd/app/main.go (3 hunks)
  • docs/_redirects (1 hunks)
  • docs/index.html (1 hunks)
  • internal/config/env.go (1 hunks)
  • internal/config/env_validate.go (1 hunks)
  • internal/util/pathutil/pathutil.go (1 hunks)
  • internal/util/pathutil/pathutil_test.go (1 hunks)
  • internal/validate/path_prefix.go (1 hunks)
  • internal/validate/path_prefix_test.go (1 hunks)
  • internal/view/middleware/require_auth.go (2 hunks)
  • internal/view/middleware/require_no_auth.go (2 hunks)
  • internal/view/router.go (2 hunks)
  • internal/view/static/css/partials/sweetalert2.css (0 hunks)
  • internal/view/static/css/style.css (0 hunks)
  • internal/view/static/js/app.js (1 hunks)
  • internal/view/static/js/init-dialogs.js (1 hunks)
  • internal/view/static/js/init-htmx.js (3 hunks)
  • internal/view/static/js/init-sweetalert2.js (0 hunks)
  • internal/view/static/static_fs.go (2 hunks)
  • internal/view/web/auth/create_first_user.go (5 hunks)
  • internal/view/web/auth/login.go (5 hunks)
  • internal/view/web/auth/logout.go (3 hunks)
  • internal/view/web/component/logotype.go (2 hunks)
  • internal/view/web/component/support_project.inc.js (3 hunks)
  • internal/view/web/dashboard/backups/create_backup.go (4 hunks)
  • internal/view/web/dashboard/backups/delete_backup.go (2 hunks)
  • internal/view/web/dashboard/backups/duplicate_backup.go (2 hunks)
  • internal/view/web/dashboard/backups/edit_backup.go (2 hunks)
  • internal/view/web/dashboard/backups/index.go (2 hunks)
  • internal/view/web/dashboard/backups/list_backups.go (3 hunks)
  • internal/view/web/dashboard/backups/manual_run.go (2 hunks)
  • internal/view/web/dashboard/databases/create_database.go (2 hunks)
  • internal/view/web/dashboard/databases/delete_database.go (2 hunks)
  • internal/view/web/dashboard/databases/edit_database.go (2 hunks)
  • internal/view/web/dashboard/databases/index.go (2 hunks)
  • internal/view/web/dashboard/databases/list_databases.go (3 hunks)
  • internal/view/web/dashboard/destinations/create_destination.go (2 hunks)
  • internal/view/web/dashboard/destinations/delete_destination.go (2 hunks)
  • internal/view/web/dashboard/destinations/edit_destination.go (2 hunks)
  • internal/view/web/dashboard/destinations/index.go (2 hunks)
  • internal/view/web/dashboard/destinations/list_destinations.go (3 hunks)
  • internal/view/web/dashboard/executions/index.go (2 hunks)
  • internal/view/web/dashboard/executions/list_executions.go (2 hunks)
  • internal/view/web/dashboard/executions/restore_execution.go (3 hunks)
  • internal/view/web/dashboard/executions/show_execution.go (2 hunks)
  • internal/view/web/dashboard/executions/soft_delete_execution.go (2 hunks)
  • internal/view/web/dashboard/profile/close_all_sessions.go (2 hunks)
  • internal/view/web/dashboard/profile/update_user.go (2 hunks)
  • internal/view/web/dashboard/restorations/index.go (2 hunks)
  • internal/view/web/dashboard/restorations/list_restorations.go (2 hunks)
  • internal/view/web/dashboard/webhooks/create_webhook.go (4 hunks)
  • internal/view/web/dashboard/webhooks/delete_webhook.go (2 hunks)
  • internal/view/web/dashboard/webhooks/duplicate_webhook.go (2 hunks)
  • internal/view/web/dashboard/webhooks/edit_webhook.go (3 hunks)
  • internal/view/web/dashboard/webhooks/index.go (2 hunks)
  • internal/view/web/dashboard/webhooks/list_webhooks.go (2 hunks)
  • internal/view/web/dashboard/webhooks/run_webhook.go (2 hunks)
  • internal/view/web/dashboard/webhooks/webhook_executions.go (3 hunks)
  • internal/view/web/layout/common.go (2 hunks)
  • internal/view/web/layout/dashboard_aside.go (3 hunks)
  • internal/view/web/layout/dashboard_header.go (2 hunks)
  • internal/view/web/router.go (3 hunks)
  • tailwind.config.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • internal/view/static/css/partials/sweetalert2.css
  • internal/view/static/js/init-sweetalert2.js
  • internal/view/static/css/style.css
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use structured logging with logger.KV{"key": value} for context
Use logger.FatalError() for startup failures

Files:

  • internal/view/web/dashboard/webhooks/create_webhook.go
  • internal/view/web/dashboard/databases/index.go
  • internal/view/web/dashboard/backups/create_backup.go
  • internal/view/web/dashboard/webhooks/run_webhook.go
  • internal/view/web/auth/create_first_user.go
  • internal/config/env_validate.go
  • internal/view/web/dashboard/webhooks/list_webhooks.go
  • internal/view/web/router.go
  • internal/view/web/dashboard/backups/delete_backup.go
  • cmd/app/main.go
  • internal/view/web/layout/dashboard_aside.go
  • internal/view/web/auth/logout.go
  • internal/view/web/dashboard/backups/duplicate_backup.go
  • internal/validate/path_prefix.go
  • internal/view/web/dashboard/webhooks/webhook_executions.go
  • internal/view/web/dashboard/databases/edit_database.go
  • internal/util/pathutil/pathutil_test.go
  • internal/util/pathutil/pathutil.go
  • internal/view/web/dashboard/restorations/index.go
  • internal/view/web/dashboard/backups/list_backups.go
  • internal/view/middleware/require_auth.go
  • internal/view/web/dashboard/executions/soft_delete_execution.go
  • internal/view/web/dashboard/backups/edit_backup.go
  • internal/validate/path_prefix_test.go
  • internal/view/web/dashboard/webhooks/index.go
  • internal/view/web/auth/login.go
  • internal/view/web/layout/dashboard_header.go
  • internal/view/web/dashboard/webhooks/duplicate_webhook.go
  • internal/view/web/dashboard/databases/create_database.go
  • internal/view/web/dashboard/backups/index.go
  • internal/view/web/dashboard/databases/list_databases.go
  • internal/view/web/dashboard/backups/manual_run.go
  • internal/view/web/dashboard/destinations/list_destinations.go
  • internal/view/static/static_fs.go
  • internal/view/middleware/require_no_auth.go
  • internal/view/web/dashboard/restorations/list_restorations.go
  • internal/view/web/dashboard/profile/close_all_sessions.go
  • internal/view/web/component/logotype.go
  • internal/view/web/dashboard/destinations/create_destination.go
  • internal/view/web/dashboard/profile/update_user.go
  • internal/view/web/dashboard/databases/delete_database.go
  • internal/view/web/dashboard/executions/restore_execution.go
  • internal/view/web/dashboard/destinations/index.go
  • internal/view/web/dashboard/webhooks/delete_webhook.go
  • internal/view/web/dashboard/webhooks/edit_webhook.go
  • internal/view/web/dashboard/executions/list_executions.go
  • internal/view/web/layout/common.go
  • internal/view/web/dashboard/destinations/delete_destination.go
  • internal/view/web/dashboard/destinations/edit_destination.go
  • internal/view/web/dashboard/executions/show_execution.go
  • internal/view/web/dashboard/executions/index.go
  • internal/view/router.go
  • internal/config/env.go
internal/view/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Access request context via internal/view/reqctx in web handlers

Files:

  • internal/view/web/dashboard/webhooks/create_webhook.go
  • internal/view/web/dashboard/databases/index.go
  • internal/view/web/dashboard/backups/create_backup.go
  • internal/view/web/dashboard/webhooks/run_webhook.go
  • internal/view/web/auth/create_first_user.go
  • internal/view/web/dashboard/webhooks/list_webhooks.go
  • internal/view/web/router.go
  • internal/view/web/dashboard/backups/delete_backup.go
  • internal/view/web/layout/dashboard_aside.go
  • internal/view/web/auth/logout.go
  • internal/view/web/dashboard/backups/duplicate_backup.go
  • internal/view/web/dashboard/webhooks/webhook_executions.go
  • internal/view/web/dashboard/databases/edit_database.go
  • internal/view/web/dashboard/restorations/index.go
  • internal/view/web/dashboard/backups/list_backups.go
  • internal/view/middleware/require_auth.go
  • internal/view/web/dashboard/executions/soft_delete_execution.go
  • internal/view/web/dashboard/backups/edit_backup.go
  • internal/view/web/dashboard/webhooks/index.go
  • internal/view/web/auth/login.go
  • internal/view/web/layout/dashboard_header.go
  • internal/view/web/dashboard/webhooks/duplicate_webhook.go
  • internal/view/web/dashboard/databases/create_database.go
  • internal/view/web/dashboard/backups/index.go
  • internal/view/web/dashboard/databases/list_databases.go
  • internal/view/web/dashboard/backups/manual_run.go
  • internal/view/web/dashboard/destinations/list_destinations.go
  • internal/view/static/static_fs.go
  • internal/view/middleware/require_no_auth.go
  • internal/view/web/dashboard/restorations/list_restorations.go
  • internal/view/web/dashboard/profile/close_all_sessions.go
  • internal/view/web/component/logotype.go
  • internal/view/web/dashboard/destinations/create_destination.go
  • internal/view/web/dashboard/profile/update_user.go
  • internal/view/web/dashboard/databases/delete_database.go
  • internal/view/web/dashboard/executions/restore_execution.go
  • internal/view/web/dashboard/destinations/index.go
  • internal/view/web/dashboard/webhooks/delete_webhook.go
  • internal/view/web/dashboard/webhooks/edit_webhook.go
  • internal/view/web/dashboard/executions/list_executions.go
  • internal/view/web/layout/common.go
  • internal/view/web/dashboard/destinations/delete_destination.go
  • internal/view/web/dashboard/destinations/edit_destination.go
  • internal/view/web/dashboard/executions/show_execution.go
  • internal/view/web/dashboard/executions/index.go
  • internal/view/router.go
internal/config/env_validate.go

📄 CodeRabbit inference engine (AGENTS.md)

Perform configuration validation in internal/config/env_validate.go

Files:

  • internal/config/env_validate.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Write table-driven tests using t.Run with a slice of structs
Mark reusable test helper functions with t.Helper()

Files:

  • internal/util/pathutil/pathutil_test.go
  • internal/validate/path_prefix_test.go
internal/util/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Provide comprehensive test coverage for packages under internal/util/

Files:

  • internal/util/pathutil/pathutil_test.go
internal/view/router.go

📄 CodeRabbit inference engine (AGENTS.md)

Mount web and API routes in internal/view/router.go using Echo

Files:

  • internal/view/router.go
internal/config/env.go

📄 CodeRabbit inference engine (AGENTS.md)

Load environment-based configuration in internal/config/env.go

Files:

  • internal/config/env.go
🧠 Learnings (5)
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/config/env_validate.go : Perform configuration validation in internal/config/env_validate.go

Applied to files:

  • internal/config/env_validate.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/view/**/*.go : Access request context via internal/view/reqctx in web handlers

Applied to files:

  • internal/view/web/auth/logout.go
  • internal/view/web/dashboard/backups/manual_run.go
  • internal/view/middleware/require_no_auth.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/util/**/*_test.go : Provide comprehensive test coverage for packages under internal/util/

Applied to files:

  • internal/util/pathutil/pathutil_test.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Require env vars PBW_ENCRYPTION_KEY and PBW_POSTGRES_CONN_STRING; support optional PBW_LISTEN_HOST, PBW_LISTEN_PORT, TZ

Applied to files:

  • .env.example
  • README.md
  • internal/config/env.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/view/router.go : Mount web and API routes in internal/view/router.go using Echo

Applied to files:

  • internal/view/router.go
🧬 Code graph analysis (53)
internal/view/web/dashboard/webhooks/create_webhook.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/databases/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/static/js/app.js (2)
internal/view/static/js/init-dialogs.js (1)
  • initDialogs (1-137)
internal/view/static/js/init-sweetalert2.js (3)
  • initSweetAlert2 (1-34)
  • swalAlert (15-20)
  • swalConfirm (22-30)
internal/view/web/dashboard/backups/create_backup.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/webhooks/run_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/auth/create_first_user.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/config/env_validate.go (1)
internal/validate/path_prefix.go (1)
  • PathPrefix (21-43)
internal/view/web/dashboard/webhooks/list_webhooks.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/router.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/delete_backup.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
cmd/app/main.go (1)
internal/util/pathutil/pathutil.go (2)
  • SetPathPrefix (12-16)
  • GetPathPrefix (19-21)
internal/view/web/layout/dashboard_aside.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/static/js/init-dialogs.js (1)
internal/view/static/js/init-sweetalert2.js (3)
  • swalAlert (15-20)
  • swalConfirm (22-30)
  • initSweetAlert2 (1-34)
internal/view/web/auth/logout.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/duplicate_backup.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/webhooks/webhook_executions.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/databases/edit_database.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/util/pathutil/pathutil_test.go (1)
internal/util/pathutil/pathutil.go (3)
  • SetPathPrefix (12-16)
  • BuildPath (30-35)
  • GetPathPrefix (19-21)
internal/view/web/dashboard/restorations/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/list_backups.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/middleware/require_auth.go (2)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/view/web/dashboard/executions/soft_delete_execution.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/edit_backup.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/validate/path_prefix_test.go (1)
internal/validate/path_prefix.go (1)
  • PathPrefix (21-43)
internal/view/web/dashboard/webhooks/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/auth/login.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/layout/dashboard_header.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/webhooks/duplicate_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/databases/create_database.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/databases/list_databases.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/backups/manual_run.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/destinations/list_destinations.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/static/static_fs.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/middleware/require_no_auth.go (2)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/view/web/dashboard/restorations/list_restorations.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/profile/close_all_sessions.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/component/logotype.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/destinations/create_destination.go (2)
internal/view/web/respondhtmx/respond.go (1)
  • Redirect (78-82)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/profile/update_user.go (2)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/profile/index.go (2)
  • indexPage (31-46)
  • h (16-29)
internal/view/web/dashboard/databases/delete_database.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/executions/restore_execution.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/destinations/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/webhooks/delete_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/webhooks/edit_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/static/js/init-htmx.js (1)
internal/view/static/js/init-sweetalert2.js (1)
  • swalConfirm (22-30)
internal/view/web/dashboard/executions/list_executions.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/layout/common.go (1)
internal/util/pathutil/pathutil.go (1)
  • GetPathPrefix (19-21)
internal/view/web/dashboard/destinations/delete_destination.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/destinations/edit_destination.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/executions/show_execution.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/web/dashboard/executions/index.go (1)
internal/util/pathutil/pathutil.go (1)
  • BuildPath (30-35)
internal/view/router.go (7)
internal/util/pathutil/pathutil.go (1)
  • GetPathPrefix (19-21)
internal/view/middleware/browser_cache.go (1)
  • BrowserCacheMiddlewareConfig (10-13)
internal/view/static/static_fs.go (1)
  • StaticFs (12-12)
internal/logger/logger.go (1)
  • FatalError (70-73)
internal/logger/kv.go (1)
  • KV (6-6)
internal/view/web/router.go (1)
  • MountRouter (16-50)
internal/view/api/router.go (1)
  • MountRouter (13-22)
🪛 dotenv-linter (3.3.0)
.env.example

[warning] 17-17: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 markdownlint-cli2 (0.18.1)
README.md

120-120: Images should have alternate text (alt text)

(MD045, no-alt-text)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Lint, test, and build the code (ubuntu-24.04-arm, linux/arm64)
  • GitHub Check: Lint, test, and build the code (ubuntu-24.04, linux/amd64)
  • GitHub Check: Lint, test, and build the code (ubuntu-24.04-arm, linux/arm64)
  • GitHub Check: Lint, test, and build the code (ubuntu-24.04, linux/amd64)
🔇 Additional comments (60)
internal/view/web/component/support_project.inc.js (2)

105-134: LGTM! Consistent data processing.

The changes ensure that both cached and freshly fetched data are processed uniformly through processData(), guaranteeing that logo paths are correctly prefixed regardless of the data source.


58-70: No changes required: window.PBW_PATH_PREFIX is always defined with default empty string.

internal/view/web/dashboard/executions/list_executions.go (1)

11-11: LGTM! Consistent path prefix integration.

The import of pathutil and usage of BuildPath for URL construction aligns with the project-wide refactoring to support configurable path prefixes. The change is minimal and correct.

Also applies to: 121-121

.prettierignore (1)

2-2: LGTM! Build directory properly excluded.

Adding the build directory to Prettier's ignore list is appropriate and follows standard practices for excluding generated artifacts.

internal/view/web/dashboard/destinations/index.go (1)

7-7: LGTM! Path prefix integration applied correctly.

The addition of pathutil import and use of BuildPath in the HxGet attribute follows the consistent pattern established across the codebase for supporting configurable path prefixes.

Also applies to: 59-59

internal/view/web/dashboard/executions/restore_execution.go (1)

10-10: LGTM! Restore workflow paths updated consistently.

Both the form submission (HxPost) and form loading (HxGet) endpoints now use pathutil.BuildPath, ensuring consistent path prefix handling throughout the restoration workflow.

Also applies to: 111-111, 226-226

internal/view/web/dashboard/backups/duplicate_backup.go (1)

4-6: LGTM! Duplicate action path construction updated.

The necessary imports (fmt, pathutil) are added and BuildPath is used correctly in the duplicate button to support path prefixing.

Also applies to: 33-33

internal/view/web/dashboard/backups/list_backups.go (1)

11-11: LGTM! Navigation and pagination paths updated consistently.

Both the executions link and pagination URLs now use pathutil.BuildPath, ensuring proper path prefix handling across backup list navigation.

Also applies to: 74-76, 129-131

docs/_redirects (2)

2-2: Verify the community redirect URL.

The community redirect points to https://ufobackup.uforg.dev, which appears to reference a different project name (ufobackup) than the repository (pgbackweb). Please confirm this is the intended URL or if it should be updated to match the project's domain.


3-8: LGTM! Redirect aliases provide convenient shorthand URLs.

The redirect mappings for project and author links are well-structured, with aliases (e.g., /r/twitter and /r/x) providing flexible shorthand URLs for external resources.

Also applies to: 11-15

internal/view/web/dashboard/destinations/delete_destination.go (1)

4-6: LGTM! Delete action path construction updated.

The necessary imports are added and pathutil.BuildPath is correctly used in the delete button to support configurable path prefixes.

Also applies to: 34-34

internal/view/web/dashboard/webhooks/edit_webhook.go (2)

106-106: Pathutil integration aligns with prefixed routes.

Switching the form action to pathutil.BuildPath correctly folds in the configured dashboard prefix.


131-131: Consistent modal fetch URL.

Using pathutil.BuildPath here keeps the edit modal loader in sync with the global prefix handling.

internal/view/web/dashboard/webhooks/create_webhook.go (3)

58-58: Redirect respects path prefix.

Good call swapping to pathutil.BuildPath; the post-create redirect now honors any configured base path.


90-90: Prefixed form submission.

Using pathutil.BuildPath here keeps the create form POST aligned with the global prefix handling.


115-115: Prefixed modal loader.

The modal fetch now routes through pathutil.BuildPath, matching the rest of the prefix-aware endpoints.

internal/view/web/dashboard/webhooks/webhook_executions.go (2)

92-94: Next-page URL honors prefix.

Wrapping the executions endpoint in pathutil.BuildPath keeps infinite scroll working under a custom base path.


262-263: Modal fetch aligned with prefixed routing.

The initial executions load now goes through pathutil.BuildPath, so path prefixes are consistently applied.

tailwind.config.ts (1)

6-9: Tailwind now scans dialog scripts.

Including init-dialogs.js in the content list ensures any dialog utility classes survive purging. 👍

internal/view/static/js/init-htmx.js (1)

9-24: Custom dialog promise contract confirmed window.customAlert and window.customConfirm resolve to {isConfirmed, isDismissed} as expected, so .then(...) usage is safe.

internal/validate/path_prefix.go (1)

21-43: LGTM!

The validation logic is correct and well-documented. The implementation properly validates:

  • Empty string as valid (no prefix)
  • Required leading slash
  • No trailing slash
  • No whitespace

The code is clear and maintainable.

docs/index.html (1)

47-51: Verify the hardcoded version tag in the logo URL.

The logo image URL references a specific git tag (v0.5.0). This means the logo won't update automatically with new versions of the application. Confirm this is intentional for version stability, or consider using a branch reference (e.g., refs/heads/main) to automatically reflect the latest logo.

internal/util/pathutil/pathutil.go (2)

10-16: LGTM!

The use of sync.Once ensures thread-safe initialization and prevents the path prefix from being changed after initial setup. This is the correct pattern for application-level configuration.


30-35: Consider documenting the caller's responsibility for path format.

BuildPath concatenates the prefix and path without validating that path starts with /. If a caller passes "dashboard" instead of "/dashboard", the result would be malformed (e.g., "/pgbackwebdashboard" instead of "/pgbackweb/dashboard").

While this may be intentional (placing responsibility on the caller), consider adding a note in the documentation or a panic/validation check to catch this common mistake during development.

For example, you could add validation like:

 func BuildPath(path string) string {
 	if pathPrefix == "" {
 		return path
 	}
+	if path != "" && !strings.HasPrefix(path, "/") {
+		panic(fmt.Sprintf("BuildPath: path must start with / or be empty, got: %s", path))
+	}
 	return pathPrefix + path
 }
internal/view/web/dashboard/destinations/edit_destination.go (1)

62-62: LGTM!

The update correctly applies the path prefix to the HTMX post URL, consistent with the broader path prefix support introduced across the codebase.

internal/view/web/dashboard/backups/edit_backup.go (1)

94-94: LGTM!

The change correctly applies the path prefix to the dynamically constructed edit URL. The path is properly formatted with a leading slash before being passed to BuildPath.

internal/view/web/dashboard/webhooks/list_webhooks.go (1)

95-99: LGTM!

The change correctly applies the path prefix to the pagination URL. The query parameters are properly added after building the base path, maintaining the existing pagination logic.

internal/view/web/dashboard/webhooks/run_webhook.go (1)

48-48: LGTM!

The change correctly applies the path prefix to the webhook run endpoint URL. The path is properly formatted with a leading slash before being passed to BuildPath.

internal/view/web/dashboard/webhooks/duplicate_webhook.go (1)

4-6: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for URL construction is correct and enables configurable path prefix for subpath deployments. The pattern is consistent with similar changes across the codebase.

Also applies to: 33-33

internal/view/web/dashboard/executions/show_execution.go (1)

4-4: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for the download button href is correct and consistent with the broader refactor to support configurable path prefixes across the application.

Also applies to: 9-9, 126-126

internal/view/web/dashboard/webhooks/delete_webhook.go (1)

4-6: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for the delete webhook URL is correct and follows the established pattern for enabling path prefix configuration.

Also applies to: 33-33

internal/view/web/dashboard/destinations/create_destination.go (1)

5-5: LGTM! Consistent path prefix support.

The migration of both the redirect path and form action URLs to pathutil.BuildPath is correct and consistent with the broader refactor to support configurable path prefixes.

Also applies to: 49-49, 55-55

internal/view/web/dashboard/backups/manual_run.go (1)

5-5: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for the manual run URL is correct and consistent with the established pattern for enabling path prefix configuration.

Also applies to: 7-7, 32-32

internal/view/web/dashboard/executions/soft_delete_execution.go (1)

4-6: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for the delete execution URL is correct and follows the established pattern for enabling path prefix configuration.

Also applies to: 34-34

internal/view/web/dashboard/backups/create_backup.go (1)

10-10: LGTM! Consistent path prefix support.

The migration of redirect, form action, and HTMX trigger URLs to pathutil.BuildPath is correct and consistent. All URL construction points in this file have been properly updated to support configurable path prefixes.

Also applies to: 74-74, 109-109, 326-326

internal/view/web/dashboard/backups/delete_backup.go (1)

4-6: LGTM! Consistent path prefix support.

The migration to pathutil.BuildPath for the delete backup URL is correct and follows the established pattern for enabling path prefix configuration.

Also applies to: 33-33

internal/view/web/layout/dashboard_aside.go (1)

6-6: LGTM! Consistent path prefix integration.

The migration to pathutil.BuildPath() for all navigation links and assets is correctly implemented and aligns with the centralized path prefix mechanism introduced across the codebase.

Also applies to: 26-26, 49-105

internal/view/web/dashboard/destinations/list_destinations.go (1)

11-11: LGTM! Path construction properly updated.

The use of pathutil.BuildPath() for the executions link, test connection endpoint, and pagination URL is correct. Including query parameters within the path string works as expected with the path prefix mechanism.

Also applies to: 66-136

internal/view/web/dashboard/databases/list_databases.go (1)

11-11: LGTM! Consistent with path prefix refactor.

The changes mirror the pattern used in the destinations file and correctly apply path prefix handling to executions links, test actions, and pagination.

Also applies to: 68-110

README.md (1)

32-37: Good addition of path prefix documentation.

The documentation for PBW_PATH_PREFIX clearly explains its purpose and usage constraints (must start with /, not end with /). The rebranding note and feature updates improve clarity.

Also applies to: 114-114

internal/view/web/dashboard/profile/close_all_sessions.go (1)

5-5: LGTM! Logout action correctly uses path prefix.

The logout endpoint now correctly respects the configured path prefix.

Also applies to: 19-19

internal/view/web/layout/common.go (1)

4-4: LGTM! Smart client-side path prefix injection.

Exposing window.PBW_PATH_PREFIX as a global JavaScript variable enables client-side code to construct URLs that respect the configured path prefix. This bridges server-side and client-side path handling effectively.

Also applies to: 36-37

internal/view/web/dashboard/backups/index.go (1)

7-7: LGTM! Initial list load uses path prefix correctly.

The backup list endpoint correctly uses pathutil.BuildPath() for the initial HTMX load trigger.

Also applies to: 54-54

internal/view/middleware/require_no_auth.go (1)

6-6: LGTM! Redirect consistency maintained.

Using the same redirectPath constructed via BuildPath() for both the HTMX header redirect and HTTP redirect ensures consistent behavior across both navigation mechanisms.

Also applies to: 17-19

internal/view/web/auth/logout.go (1)

4-4: LGTM!

Clean migration to centralized path construction via pathutil.BuildPath. The logout handlers now correctly support configurable path prefixes while preserving existing redirect behavior.

Also applies to: 19-19, 32-32

internal/view/web/dashboard/databases/index.go (1)

7-7: LGTM!

The migration to pathutil.BuildPath for the HTMX endpoint is correct and preserves the query parameters.

Also applies to: 46-46

internal/view/static/js/app.js (1)

2-2: LGTM!

Clean migration from SweetAlert2 to the custom dialogs system. The new implementation exposes compatible global APIs (window.customAlert, window.customConfirm) and removes an external dependency.

Also applies to: 8-8

.env.example (1)

15-17: LGTM!

The new PBW_PATH_PREFIX environment variable is well-documented with a clear example. The static analysis warning about quote characters is a false positive—the empty quotes are intentional in an example file to demonstrate the expected format.

internal/view/web/component/logotype.go (1)

4-4: LGTM!

The logotype component now correctly uses pathutil.BuildPath for the logo image source, ensuring it works under configurable path prefixes.

Also applies to: 16-16

internal/view/web/dashboard/databases/create_database.go (1)

7-7: LGTM!

The migration to pathutil.BuildPath is correct for both the post-creation redirect and the HTMX form submission endpoints. All URL construction is now centralized.

Also applies to: 45-45, 51-51

internal/view/web/dashboard/restorations/index.go (1)

7-7: LGTM!

The base URL construction now correctly uses pathutil.BuildPath, while preserving the existing query parameter logic with strutil.AddQueryParamToUrl. This ensures the path prefix is applied before adding query parameters.

Also applies to: 70-70

internal/view/web/dashboard/databases/edit_database.go (1)

7-7: LGTM!

The HTMX form submission endpoints now correctly use pathutil.BuildPath for centralized URL construction, consistent with the create database handler.

Also applies to: 59-59

internal/view/web/dashboard/restorations/list_restorations.go (1)

113-113: LGTM!

The path construction correctly uses pathutil.BuildPath and appends query parameters afterward, maintaining compatibility with the pagination and filtering logic.

internal/view/web/router.go (1)

25-42: LGTM!

All redirect paths correctly utilize pathutil.BuildPath, ensuring consistent path prefix handling across authentication flows and dashboard navigation.

internal/view/web/dashboard/webhooks/index.go (1)

49-49: LGTM!

The path construction correctly uses pathutil.BuildPath with the query parameter included in the path string, which is appropriate since BuildPath only prepends the configured prefix.

internal/config/env.go (1)

15-15: LGTM!

The PBW_PATH_PREFIX field is properly defined following the existing environment variable pattern, with an empty default value making the path prefix optional as intended.

internal/config/env_validate.go (1)

19-21: LGTM!

The path prefix validation is correctly implemented using validate.PathPrefix, with a clear error message that accurately describes the validation rules (must start with /, must not end with /, or be empty). As per coding guidelines.

internal/view/web/dashboard/profile/update_user.go (1)

52-52: LGTM!

The form submission path correctly uses pathutil.BuildPath, ensuring the profile update form works correctly when the application is served under a path prefix.

internal/view/middleware/require_auth.go (1)

33-40: LGTM!

The redirect logic correctly handles both HTMX-based and browser-based redirects consistently by using pathutil.BuildPath for both htmx.ServerSetRedirect and c.Redirect, ensuring proper navigation regardless of the request type.

internal/view/static/static_fs.go (1)

32-46: LGTM!

The implementation correctly prepends the path prefix before appending the version query parameter, ensuring static files are properly referenced when the application is served under a subpath. The added comments clearly document the integration with the path prefix system.

Comment on lines +11 to +13
"logo": "https://raw.githubusercontent.com/eduardolat/pgbackweb/refs/heads/develop/assets/logos/hetzner-horizontal.png",
"link": "https://hetzner.cloud/?ref=TdOypLgK8yGR",
"description": "Get started with Hetzner Cloud today and enjoy €20 in free credits just for signing up through this link! Their powerful cloud servers offer excellent performance at competitive prices. After you spend your first €10, I'll receive €10 in credits too, making it a win-win for both of us!"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid hotlinking logos from a mutable GitHub branch

Both the Hetzner and FetchGoat logos point to raw.githubusercontent.com/.../refs/heads/develop/.... Those URLs rely on the branch name existing forever and will 404 or change unexpectedly if the branch is renamed, deleted, or the repo reorganizes assets—breaking the images in production. Please add the logo files to the deployed static assets (as you do with other logos) or pin the URLs to an immutable location (e.g., a tagged release or CDN).

Also applies to: 45-46

🤖 Prompt for AI Agents
In assets/support-project-v1.json around lines 11-13 (also apply same change to
lines 45-46), the logo URLs hotlink to raw.githubusercontent.com with a branch
ref which can break if the branch is renamed or removed; replace those fragile
external links by either (A) adding the Hetzner and FetchGoat logo files into
the project's deployed static assets folder and updating the JSON to point to
the local/static asset paths, or (B) pinning the external URLs to an immutable
location (e.g., a tagged release URL or a CDN/GitHub release asset URL) so the
links won’t change; ensure you add the files to the repo, update the JSON
entries, and verify the assets are included in the build/deploy pipeline.

)

func TestBuildPath(t *testing.T) {
t.Helper()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove misplaced t.Helper() call.

According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.

Apply this diff:

 func TestBuildPath(t *testing.T) {
-	t.Helper()
-
 	tests := []struct {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
t.Helper()
func TestBuildPath(t *testing.T) {
tests := []struct {
name string
prefix string
path string
want string
}{
// test cases...
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// ...
})
}
}
🤖 Prompt for AI Agents
In internal/util/pathutil/pathutil_test.go around line 9, the test contains a
misplaced t.Helper() call; remove the t.Helper() invocation from the test
function body so only actual helper functions use t.Helper(); if you intended to
mark a helper, move the t.Helper() call into that helper function instead and
leave the test function without it.

}

func TestGetPathPrefix(t *testing.T) {
t.Helper()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove misplaced t.Helper() call.

According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.

Apply this diff:

 func TestGetPathPrefix(t *testing.T) {
-	t.Helper()
 	originalPrefix := pathPrefix
🤖 Prompt for AI Agents
internal/util/pathutil/pathutil_test.go around line 74: the test contains a
misplaced call to t.Helper() on the test function itself; remove the t.Helper()
invocation from this test (delete the line at 74) so that t.Helper() is only
used inside reusable helper functions.

import "testing"

func TestPathPrefix(t *testing.T) {
t.Helper()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove misplaced t.Helper() call.

According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.

Apply this diff:

 func TestPathPrefix(t *testing.T) {
-	t.Helper()
-
 	tests := []struct {
🤖 Prompt for AI Agents
internal/validate/path_prefix_test.go around line 6: the test function contains
a misplaced t.Helper() call which should only be used inside reusable helper
functions; remove the t.Helper() invocation from the test function so it is no
longer called at this location (leave helper functions' t.Helper() unchanged if
present).

Comment on lines +56 to +57
backdrop.onclick = () => closeDialog(dialogId, resolve, !isConfirm);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Backdrop/ESC dismissal flips confirmation state

When showing an alert (isConfirm === false), both the backdrop click (Line 56) and ESC handler (Line 110) resolve with !isConfirm, i.e., true. That incorrectly marks dismissals as confirmations, diverging from the previous SweetAlert2 semantics and can falsely signal user acknowledgement. Please resolve dismissals with false instead.

-    backdrop.onclick = () => closeDialog(dialogId, resolve, !isConfirm);
+    backdrop.onclick = () => closeDialog(dialogId, resolve, false);
...
-        closeDialog(dialogId, resolve, !isConfirm);
+        closeDialog(dialogId, resolve, false);

Also applies to: 109-111

🤖 Prompt for AI Agents
In internal/view/static/js/init-dialogs.js around lines 56-57 and 109-111, the
backdrop click and ESC key handlers call closeDialog(..., !isConfirm) so
dismissals are treated as confirmations when isConfirm is false; change those
calls to resolve dismissals as false (e.g., use closeDialog(dialogId, resolve,
false)) so clicking the backdrop or pressing ESC always resolves as a dismissal
(false) rather than flipping the confirmation state.


## Screenshot

<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add alt text to the screenshot image.

The screenshot image is missing alternative text, which affects accessibility for screen reader users.

Apply this diff to add descriptive alt text:

-<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" />
+<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" alt="PG Back Web dashboard interface showing backup management features" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" />
<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" alt="PG Back Web dashboard interface showing backup management features" />
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

120-120: Images should have alternate text (alt text)

(MD045, no-alt-text)

🤖 Prompt for AI Agents
In README.md around line 120 the screenshot <img> tag lacks alt text which harms
accessibility; update the tag to include a concise, descriptive alt attribute
(for example: alt="pgbackweb web UI showing dashboard and navigation with
database list and query results") so screen readers can convey the image
content.

@eduardolat eduardolat merged commit a1c38a1 into main Oct 6, 2025
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants