restore: pick a dump, pick a database, say yes

A pg_dump carries CREATE TABLE, so it cannot be layered onto a database that
already has the schema — it fails on every object. The only honest restore
empties the target first, and that is not a detail to bury behind a button. So
choosing a destination and confirming are two separate clicks, and the second
names what it is about to destroy.

`confirm` is required by the function, not merely by the panel, so no code path
can reach a restore by accident.

The file is matched against what listDumps actually found in the backup
directory rather than taken as given. There is no path to traverse out of and no
way to point psql at a file this module did not write: an unknown name is
refused before anything is opened, rather than sanitised and hoped about.

Emptied with DROP SCHEMA public CASCADE through psql, not by dropping the
DATABASE — that would need a connection to another one, fail while anything is
attached, and lose whatever was granted on it. Replacing the schema does the
same job to the part that matters.

psql rather than pg_restore, because these are plain-SQL dumps, which is what
pg_dump writes without -F c.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 13:11:57 +01:00
co-authored by Claude Opus 5
parent c429dc3455
commit 89c9dd6f63
4 changed files with 195 additions and 7 deletions
+1 -1
View File
@@ -241,7 +241,7 @@ export const DatabaseBlock = () => {
<Console output={output} failed={failed} />
{/* Below the two databases, because it is about both of them rather than either. */}
<BackupsRow />
<BackupsRow prodName={status.production.name ?? 'production'} devName={status.development.name ?? 'development'} />
{/* The common case is both. Doing them one at a time is still there for when it is not. */}
<div className="flex justify-end border-t border-border pt-3">