Skip to content

feat(updates): add API endpoints for update management, backup, chang…#110

Merged
JoachimLK merged 2 commits into
mainfrom
feat/improve-self-hosting-updates
Mar 15, 2026
Merged

feat(updates): add API endpoints for update management, backup, chang…#110
JoachimLK merged 2 commits into
mainfrom
feat/improve-self-hosting-updates

Conversation

@JoachimLK
Copy link
Copy Markdown
Contributor

@JoachimLK JoachimLK commented Mar 15, 2026

…elog, system info, and version check

  • Implemented POST /api/updates/apply to trigger self-hosted updates via Docker Compose.
  • Created POST /api/updates/backup for PostgreSQL database backups before updates.
  • Added GET /api/updates/changelog to parse and return structured changelog entries from CHANGELOG.md.
  • Developed GET /api/updates/system to provide system information for diagnostics.
  • Introduced GET /api/updates/version to compare the running version against the latest GitHub release.

Summary

  • What does this PR change?
  • Why is this needed?

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Chore

Validation

  • I tested locally
  • I added/updated relevant documentation
  • I verified multi-tenant scoping and auth behavior for affected API paths

DCO

  • All commits in this PR are signed off (Signed-off-by) via git commit -s

Summary by CodeRabbit

  • New Features

    • Added Updates dashboard with version checks, one-click update flow, system health panel, backup actions, and changelog viewer
    • Added an Updates button in the app header for quick access
  • Documentation

    • Added comprehensive self-hosting guide covering installation, configuration, updates, backups, security, and troubleshooting
  • Chores

    • Removed duplicate changelog entries to reduce redundancy

…elog, system info, and version check

- Implemented POST /api/updates/apply to trigger self-hosted updates via Docker Compose.
- Created POST /api/updates/backup for PostgreSQL database backups before updates.
- Added GET /api/updates/changelog to parse and return structured changelog entries from CHANGELOG.md.
- Developed GET /api/updates/system to provide system information for diagnostics.
- Introduced GET /api/updates/version to compare the running version against the latest GitHub release.
@railway-app
Copy link
Copy Markdown

railway-app Bot commented Mar 15, 2026

🚅 Deployed to the reqcore-pr-110 environment in applirank

Service Status Web Updated (UTC)
applirank ✅ Success (View Logs) Mar 15, 2026 at 10:09 am

@railway-app railway-app Bot temporarily deployed to applirank / reqcore-pr-110 March 15, 2026 09:46 Destroyed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 15, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a self-hosting and updates subsystem: documentation (SELF-HOSTING.md), UI entry and dashboard for updates, five server APIs (version, system, changelog, backup, apply), Dockerfile/docker-compose adjustments, and cleanup of duplicate CHANGELOG.md entries.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md, SELF-HOSTING.md
Removed duplicated changelog blocks; added comprehensive SELF-HOSTING.md covering installation, config, updates, backups, security, monitoring, and troubleshooting.
Frontend — Updates UI
app/components/AppTopBar.vue, app/pages/dashboard/updates.vue
Added Updates button to top bar; new updates dashboard with version check, system health panel, changelog viewer, backup and one‑click update flows, owner‑only guards, and loading/error states.
Server — Update APIs
server/api/updates/version.get.ts, server/api/updates/system.get.ts, server/api/updates/changelog.get.ts, server/api/updates/backup.post.ts, server/api/updates/apply.post.ts
New endpoints: version (GitHub latest release check), system (diagnostics: DB, storage, runtime, deployment), changelog (parse CHANGELOG.md), backup (pg_dump to /data/backups with fallbacks), apply (git pull + docker compose rebuild flow). New types/structured responses and owner permission checks.
Infrastructure
docker-compose.yml, Dockerfile
Added backups_data volume and mount for /data/backups; Dockerfile updated to install postgresql client tools for pg_dump support.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Dashboard as Updates Dashboard
    participant VersionAPI as /api/updates/version
    participant BackupAPI as /api/updates/backup
    participant ApplyAPI as /api/updates/apply
    participant GitHub as GitHub API
    participant DB as PostgreSQL
    participant Docker as Docker Engine

    Client->>Dashboard: Open Updates Page
    activate Dashboard

    Dashboard->>VersionAPI: GET /api/updates/version
    activate VersionAPI
    VersionAPI->>GitHub: Query latest release
    GitHub-->>VersionAPI: Release info
    VersionAPI-->>Dashboard: currentVersion, latestVersion, updateAvailable
    deactivate VersionAPI

    alt Update Available
        Client->>Dashboard: Click "Install Update"
        Dashboard->>BackupAPI: POST /api/updates/backup
        activate BackupAPI
        BackupAPI->>DB: pg_dump
        DB-->>BackupAPI: SQL dump file
        BackupAPI-->>Dashboard: { success, filename }
        deactivate BackupAPI

        Dashboard->>ApplyAPI: POST /api/updates/apply
        activate ApplyAPI
        ApplyAPI->>Docker: git pull origin main
        Docker-->>ApplyAPI: git pull output
        ApplyAPI->>Docker: docker compose up --build --detach
        Docker-->>ApplyAPI: rebuild & restart output
        ApplyAPI-->>Dashboard: { success, steps }
        deactivate ApplyAPI
    end

    deactivate Dashboard
