Skip to content

Commit 9e8cd9e

Browse files
committed
Add database promotion backup drift seed owner tools and runbook lanes - PR_26167_201-206-database-operations-stack
1 parent c0872b8 commit 9e8cd9e

46 files changed

Lines changed: 1963 additions & 682 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

assets/theme-v2/js/owner-operations.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ class OwnerOperationsController {
99
this.root = root;
1010
this.actionButtons = Array.from(root.querySelectorAll("[data-owner-operation-action]"));
1111
this.connectionSummary = root.querySelector("[data-owner-connection-summary]");
12+
this.databaseStatusRows = root.querySelector("[data-owner-database-status-rows]");
1213
this.resultRows = root.querySelector("[data-owner-operation-result-rows]");
1314
this.status = root.querySelector("[data-owner-operations-status]");
1415
this.validateButton = root.querySelector("[data-owner-operation-validate]");
1516
}
1617

1718
init() {
18-
if (!this.connectionSummary || !this.resultRows || !this.status || !this.validateButton) {
19+
if (!this.connectionSummary || !this.databaseStatusRows || !this.resultRows || !this.status || !this.validateButton) {
1920
return;
2021
}
2122
this.validateButton.addEventListener("click", () => this.validateConnection());
@@ -48,6 +49,36 @@ class OwnerOperationsController {
4849
});
4950
}
5051

