|
| 1 | +# PR_26168_246-r2-backed-postgres-backups |
| 2 | + |
| 3 | +## Branch Validation |
| 4 | + |
| 5 | +PASS - Current branch is `main`; expected branch is `main`. |
| 6 | + |
| 7 | +Local branches found: |
| 8 | + |
| 9 | +```text |
| 10 | +main |
| 11 | +``` |
| 12 | + |
| 13 | +## Summary |
| 14 | + |
| 15 | +Create Backup now validates the current database connection through Admin Operations, runs server-side `pg_dump --format=custom`, writes the dump only to temporary server-side staging, uploads the final `.dump` to the configured R2 backup prefix, and removes staging after upload. `GAMEFOUNDRY_DB_BACKUP_DIR` is deprecated for final backup storage. |
| 16 | + |
| 17 | +Restore From Backup remains scaffold-only. |
| 18 | + |
| 19 | +## Requirement Checklist |
| 20 | + |
| 21 | +| Requirement | Status | Evidence | |
| 22 | +| --- | --- | --- | |
| 23 | +| Read `docs_build/dev/PROJECT_INSTRUCTIONS.md` first | PASS | Read before implementation and followed BUILD/report/ZIP rules. | |
| 24 | +| Hard stop unless current branch is `main` | PASS | `git branch --show-current` returned `main`; local branch list contained `main`. | |
| 25 | +| Upload final Create Backup artifacts to R2 instead of permanently storing in `GAMEFOUNDRY_DB_BACKUP_DIR` | PASS | `createPostgresBackup` uploads via configured R2 storage and only reports the R2 key. | |
| 26 | +| Validate current DB connection before backup | PASS | `createBackupAction()` still calls `validateBackupDatabaseConnection()` before `createPostgresBackup()`. | |
| 27 | +| Run server-side `pg_dump --format=custom` | PASS | Backup service keeps `--format=custom`; Node test asserts the dump command args. | |
| 28 | +| Write dump to temporary server-side staging only | PASS | Backup service uses OS temp or `GAMEFOUNDRY_DB_BACKUP_STAGING_DIR`; repo `tmp/` staging is rejected. | |
| 29 | +| Upload `.dump` to configured R2 backup prefix | PASS | `createConfiguredBackupStorage()` loads `GAMEFOUNDRY_DB_BACKUP_PREFIX`; configured fake R2 validation captured the PUT. | |
| 30 | +| Delete temporary local dump after successful upload | PASS | Node test asserts the staged file and staging directory are removed after PASS. | |
| 31 | +| Report PASS/FAIL with R2 key, filename, size, timestamp, and environment | PASS | Success and upload-failure results include backup metadata; Playwright asserts visible R2 key PASS/FAIL behavior. | |
| 32 | +| Add safe env placeholders and copy-source guidance | PASS | `.env.example` includes provider, prefix, staging note, and deprecated backup-dir guidance. | |
| 33 | +| Use environment-specific prefixes for DEV, IST, UAT, PRD | PASS | `.env.example` and database docs list `/dev/`, `/ist/`, `/uat/`, and `/prd/backups/postgres/`; config validates allowed prefixes. | |
| 34 | +| R2 prefixes must not require manual folder creation | PASS | `.env.example` and database docs state prefixes are object-key prefixes created by upload. | |
| 35 | +| Treat `GAMEFOUNDRY_DB_BACKUP_DIR` as deprecated final storage | PASS | Code ignores it for final storage and only appends a deprecation note when present. | |
| 36 | +| Rename/document local staging as temporary only | PASS | Added `GAMEFOUNDRY_DB_BACKUP_STAGING_DIR` as optional temporary staging override. | |
| 37 | +| Do not store backups in repo `tmp/` | PASS | Staging root under repo `tmp/` returns FAIL; no `.dump` files were found. | |
| 38 | +| Do not commit backup files | PASS | `rg --files -g '*.dump'` returned no matches. | |
| 39 | +| Do not expose DB password, storage keys, or secrets | PASS | DB password stays in `PGPASSWORD`; tests assert command args and UI/report messages do not expose secret fixture values. | |
| 40 | +| Restore From Backup remains guarded/scaffold-only | PASS | Restore action remains `SKIP`; docs state no approved safe R2 restore path exists in this PR. | |
| 41 | +| Use existing storage provider contract where possible | PASS | Backup uses the existing R2 signed storage module and `putObject` contract, with backup-specific config. | |
| 42 | +| Do not add unrelated Project Package, migration, or workspace behavior | PASS | Changes are limited to backup storage, Admin Operations backup diagnostics/tests, env/docs, and required reports. | |
| 43 | +| Do not run full samples smoke | PASS | Full samples smoke was skipped; no sample JSON or sample runtime behavior changed. | |
| 44 | + |
| 45 | +## Validation Lane Report |
| 46 | + |
| 47 | +Impacted lane: Admin Operations backup action, Local API backup service, R2 storage provider config, and database backup docs. |
| 48 | + |
| 49 | +Skipped broad lanes: full samples, engine-wide runtime, Project Package, migration, and Project Workspace lanes. They were safe to skip because no sample JSON, engine core, package import/export behavior, migration runner, or Project Workspace runtime files changed. |
| 50 | + |
| 51 | +PASS - Syntax/static checks: |
| 52 | + |
| 53 | +```text |
| 54 | +node --check src/dev-runtime/storage/storage-config.mjs |
| 55 | +node --check src/dev-runtime/storage/r2-project-asset-storage.mjs |
| 56 | +node --check src/dev-runtime/database/postgres-backup-service.mjs |
| 57 | +node --check src/dev-runtime/server/local-api-router.mjs |
| 58 | +node --check assets/theme-v2/js/admin-operations.js |
| 59 | +node --check src/engine/api/admin-operations-api-client.js |
| 60 | +node --check tests/dev-runtime/PostgresBackupService.test.mjs |
| 61 | +node --check tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs |
| 62 | +``` |
| 63 | + |
| 64 | +PASS - Targeted Local API backup and R2 upload validation: |
| 65 | + |
| 66 | +```text |
| 67 | +node --test tests/dev-runtime/PostgresBackupService.test.mjs |
| 68 | +``` |
| 69 | + |
| 70 | +Result: 7 passed. |
| 71 | + |
| 72 | +Covered: |
| 73 | + |
| 74 | +- Missing R2 backup storage visible FAIL. |
| 75 | +- Missing `pg_dump` visible FAIL. |
| 76 | +- Repo `tmp/` staging rejection. |
| 77 | +- `pg_dump --format=custom` command construction without DB password in args. |
| 78 | +- Successful R2 upload metadata with R2 key, filename, size, timestamp, and environment. |
| 79 | +- Temporary staged dump and staging directory cleanup after successful upload. |
| 80 | +- R2 upload failure reports key metadata and cleans staging. |
| 81 | +- Configured R2 provider path against a fake local R2-compatible server. |
| 82 | + |
| 83 | +PASS - Targeted Admin Operations Playwright / visible PASS/FAIL behavior: |
| 84 | + |
| 85 | +```text |
| 86 | +npx playwright test tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs --grep "Admin Operations" --reporter=line |
| 87 | +``` |
| 88 | + |
| 89 | +Result: 4 passed. |
| 90 | + |
| 91 | +Covered: |
| 92 | + |
| 93 | +- Create Backup visible PASS message includes the R2 key. |
| 94 | +- Create Backup visible FAIL message is actionable when backup storage config is missing. |
| 95 | +- Restore From Backup remains scaffold-only. |
| 96 | +- Admin Operations order, safety table, non-admin block, and DEV-only reseed gating remain intact. |
| 97 | + |
| 98 | +PASS - Static artifact and HTML checks: |
| 99 | + |
| 100 | +```text |
| 101 | +rg --files -g '*.dump' -g '!node_modules' -g '!tests/results' -g '!tmp' |
| 102 | +rg --pcre2 -n "<script(?![^>]+src=)|<style|\s(onclick|onchange|oninput|onsubmit|onkeydown|onkeyup|onload)=" admin/operations.html |
| 103 | +git diff --check |
| 104 | +``` |
| 105 | + |
| 106 | +Results: |
| 107 | + |
| 108 | +- No `.dump` files found. |
| 109 | +- No inline Admin Operations HTML violations found. |
| 110 | +- `git diff --check` passed with line-ending warnings only. |
| 111 | + |
| 112 | +PASS/WARN - Playwright V8 coverage report generated: |
| 113 | + |
| 114 | +- `docs_build/dev/reports/playwright_v8_coverage_report.txt` |
| 115 | +- `docs_build/dev/reports/coverage_changed_js_guardrail.txt` |
| 116 | +- WARN entries are expected for Node-only Local API/storage modules that browser V8 coverage cannot collect. |
| 117 | + |
| 118 | +## Manual Validation Notes |
| 119 | + |
| 120 | +PASS - The tested R2 path used a local fake R2-compatible server and the real configured storage factory, not real production credentials. |
| 121 | + |
| 122 | +PASS - Successful backup tests verified that temporary local staging is removed after upload. |
| 123 | + |
| 124 | +PASS - No real database password, storage access key, storage secret key, service role key, full database URL, or raw dump content was written to reports or UI messages. |
| 125 | + |
| 126 | +PASS - Actual live backup creation still requires a real `.env`, reachable Postgres database, installed PostgreSQL client tools on the Local API host, and configured R2 credentials. |
| 127 | + |
| 128 | +SKIP - Full samples smoke was not run because this PR only changes Admin Operations backup feedback, Local API backup service/storage behavior, env/docs, and targeted tests. |
| 129 | + |
| 130 | +## Artifacts |
| 131 | + |
| 132 | +PASS - Required reports: |
| 133 | + |
| 134 | +- `docs_build/dev/reports/codex_review.diff` |
| 135 | +- `docs_build/dev/reports/codex_changed_files.txt` |
| 136 | +- `docs_build/dev/reports/PR_26168_246-r2-backed-postgres-backups.md` |
| 137 | + |
| 138 | +PASS - Repo-structured delta ZIP: |
| 139 | + |
| 140 | +- `tmp/PR_26168_246-r2-backed-postgres-backups_delta.zip` |
0 commit comments