Loading
sequenceDiagram
    participant Client
    participant Dashboard as Updates Dashboard
    participant SystemAPI as /api/updates/system
    participant ChangelogAPI as /api/updates/changelog
    participant DB as PostgreSQL
    participant MinIO as MinIO/S3
    participant FS as Filesystem

    Client->>Dashboard: Load Updates Page
    activate Dashboard

    par Health Check & Changelog
        Dashboard->>SystemAPI: GET /api/updates/system
        activate SystemAPI
        SystemAPI->>DB: SELECT 1
        SystemAPI->>MinIO: HeadBucket
        SystemAPI->>FS: Check /.dockerenv
        SystemAPI-->>Dashboard: diagnostics object
        deactivate SystemAPI
    and
        Dashboard->>ChangelogAPI: GET /api/updates/changelog
        activate ChangelogAPI
        ChangelogAPI->>FS: Read CHANGELOG.md & package.json
        ChangelogAPI-->>Dashboard: entries[], currentVersion
        deactivate ChangelogAPI
    end

    Dashboard->>Dashboard: Render health and changelog
    deactivate Dashboard
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through changelogs, trimmed the mess,

Brought docs and dashboards to tidy progress,
Backups nestled safe in a data chest,
Git and Docker dance, the system will rest,
A cheerful hop for self-hosters' success!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description lists the implemented API endpoints but does not fill in the template sections (Summary rationale, Type of change selection, or validation/DCO checklist marks). Complete the template by explaining why these endpoints are needed, selecting the appropriate change type checkbox, and confirming validation and DCO compliance.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes—adding API endpoints for updates, backup, changelog, and version checking.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/improve-self-hosting-updates
📝 Coding Plan
  • Generate coding plan for human review comments

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
Copy Markdown