52+
renderDatabaseOperations(operations = []) {
53+
const rows = Array.isArray(operations) ? operations : [];
54+
this.databaseStatusRows.replaceChildren();
55+
if (!rows.length) {
56+
const emptyRow = document.createElement("tr");
57+
["Database Operations", "WARN", "read-only", "unavailable", "No database operation status was returned."].forEach((value) => {
58+
const cell = document.createElement("td");
59+
cell.textContent = value;
60+
emptyRow.append(cell);
61+
});
62+
this.databaseStatusRows.append(emptyRow);
63+
return;
64+
}
65+
rows.forEach((operation) => {
66+
const tableRow = document.createElement("tr");
67+
[
68+
operation.label || operation.id || "Database Operation",
69+
operation.status || "WARN",
70+
operation.mode || "read-only",
71+
operation.command || "not exposed",
72+
operation.message || "No database operation message returned.",
73+
].forEach((value) => {
74+
const cell = document.createElement("td");
75+
cell.textContent = value;
76+
tableRow.append(cell);
77+
});
78+
this.databaseStatusRows.append(tableRow);
79+
});
80+
}
81+
5182
appendResult(result = {}) {
5283
const row = document.createElement("tr");
5384
[
@@ -67,6 +98,7 @@ class OwnerOperationsController {
6798
try {
6899
const payload = readOwnerOperationsStatus();
69100
this.renderConnectionSummary(payload.connectionSummary || {});
101+
this.renderDatabaseOperations(payload.databaseOperations || []);
70102
this.setStatus(payload.status || "PASS", payload.message || "Owner Operations loaded.");
71103
} catch (error) {
72104
this.setStatus("FAIL", error instanceof Error ? error.message : "Owner Operations are unavailable.");
@@ -77,6 +109,7 @@ class OwnerOperationsController {
77109
try {
78110
const result = validateOwnerOperationsConnection();
79111
this.renderConnectionSummary(result.connectionSummary || {});
112+
this.renderDatabaseOperations(result.databaseOperations || []);
80113
this.appendResult(result);
81114
this.setStatus(result.status || "PASS", result.message || "Connection validation finished.");
82115
} catch (error) {

docs_build/database/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,25 @@ Each product area/tool owns one grouped file in `ddl/`, `dml/`, and `seed/`. Acc
2020
Runtime DEV setup and reseed actions must call server-side APIs. Browser pages must not directly seed authoritative DB records or generate authoritative DB keys.
2121

2222
Codex may execute DEV database setup only. UAT and production SQL execution is user-controlled. Codex may prepare review artifacts, but it must not execute UAT or production SQL.
23+
24+
## Apply Lanes
25+
26+
Database setup is split into separate lanes:
27+
28+
- DDL: `node .\scripts\apply-database-ddl.mjs`
29+
- DML: `node .\scripts\apply-database-dml.mjs`
30+
- DEV seed: `node .\scripts\apply-database-seed.mjs --dry-run`
31+
32+
DDL and DML use `schema_migrations` for applied file tracking. DEV seed is separate from migration tracking and refuses non-DEV database targets.
33+
34+
## Promotion
35+
36+
The database promotion lane is documented in [promotion-lane.md](promotion-lane.md). Promotion uses manual `.env.<target>` copy-source files, validates and applies against `.env` only, and uses `schema_migrations` as the authoritative DDL/DML migration state.
37+
38+
## Backup And Restore
39+
40+
The operator-controlled backup and restore lane is documented in [backup-restore-lane.md](backup-restore-lane.md). Backup and restore use `GAMEFOUNDRY_DATABASE_URL` from `.env`; restore requires an explicit operator checklist and confirmation phrase before any destructive command runs.
41+
42+
## Runbook
43+
44+
The consolidated operator runbook is documented in [runbook.md](runbook.md). It covers validation, DDL apply, DML apply, DEV seed, backup, restore, promotion, and rollback guidance while keeping `schema_migrations` as migration state and `platform_settings` as runtime settings only.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Database Backup And Restore Lane
2+
3+
This lane documents operator-controlled backup and restore for the database configured by `.env`.
4+
5+
Runtime, validation, migration apply, backup, and restore all use:
6+
7+
```text
8+
GAMEFOUNDRY_DATABASE_URL
9+
```
10+
11+
Do not paste database URLs, passwords, service keys, or dump contents into reports.
12+
13+
## Backup Command Path
14+
15+
Use the active `.env` as the source of the database connection. Do not pass deployment-target parameters.
16+
17+
PowerShell operator flow:
18+
19+
```powershell
20+
$databaseUrl = (Get-Content .env |
21+
Where-Object { $_ -match '^GAMEFOUNDRY_DATABASE_URL=' } |
22+
Select-Object -First 1) -replace '^GAMEFOUNDRY_DATABASE_URL=', ''
23+
24+
$backupPath = Join-Path (Get-Location) 'backups\gamefoundry-backup.dump'
25+
pg_dump --dbname $databaseUrl --format custom --file $backupPath
26+
```
27+
28+
Validation expectation:
29+
30+
- `.env` exists
31+
- `GAMEFOUNDRY_DATABASE_URL` is present
32+
- `pg_dump` is available on the operator machine
33+
- the backup file is written outside tracked source paths
34+
- reports state only the backup path and success/failure, not the connection string
35+
36+
## Restore Checklist
37+
38+
Restore is destructive. Do not run restore unless every checklist item is complete:
39+
40+
- Confirm the target `.env` is the intended database.
41+
- Run `node .\scripts\validate-runtime-connections.mjs` and record PASS/FAIL.
42+
- Confirm the backup file path and checksum.
43+
- Confirm the application is stopped or in a maintenance window.
44+
- Confirm owner approval.
45+
- Type or record the exact operator confirmation phrase: `RESTORE CONFIRMED`.
46+
- Run restore from the operator machine only.
47+
- Run validation after restore.
48+
- Run drift validation when available.
49+
50+
## Restore Command Path
51+
52+
PowerShell operator flow:
53+
54+
```powershell
55+
$confirmation = Read-Host 'Type RESTORE CONFIRMED to restore the configured database'
56+
if ($confirmation -ne 'RESTORE CONFIRMED') {
57+
throw 'Restore cancelled because confirmation did not match.'
58+
}
59+
60+
$databaseUrl = (Get-Content .env |
61+
Where-Object { $_ -match '^GAMEFOUNDRY_DATABASE_URL=' } |
62+
Select-Object -First 1) -replace '^GAMEFOUNDRY_DATABASE_URL=', ''
63+
64+
$backupPath = Join-Path (Get-Location) 'backups\gamefoundry-backup.dump'
65+
pg_restore --dbname $databaseUrl --clean --if-exists --single-transaction $backupPath
66+
```
67+
68+
Restore reports must include:
69+
70+
- target host, port, and database name only
71+
- backup file path
72+
- backup checksum
73+
- confirmation checklist status
74+
- validation result after restore
75+
76+
Restore reports must not include:
77+
78+
- database passwords
79+
- full database URLs
80+
- Supabase service role keys
81+
- access tokens
82+
- raw dump data
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Database Promotion Lane
2+
3+
This lane promotes database changes through the deployment targets in order:
4+
5+
```text
6+
DEV -> IST -> UAT -> PRD
7+
```
8+
9+
The target name describes where the operator points the configured connection. It must not change application behavior.
10+
11+
## Copy-Source Flow
12+
13+
Runtime, validation, and migration apply scripts load `.env` only.
14+
15+
The target-specific files are copy sources only:
16+
17+
- `.env.dev`
18+
- `.env.ist`
19+
- `.env.uat`
20+
- `.env.prd`
21+
22+
Promotion is manual:
23+
24+
1. Copy the selected `.env.<target>` file to `.env`.
25+
2. Review that `.env` contains the intended `GAMEFOUNDRY_DATABASE_URL` and `GAMEFOUNDRY_DATABASE_SSL`.
26+
3. Run `node .\scripts\validate-runtime-connections.mjs`.
27+
4. Run `node .\scripts\apply-database-ddl.mjs`.
28+
5. Run `node .\scripts\apply-database-dml.mjs`.
29+
6. Run `node .\scripts\validate-runtime-connections.mjs` again.
30+
7. Review `schema_migrations` before promoting the next target.
31+
8. Start or restart the runtime after validation passes.
32+
33+
Do not pass runtime environment parameters such as `--env`, `--environment`, or `ENVIRONMENT=<target>`.
34+
35+
## Migration State
36+
37+
`schema_migrations` is the authoritative record of applied DDL/DML.
38+
39+
The migration apply lane records:
40+
41+
- `fileName`
42+
- `migrationType`
43+
- `checksum`
44+
- `appliedAt`
45+
- `appliedBy`
46+
47+
If an already-applied file changes checksum, the apply lane must fail visibly. Create a new migration file instead of editing applied migration content.
48+
49+
`platform_settings` is runtime product configuration only. It must not control migration apply state, promotion state, or schema drift gates.
50+
51+
## Promotion Gate
52+
53+
Each target is eligible for the next promotion step only after:
54+
55+
- validation passes against the current `.env`
56+
- DDL/DML apply completes without checksum drift
57+
- repeat validation passes
58+
- the operator confirms the intended target connection without exposing secrets
59+
60+
Codex may validate and apply against the configured current `.env` only. IST, UAT, and PRD promotion remains user-controlled through the manual copy-source flow.

docs_build/database/runbook.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Database Runbook
2+
3+
This runbook is the operator path for the database configured by `.env`.
4+
5+
Runtime, validation, DDL apply, DML apply, seed, backup, and restore use `.env`
6+
only. Files such as `.env.dev`, `.env.ist`, `.env.uat`, and `.env.prd` are
7+
manual copy sources only.
8+
9+
Do not pass runtime environment parameters such as `--env`, `--environment`, or
10+
`ENVIRONMENT=<target>`. Deployment targets describe the selected connection, not
11+
application behavior.
12+
13+
## State Authority
14+
15+
`schema_migrations` is the authoritative migration state for DDL and DML apply
16+
history.
17+
18+
`platform_settings` is runtime settings data only. It may hold settings such as
19+
platform banners and future maintenance toggles, but it must not track, gate, or
20+
control migration apply state.
21+
22+
## Validate
23+
24+
Run connection validation before and after apply work:
25+
26+
```powershell
27+
node .\scripts\validate-runtime-connections.mjs
28+
```
29+
30+
Run drift validation when schema shape needs to be compared with expected DDL:
31+
32+
```powershell
33+
node .\scripts\validate-database-drift.mjs
34+
```
35+
36+
Validation reports must include host, port, database name, and SSL mode only.
37+
They must not include passwords, full connection strings, service role keys, or
38+
access tokens.
39+
40+
## Apply DDL
41+
42+
Apply DDL from `docs_build/database/ddl/`:
43+
44+
```powershell
45+
node .\scripts\apply-database-ddl.mjs
46+
```
47+
48+
The apply lane records each file in `schema_migrations` with file name, type,
49+
checksum, applied time, and applied-by metadata. If an applied file checksum
50+
changes, the apply lane must fail visibly. Create a new migration file instead
51+
of editing an already-applied file.
52+
53+
## Apply DML
54+
55+
Apply DML from `docs_build/database/dml/`:
56+
57+
```powershell
58+
node .\scripts\apply-database-dml.mjs
59+
```
60+
61+
DML uses the same `schema_migrations` tracking contract as DDL. Repeat runs must
62+
skip unchanged already-applied files and fail on checksum drift.
63+
64+
## Seed DEV
65+
66+
Seed is separate from DDL and DML migration apply. Use the seed dry run first:
67+
68+
```powershell
69+
node --use-system-ca .\scripts\apply-database-seed.mjs --dry-run
70+
```
71+
72+
Run the DEV seed only after the dry run passes:
73+
74+
```powershell
75+
node --use-system-ca .\scripts\apply-database-seed.mjs
76+
```
77+
78+
The DEV seed target keeps User 1, User 2, and User 3 as creator-only identities.
79+
DavidQ remains owner, admin, and creator. The seed script must refuse unsafe
80+
non-DEV targets unless a later approved operator lane explicitly changes that
81+
rule.
82+
83+
## Backup
84+
85+
Use the backup path documented in
86+
[backup-restore-lane.md](backup-restore-lane.md). Backups use
87+
`GAMEFOUNDRY_DATABASE_URL` from `.env`.
88+
89+
Minimum backup checklist:
90+
91+
- Confirm `.env` points at the intended database.
92+
- Confirm `pg_dump` is installed.
93+
- Write backup files outside tracked source paths.
94+
- Record backup path and checksum only.
95+
- Do not write secrets, full URLs, service role keys, or dump contents to
96+
reports.
97+
98+
## Restore
99+
100+
Use the restore path documented in
101+
[backup-restore-lane.md](backup-restore-lane.md). Restore is destructive and
102+
must require explicit operator confirmation.
103+
104+
Minimum restore checklist:
105+
106+
- Confirm `.env` points at the intended target database.
107+
- Confirm the backup file path and checksum.
108+
- Stop the application or enter a maintenance window.
109+
- Confirm owner approval.
110+
- Record the confirmation phrase `RESTORE CONFIRMED`.
111+
- Run restore from the operator machine.
112+
- Run connection validation after restore.
113+
- Run drift validation after restore.
114+
115+
## Promote DEV -> IST -> UAT -> PRD
116+
117+
Promotion is manual and must move in this order:
118+
119+
```text
120+
DEV -> IST -> UAT -> PRD
121+
```
122+
123+
For each target:
124+
125+
1. Copy the selected `.env.<target>` file to `.env`.
126+
2. Confirm `.env` contains the intended database host, port, database name, and
127+
SSL mode without exposing secrets.
128+
3. Run `node .\scripts\validate-runtime-connections.mjs`.
129+
4. Run `node .\scripts\apply-database-ddl.mjs`.
130+
5. Run `node .\scripts\apply-database-dml.mjs`.
131+
6. Run `node .\scripts\validate-database-drift.mjs`.
132+
7. Run `node .\scripts\validate-runtime-connections.mjs` again.
133+
8. Review `schema_migrations` for the expected DDL/DML files.
134+
9. Start or restart the runtime.
135+
10. Promote the next target only after the current target passes.
136+
137+
Do not use `platform_settings` as a migration gate or promotion gate.
138+
139+
## Rollback Guidance
140+
141+
Prefer forward-fix migrations for application schema corrections. Do not edit an
142+
already-applied DDL or DML file; checksum drift must remain a visible failure.
143+
144+
When restore-based rollback is required:
145+
146+
1. Stop runtime traffic or enter a maintenance window.
147+
2. Confirm the target `.env` and backup checksum.
148+
3. Follow the restore checklist and confirmation phrase.
149+
4. Run connection validation.
150+
5. Run drift validation.
151+
6. Review `schema_migrations` against the expected migration state.
152+
7. Restart runtime only after validation passes.
153+
154+
Runtime settings in `platform_settings` may be adjusted after rollback as normal
155+
product configuration, but they must not be treated as migration state.

0 commit comments

Comments
 (0)