@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: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/AppTopBar.vue`:
- Around line 199-209: The Updates icon link is hidden on mobile and lacks an
accessible name; update the NuxtLink (the Updates button using ArrowUpCircle and
isActiveRoute) to include an explicit aria-label (e.g., aria-label="Updates and
changelog") and make it visible on small screens (remove or adjust the "hidden
sm:flex" class) so it appears in the mobile toolbar, and also add "updates" (or
the same route $localePath('/dashboard/updates')) to the mobile menu data where
mainNav and "New Job" are rendered so the Updates page is reachable from mobile.

In `@app/pages/dashboard/updates.vue`:
- Around line 243-254: The UI currently shows "Up to date" when versionInfo is
null; change the header and the fallback template to only claim up-to-date when
versionInfo exists and versionInfo.updateAvailable is false. Update the h2
conditional and the last <template> so they check versionInfo (e.g., use
versionLoading ? "Checking…" : versionInfo ? (versionInfo.updateAvailable ?
"Update available" : "Up to date") : "Update status unavailable"), and change
the paragraph fallback to show a neutral message when versionInfo is missing
(e.g., "Update status unavailable" or similar) instead of "You're running the
latest version"; keep use of versionInfo.latestVersion and
versionInfo.currentVersion only when versionInfo is present.
- Around line 592-598: The template currently treats failed fetches and
genuinely empty changelogs the same by only checking entries.length; add a
reactive error flag (e.g., changelogError) alongside entries, set changelogError
= true inside the changelog fetch function (the method that populates entries —
e.g., fetchChangelog / loadEntries) when the network/API call fails and clear it
on successful fetch, then change the template logic so the empty-state block is
shown only when entries.length === 0 && !changelogError and add a new error
block (or modify the existing block) to display a distinct error message when
changelogError === true. Ensure the fetch function records the actual error (for
logging) and toggles the flag appropriately.
- Around line 467-472: The panel currently handles loading
(v-if="systemLoading") and success (v-else-if="systemInfo") but has no fallback,
so when loading finishes with no data the panel is blank; update the template in
updates.vue to add an explicit v-else block after the existing v-if/v-else-if
pair (i.e., after the elements referencing systemLoading and systemInfo) that
renders a clear failure state (e.g., a message like "System information
unavailable" and optional retry action) so users see a meaningful error UI when
systemInfo is falsy.

In `@SELF-HOSTING.md`:
- Around line 191-193: The fenced code blocks in SELF-HOSTING.md (example blocks
around the snippets at lines 191-193, 318-322, and 625-640) lack language
identifiers and are flagged by markdownlint; update each opening fence from ```
to a labeled fence such as ```text or ```plaintext so the linter recognizes them
(e.g., change the three unlabeled fenced blocks to use ```text).

In `@server/api/updates/apply.post.ts`:
- Around line 96-124: The rebuild currently runs execFileAsync('docker',
['compose', 'up', ...]) inside the container serving the request (the "Rebuild &
restart" step), which will tear down the caller and make the HTTP response
unreliable; change this to hand off the work to an external updater: either
spawn a detached background process (use child_process.spawn with detached: true
and unref()) to run a small updater script that performs the docker compose
rebuild, or write an update request to a file/queue that a sidecar/updater
service polls; update the code paths around the execFileAsync call and the
"Rebuild & restart" step so the handler returns a success status immediately
after scheduling the external update and does not block on or directly invoke
the in-container docker compose command.
- Around line 75-76: The code currently runs execFileAsync('git', ['pull',
'origin', 'main']) which always updates main; instead fetch and check out the
release tag that was validated by version.get. Replace the pull of origin/main
with steps that use the verified release tag (e.g., a releaseTag variable coming
from the request or version check): run git fetch --tags (or git fetch origin)
and then git checkout -f "refs/tags/<releaseTag>" (or git reset --hard
"<releaseTag>") via execFileAsync to ensure the repo is moved to the exact
release commit rather than the main branch; update the execFileAsync
invocation(s) in apply.post to reference that releaseTag.
- Around line 58-103: The updater currently assumes the container is a repo
checkout and can run git/docker commands; add a pre-check before running
execFileAsync('git'...) and the docker compose call to verify the runtime has a
repository and compose file: check that '/app/.git' exists and that either
'/app/docker-compose.yml' or '/app/docker-compose.yaml' (or 'docker-compose.yml'
variants) exist (use fs.stat or fs.access), and if those checks fail push a
clear failure UpdateResult (using the existing steps array and UpdateResult
shape) explaining the container is not a repo/compose layout and instructing
manual update; update the error message returned where execFileAsync('git'...)
or the docker compose block would run to short-circuit earlier when these files
are missing and avoid attempting git pull/docker compose in apply.post.ts
(referencing execFileAsync, steps, and UpdateResult).

In `@server/api/updates/backup.post.ts`:
- Around line 28-34: The current logic only calls mkdir(backupDir, { recursive:
true }) and assumes writability; instead, after ensuring the directory exists
(via mkdir or otherwise) probe actual write access before assigning effectiveDir
(for example using fs.access with fs.constants.W_OK or attempting to
create+remove a temp file) so that root-owned or read-only mounts are detected
and you fall back to '/tmp'. Apply the same writable-probe fix to the other
similar block (lines 48-55) that sets effectiveDir so both code paths verify
real write permission before invoking pg_dump or other writers.
- Around line 48-55: The handler in server/api/updates/backup.post.ts currently
assumes the pg_dump binary is present when calling execFileAsync('pg_dump',
...); modify the handler to first check for pg_dump availability (e.g., attempt
a lightweight execFileAsync('which' or 'pg_dump --version') or fs.access) and if
absent provide a safe fallback: either (A) return a clear 5xx error explaining
pg_dump is not installed, or (B) implement a Node-side dump using the 'pg'
client (connect via the same host/port/user/database and stream a logical dump
by enumerating tables and using COPY TO STDOUT or SELECTs to write schema+data
into backupPath). Update the code path around execFileAsync to use this
check/fallback so the endpoint does not assume pg_dump exists.

In `@server/api/updates/version.get.ts`:
- Around line 23-31: The fetch to GitHub in version.get.ts (the call that
assigns to response using owner, repo and currentVersion) lacks a timeout; wrap
the request with an AbortController: create controller = new AbortController(),
start a timer (e.g. 5000ms) that calls controller.abort(), pass
controller.signal to fetch, and clear the timer after fetch resolves; keep the
existing try/catch so the abort will fall into the current error handling and
return the default response.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91f7c3bc-6d36-44c2-bbb4-be6645c6d58f

📥 Commits

Reviewing files that changed from the base of the PR and between 60e0840 and 3a5d96e.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • SELF-HOSTING.md
  • app/components/AppTopBar.vue
  • app/pages/dashboard/updates.vue
  • docker-compose.yml
  • server/api/updates/apply.post.ts
  • server/api/updates/backup.post.ts
  • server/api/updates/changelog.get.ts
  • server/api/updates/system.get.ts
  • server/api/updates/version.get.ts
💤 Files with no reviewable changes (1)
  • CHANGELOG.md

Comment on lines +199 to +209
<!-- Updates button -->
<NuxtLink
:to="$localePath('/dashboard/updates')"
class="hidden sm:flex items-center justify-center size-8 rounded-lg transition-all duration-200 no-underline"
:class="isActiveRoute('/dashboard/updates', false)
? 'text-brand-600 dark:text-brand-400 bg-brand-50 dark:bg-brand-950/40'
: 'text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-200 hover:bg-surface-100 dark:hover:bg-surface-800'"
title="Updates & changelog"
>
<ArrowUpCircle class="size-4" />
</NuxtLink>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Expose the Updates route on mobile and give this icon link an accessible name.

This control disappears below sm, and the mobile menus in this file only render mainNav plus “New Job”, so the new page has no visible mobile entry. It is also icon-only with just a title, which does not provide a reliable accessible name—please add a mobile nav item and an explicit aria-label.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/AppTopBar.vue` around lines 199 - 209, The Updates icon link
is hidden on mobile and lacks an accessible name; update the NuxtLink (the
Updates button using ArrowUpCircle and isActiveRoute) to include an explicit
aria-label (e.g., aria-label="Updates and changelog") and make it visible on
small screens (remove or adjust the "hidden sm:flex" class) so it appears in the
mobile toolbar, and also add "updates" (or the same route
$localePath('/dashboard/updates')) to the mobile menu data where mainNav and
"New Job" are rendered so the Updates page is reachable from mobile.

Comment thread app/pages/dashboard/updates.vue Outdated
Comment thread app/pages/dashboard/updates.vue
Comment on lines +592 to +598
v-else-if="entries.length === 0"
class="rounded-xl border border-surface-200 dark:border-surface-700 bg-white dark:bg-surface-900 p-12 text-center"
>
<RefreshCw class="size-8 text-surface-300 dark:text-surface-600 mx-auto mb-3" />
<div class="text-sm font-medium text-surface-500 dark:text-surface-400">No changelog entries found</div>
<div class="text-xs text-surface-400 dark:text-surface-500 mt-1">The CHANGELOG.md file may be missing or empty.</div>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Differentiate changelog fetch errors from true empty data.

Line 592 treats failed loads and genuinely empty changelogs the same, which can hide operational/API issues.

Proposed fix
-    <div
-      v-else-if="entries.length === 0"
+    <div
+      v-else-if="status === 'error'"
+      class="rounded-xl border border-danger-200 dark:border-danger-900 bg-danger-50/40 dark:bg-danger-950/20 p-12 text-center"
+    >
+      <AlertTriangle class="size-8 text-danger-500 mx-auto mb-3" />
+      <div class="text-sm font-medium text-danger-600 dark:text-danger-400">Failed to load changelog</div>
+      <div class="text-xs text-danger-500/80 mt-1">Please retry in a moment.</div>
+    </div>
+    <div
+      v-else-if="entries.length === 0"
       class="rounded-xl border border-surface-200 dark:border-surface-700 bg-white dark:bg-surface-900 p-12 text-center"
     >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/pages/dashboard/updates.vue` around lines 592 - 598, The template
currently treats failed fetches and genuinely empty changelogs the same by only
checking entries.length; add a reactive error flag (e.g., changelogError)
alongside entries, set changelogError = true inside the changelog fetch function
(the method that populates entries — e.g., fetchChangelog / loadEntries) when
the network/API call fails and clear it on successful fetch, then change the
template logic so the empty-state block is shown only when entries.length === 0
&& !changelogError and add a new error block (or modify the existing block) to
display a distinct error message when changelogError === true. Ensure the fetch
function records the actual error (for logging) and toggles the flag
appropriately.

Comment thread SELF-HOSTING.md
Comment on lines +191 to +193
```
http://localhost:3000
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language identifiers to these fenced blocks.

markdownlint is already flagging these fences, so docs lint will keep failing until they are labeled. text/plaintext is enough for all three examples here.

Also applies to: 318-322, 625-640

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 191-191: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SELF-HOSTING.md` around lines 191 - 193, The fenced code blocks in
SELF-HOSTING.md (example blocks around the snippets at lines 191-193, 318-322,
and 625-640) lack language identifiers and are flagged by markdownlint; update
each opening fence from ``` to a labeled fence such as ```text or ```plaintext
so the linter recognizes them (e.g., change the three unlabeled fenced blocks to
use ```text).

Comment on lines +75 to +76
const { stdout } = await execFileAsync('git', ['pull', 'origin', 'main'], {
cwd: '/app',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Update the checked release, not the main branch head.

server/api/updates/version.get.ts compares against GitHub's latest release, but this step always pulls origin/main. Those can diverge, so the UI can advertise vX.Y.Z and then deploy different or unreleased code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/updates/apply.post.ts` around lines 75 - 76, The code currently
runs execFileAsync('git', ['pull', 'origin', 'main']) which always updates main;
instead fetch and check out the release tag that was validated by version.get.
Replace the pull of origin/main with steps that use the verified release tag
(e.g., a releaseTag variable coming from the request or version check): run git
fetch --tags (or git fetch origin) and then git checkout -f
"refs/tags/<releaseTag>" (or git reset --hard "<releaseTag>") via execFileAsync
to ensure the repo is moved to the exact release commit rather than the main
branch; update the execFileAsync invocation(s) in apply.post to reference that
releaseTag.

Comment on lines +96 to +124
// Step 2: Rebuild and restart via Docker Compose
try {
const { stdout } = await execFileAsync(
'docker', ['compose', 'up', '--build', '--detach', '--no-deps', 'app'],
{
cwd: '/app',
timeout: 600_000, // 10 minutes for build
},
)
steps.push({
step: 'Rebuild & restart',
status: 'success',
detail: stdout.trim(),
})
}
catch (err: unknown) {
const message = err instanceof Error ? err.message : 'Unknown error'
steps.push({ step: 'Rebuild & restart', status: 'failed', detail: message })
return {
success: false,
message: 'Failed to rebuild. Your current version is still running safely. Try running the update manually.',
previousVersion,
steps,
} satisfies UpdateResult
}

return {
success: true,
message: 'Update started successfully. The application will restart momentarily. Refresh this page in about 30 seconds.',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Recreating app from inside app makes the response unreliable.

If this step succeeds, Docker tears down the very container serving the request, so the browser is likely to see a dropped connection instead of the success payload. This needs an external updater process/sidecar or an async handoff before the current container is replaced.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/updates/apply.post.ts` around lines 96 - 124, The rebuild
currently runs execFileAsync('docker', ['compose', 'up', ...]) inside the
container serving the request (the "Rebuild & restart" step), which will tear
down the caller and make the HTTP response unreliable; change this to hand off
the work to an external updater: either spawn a detached background process (use
child_process.spawn with detached: true and unref()) to run a small updater
script that performs the docker compose rebuild, or write an update request to a
file/queue that a sidecar/updater service polls; update the code paths around
the execFileAsync call and the "Rebuild & restart" step so the handler returns a
success status immediately after scheduling the external update and does not
block on or directly invoke the in-container docker compose command.

Comment thread server/api/updates/backup.post.ts
Comment on lines +48 to +55
await execFileAsync(
'pg_dump',
['-h', host, '-p', port, '-U', user, '-d', database, '--no-owner', '--no-acl', '-f', backupPath],
{
timeout: 300_000,
env: { ...process.env, PGPASSWORD: dbUrl.password },
},
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

pg_dump is not available in the shipped app image.

This handler shells out to pg_dump, but the provided runtime image only copies Node artifacts and does not install PostgreSQL client tools. In the current container this endpoint will fail before any backup is created.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/updates/backup.post.ts` around lines 48 - 55, The handler in
server/api/updates/backup.post.ts currently assumes the pg_dump binary is
present when calling execFileAsync('pg_dump', ...); modify the handler to first
check for pg_dump availability (e.g., attempt a lightweight
execFileAsync('which' or 'pg_dump --version') or fs.access) and if absent
provide a safe fallback: either (A) return a clear 5xx error explaining pg_dump
is not installed, or (B) implement a Node-side dump using the 'pg' client
(connect via the same host/port/user/database and stream a logical dump by
enumerating tables and using COPY TO STDOUT or SELECTs to write schema+data into
backupPath). Update the code path around execFileAsync to use this
check/fallback so the endpoint does not assume pg_dump exists.

Comment thread server/api/updates/version.get.ts
@railway-app railway-app Bot temporarily deployed to applirank / reqcore-pr-110 March 15, 2026 10:06 Destroyed
@JoachimLK JoachimLK merged commit e8432e5 into main Mar 15, 2026
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.

1 participant