Skip to content

Commit da1e6bb

Browse files
committed
Add storage status, real asset storage, asset reference linking, and promotion foundation - PR_26168_211-through-214-storage-promotion-stack
1 parent 2b60371 commit da1e6bb

48 files changed

Lines changed: 47510 additions & 6952 deletions

File tree

Some content is hidden

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

assets/GFS-Infrastructure v1-2.png

1.77 MB
Loading

assets/GFS-Infrastructure v1-3.png

1.88 MB
Loading

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

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ class OwnerOperationsController {
1010
this.actionButtons = Array.from(root.querySelectorAll("[data-owner-operation-action]"));
1111
this.connectionSummary = root.querySelector("[data-owner-connection-summary]");
1212
this.databaseStatusRows = root.querySelector("[data-owner-database-status-rows]");
13+
this.promotionFoundationRows = root.querySelector("[data-owner-promotion-foundation-rows]");
1314
this.resultRows = root.querySelector("[data-owner-operation-result-rows]");
1415
this.status = root.querySelector("[data-owner-operations-status]");
16+
this.storageStatusRows = root.querySelector("[data-owner-storage-status-rows]");
1517
this.validateButton = root.querySelector("[data-owner-operation-validate]");
1618
}
1719

1820
init() {
19-
if (!this.connectionSummary || !this.databaseStatusRows || !this.resultRows || !this.status || !this.validateButton) {
21+
if (!this.connectionSummary || !this.databaseStatusRows || !this.promotionFoundationRows || !this.resultRows || !this.status || !this.storageStatusRows || !this.validateButton) {
2022
return;
2123
}
2224
this.validateButton.addEventListener("click", () => this.validateConnection());
@@ -34,6 +36,7 @@ class OwnerOperationsController {
3436
const rows = [
3537
["Account", summary.account?.status || "unknown", summary.account?.configured === true ? "configured" : "not configured"],
3638
["Product Data", summary.productData?.status || "unknown", summary.productData?.configured === true ? "configured" : "not configured"],
39+
["Project Asset Storage", summary.projectAssetStorage?.status || "unknown", summary.projectAssetStorage?.configured === true ? "configured" : "not configured"],
3740
["Environment Switching", summary.environmentSwitching || "manual-env-change-and-server-restart", "manual"],
3841
["Secrets", summary.secretsExposed === true ? "exposed" : "not exposed", "read-only summary"],
3942
];
@@ -73,6 +76,49 @@ class OwnerOperationsController {
7376
});
7477
}
7578

79+
renderStorageStatus(storageStatus = {}) {
80+
const rows = [
81+
["Storage Configured", storageStatus.configured === true ? "PASS" : "WARN", storageStatus.configured === true ? "yes" : "no"],
82+
["Storage Endpoint", storageStatus.endpointStatus || "WARN", storageStatus.endpoint || "not configured"],
83+
["Storage Bucket", storageStatus.bucketStatus || "WARN", storageStatus.bucket || "not configured"],
84+
["Projects Prefix", storageStatus.projectsPrefixStatus || "WARN", storageStatus.projectsPrefix || "not configured"],
85+
["Access Key", storageStatus.accessKeyStatus || "WARN", storageStatus.accessKeyConfigured === true ? "configured; value hidden" : "not configured"],
86+
["Secret Key", storageStatus.secretKeyStatus || "WARN", storageStatus.secretKeyConfigured === true ? "configured; value hidden" : "not configured"],
87+
];
88+
this.storageStatusRows.replaceChildren();
89+
rows.forEach((row) => {
90+
const tableRow = document.createElement("tr");
91+
row.forEach((value) => {
92+
const cell = document.createElement("td");
93+
cell.textContent = value;
94+
tableRow.append(cell);
95+
});
96+
this.storageStatusRows.append(tableRow);
97+
});
98+
}
99+
100+
renderPromotionFoundation(promotionFoundation = {}) {
101+
const steps = Array.isArray(promotionFoundation.steps) ? promotionFoundation.steps : [];
102+
const rows = steps.length
103+
? steps.map((step) => [
104+
step.stage || "Unknown",
105+
step.operation || "Planning",
106+
step.status || "PLAN",
107+
`${promotionFoundation.ownerOnly === true ? "Owner-only" : "Restricted"}; ${promotionFoundation.browserExecutionAllowed === false ? "browser execution disabled" : "browser execution unknown"}; ${promotionFoundation.destructiveOperationsAllowed === false ? "destructive operations disabled" : "destructive operations unknown"}; ${step.message || promotionFoundation.message || "Promotion foundation planning."}`,
108+
])
109+
: [["DEV/UAT/PROD", "Planning", promotionFoundation.status || "WARN", promotionFoundation.message || "Promotion foundation status unavailable."]];
110+
this.promotionFoundationRows.replaceChildren();
111+
rows.forEach((row) => {
112+
const tableRow = document.createElement("tr");
113+
row.forEach((value) => {
114+
const cell = document.createElement("td");
115+
cell.textContent = value;
116+
tableRow.append(cell);
117+
});
118+
this.promotionFoundationRows.append(tableRow);
119+
});
120+
}
121+
76122
appendResult(result = {}) {
77123
const row = document.createElement("tr");
78124
[
@@ -93,6 +139,8 @@ class OwnerOperationsController {
93139
const payload = readOwnerOperationsStatus();
94140
this.renderConnectionSummary(payload.connectionSummary || {});
95141
this.renderDatabaseStatus(payload.databaseStatus || {});
142+
this.renderPromotionFoundation(payload.promotionFoundation || {});
143+
this.renderStorageStatus(payload.storageStatus || {});
96144
this.setStatus(payload.status || "PASS", payload.message || "Owner Operations loaded.");
97145
} catch (error) {
98146
this.setStatus("FAIL", error instanceof Error ? error.message : "Owner Operations are unavailable.");
@@ -104,6 +152,8 @@ class OwnerOperationsController {
104152
const result = validateOwnerOperationsConnection();
105153
this.renderConnectionSummary(result.connectionSummary || {});
106154
this.renderDatabaseStatus(result.databaseStatus || {});
155+
this.renderPromotionFoundation(result.promotionFoundation || {});
156+
this.renderStorageStatus(result.storageStatus || {});
107157
this.appendResult(result);
108158
this.setStatus(result.status || "PASS", result.message || "Connection validation finished.");
109159
} catch (error) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# PR_26168_211-storage-status-surface
2+
3+
## Branch Validation
4+
- PASS - Current branch: `main`.
5+
- PASS - Expected branch: `main`.
6+
- PASS - Local branches found: `main`.
7+
8+
## Scope Summary
9+
- Added safe Project Asset Storage status visibility to Owner Operations.
10+
- Storage status is status-first and read-only.
11+
- Browser-visible fields are limited to configured state, endpoint, bucket, projects prefix, and credential configured/hidden status.
12+
- Storage access key and secret key values are never rendered.
13+
- No storage write, delete, promotion, `.env` editing, or destructive action was added.
14+
15+
## Validation Lane Report
16+
- Impacted lane: Owner/Admin operations status surface.
17+
- PASS - `node --check assets/theme-v2/js/owner-operations.js`.
18+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`.
19+
- PASS - `node --check tests/helpers/playwrightRepoServer.mjs`.
20+
- PASS - `node --check tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs`.
21+
- PASS - `npx playwright test tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs -g "Owner Operations"`:
22+
- 2 passed.
23+
- DavidQ owner/admin session sees storage status.
24+
- Signed-in non-owner session is blocked from Owner Operations.
25+
- WARN - `npm run test:workspace-v2` was run because this PR changes UI/API/storage-adjacent behavior. This command name is legacy; user-facing language remains Project Workspace.
26+
- First run failed before PR211 behavior because the Playwright repo server helper did not load `.env` before creating the Local API router.
27+
- Fixed the test helper to load `.env` server-side only, matching the Local API runtime path.
28+
- Rerun improved to 3 passed / 2 failed.
29+
- Remaining failures are outside PR211 scope: a root tools page error and Game Design/Controls repository method 500s in `RootToolsFutureState.spec.mjs`.
30+
- PASS - Playwright V8 coverage report was produced at `docs_build/dev/reports/playwright_v8_coverage_report.txt`.
31+
32+
## Manual Validation Notes
33+
- Owner Operations now includes a `Project Asset Storage Status` table.
34+
- Safe status rows show storage configured state, endpoint, bucket, projects prefix, access key configured/hidden, and secret key configured/hidden.
35+
- The page continues to state that secrets and configuration files are not editable from the browser.
36+
- No inline HTML script/style/event handlers were added.
37+
- No `start_of_day` folders or sample JSON were touched.
38+
39+
## Requirement Checklist
40+
- PASS - Read `docs_build/dev/PROJECT_INSTRUCTIONS.md` first.
41+
- PASS - Hard stop unless current branch is `main`.
42+
- PASS - Kept PR211 independently scoped to storage status visibility.
43+
- PASS - Added Owner/Admin storage status visibility for configured project asset storage.
44+
- PASS - Did not expose secrets, keys, or full connection strings.
45+
- PASS - Preserved Web UI -> API/Service Contract -> Database/Storage.
46+
- PASS - Did not introduce silent fallbacks or hidden defaults.
47+
- PASS - Did not introduce page-local product data arrays.
48+
- PASS - Did not introduce browser storage SSoT.
49+
- PASS - Did not introduce fake login, MEM DB, or custom auth.
50+
- PASS - Did not modify `start_of_day` folders.
51+
- PASS - Did not touch sample JSON.
52+
- PASS - Did not add inline HTML script/style/event handlers.
53+
- PASS - Used existing Theme V2 classes only on the public/root UI surface.
54+
- PASS - Used Local API / Local DB terminology in report prose where DEV runtime is discussed.
55+
- PASS - Produced required reports: `codex_review.diff`, `codex_changed_files.txt`, and this PR-specific report.
56+
57+
## Full Samples Decision
58+
- SKIP - Full samples smoke was not run. PR211 changes Owner Operations status UI/API behavior only and does not touch samples, sample JSON, engine runtime, or shared sample launch surfaces.
59+
60+
## Artifact
61+
- `tmp/PR_26168_211-storage-status-surface_delta.zip`
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# PR_26168_212-assets-real-storage-mode
2+
3+
## Branch Validation
4+
- PASS - Current branch was `main` before and during implementation.
5+
6+
## Summary
7+
- Wired the Assets DEV storage upload flow through the Local API repository and configured project asset storage contract.
8+
- Removed the test-owned browser mock boundary for the affected storage path; the targeted test now uses the real Assets page, Local API repository calls, Local DB persistence, and API-owned storage read/list endpoints.
9+
- Preserved server-side storage secrets: the browser receives read/list API routes and object keys, not access keys or secret keys.
10+
11+
## Requirement Checklist
12+
- PASS - Hard stop unless current branch is `main`; branch guard passed.
13+
- PASS - PR scope stayed on Assets real storage mode and the Local API/storage contract.
14+
- PASS - Preserved Web UI -> API/Service Contract -> Database/Storage.
15+
- PASS - Affected asset storage path no longer uses page-local product data arrays or browser-owned product-data behavior.
16+
- PASS - Browser uploads through the Local API repository/service contract.
17+
- PASS - Object writes use configured storage prefix `/dev/projects/` in the targeted storage validation.
18+
- PASS - No storage secrets are rendered in the browser; the targeted Playwright test asserts access key and secret key text are absent.
19+
- PASS - No fake login, MEM DB, custom auth, silent fallback, start_of_day edits, sample JSON edits, or inline HTML script/style/event handlers were added.
20+
- PASS - DEV user-facing language uses Local API, Local DB, and SQLite terminology where touched.
21+
22+
## Validation Lane Report
23+
- PASS - `node --check assets/theme-v2/js/owner-operations.js`
24+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`
25+
- PASS - `node --check tests/helpers/playwrightRepoServer.mjs`
26+
- PASS - `node --check tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs`
27+
- PASS - `node --check tests/playwright/tools/AssetToolMockRepository.spec.mjs`
28+
- PASS - `npx playwright test tests/playwright/tools/AssetToolMockRepository.spec.mjs -g "Assets DEV storage upload list and read"`
29+
- INFO - `docs_build/dev/reports/playwright_v8_coverage_report.txt` included as the advisory Playwright V8 coverage report for changed runtime JavaScript.
30+
- PASS/SKIP - `node .\scripts\validate-storage-config.mjs`: `.env` loaded; live DEV storage values were not configured, so live storage validation skipped.
31+
- FAIL (known unrelated lane failures) - `npm run test:workspace-v2`: 3 passed, 2 failed in `RootToolsFutureState.spec.mjs` due root tools page error `Cannot read properties of undefined (reading 'length')` and unrelated Game Design/Controls repository 500s. This command name is legacy; user-facing language remains Project Workspace.
32+
33+
## Manual Validation Notes
34+
- Targeted storage test wrote `SMALL_PNG` through the Assets page and Local API to fake R2 storage.
35+
- Evidence: storage server observed a `PUT` under `/dev/projects/<projectId>/image/<uploadFileName>.png`.
36+
- Evidence: `GET /api/storage/project-assets/list?projectId=<projectId>` returned the stored key and `/dev/projects/` prefix.
37+
- Evidence: `GET /api/storage/project-assets/read?key=<objectKey>` returned the uploaded bytes with `application/octet-stream`.
38+
- Local DB persistence now writes only the asset runtime rows and the project row needed for the asset FK chain, not a broad browser-owned product snapshot.
39+
40+
## Full Samples Decision
41+
- SKIP - Full samples smoke was not run because this PR changed a targeted Assets storage/API path and did not require shared samples runtime coverage.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# PR_26168_213-project-asset-reference-linking
2+
3+
## Branch Validation
4+
- PASS - Current branch was `main` before and during implementation.
5+
6+
## Summary
7+
- Linked storage-backed asset metadata to API-owned object keys.
8+
- Storage uploads now keep the configured object key as the durable `storedPath` for asset metadata and storage-object metadata.
9+
- The Assets UI shows the storage object key as read-only metadata; the browser still does not generate or edit authoritative keys.
10+
11+
## Requirement Checklist
12+
- PASS - Hard stop unless current branch is `main`; branch guard passed.
13+
- PASS - PR scope stayed on project asset metadata/reference linking.
14+
- PASS - Asset metadata records link to storage object metadata through `storageObjectId` and `asset_storage_objects.id`.
15+
- PASS - Local DB metadata carries the API-owned object key in `storedPath` after a storage-backed upload.
16+
- PASS - The Local API/storage service owns authoritative object keys through `objectKeyForProjectPath`.
17+
- PASS - Browser receives object-key evidence for display/read calls only; it does not receive storage secrets or own key generation.
18+
- PASS - Preserved Web UI -> API/Service Contract -> Database/Storage.
19+
- PASS - No fake login, MEM DB, custom auth, silent fallback, start_of_day edits, sample JSON edits, or inline HTML script/style/event handlers were added.
20+
21+
## Validation Lane Report
22+
- PASS - `node --check src/dev-runtime/persistence/tool-repositories/assets-mock-repository.js`
23+
- PASS - `node --check toolbox/assets/assets.js`
24+
- PASS - `node --check tests/playwright/tools/AssetToolMockRepository.spec.mjs`
25+
- PASS - `npx playwright test tests/playwright/tools/AssetToolMockRepository.spec.mjs -g "Assets DEV storage upload list and read"`
26+
- INFO - `docs_build/dev/reports/playwright_v8_coverage_report.txt` included as the advisory Playwright V8 coverage report for changed runtime JavaScript.
27+
- FAIL (known unrelated lane failures) - `npm run test:workspace-v2`: 3 passed, 2 failed in `RootToolsFutureState.spec.mjs` due root tools page error `Cannot read properties of undefined (reading 'length')` and unrelated Game Design/Controls repository 500s. This command name is legacy; user-facing language remains Project Workspace.
28+
29+
## Manual Validation Notes
30+
- Targeted Playwright uploaded an image through the real Assets page and Local API storage path.
31+
- Evidence: `GET /api/storage/project-assets/list?projectId=<projectId>` returned `/dev/projects/<projectId>/image/<fileName>.png`.
32+
- Evidence: `GET /api/storage/project-assets/read?key=<objectKey>` returned the uploaded bytes.
33+
- Evidence: Assets metadata displayed `Stored path: <objectKey>`, `Storage object key: <objectKey>`, and the API read URL.
34+
- Evidence: `/api/product-data/snapshot` returned matching `asset_library_items.storedPath` and `asset_storage_objects.storedPath` for the uploaded object key.
35+
36+
## Full Samples Decision
37+
- SKIP - Full samples smoke was not run because this PR changed the targeted asset metadata/storage-linking path and did not require shared samples runtime coverage.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# PR_26168_214-project-promotion-foundation
2+
3+
## Branch Validation
4+
- PASS - Current branch was `main` before and during implementation.
5+
6+
## Summary
7+
- Added an Owner-only project promotion foundation surface to Owner Operations.
8+
- The foundation is planning/status only for DEV, UAT, and PROD export/import/validate flow.
9+
- No browser-side export/import/validate execution, destructive operation, secret editing, fake auth, or environment switching was added.
10+
11+
## Requirement Checklist
12+
- PASS - Hard stop unless current branch is `main`; branch guard passed.
13+
- PASS - PR scope stayed on project promotion foundation planning.
14+
- PASS - Owner-only access preserved through the existing Owner Operations session gate.
15+
- PASS - DEV/UAT/PROD promotion foundation includes export, import, and validate planning steps.
16+
- PASS - Runtime-safe flow is status-first: browser execution and destructive operations are explicitly disabled.
17+
- PASS - Existing promotion action buttons continue to return `SKIP` and `executed=false`.
18+
- PASS - Preserved Web UI -> API/Service Contract -> Database/Storage.
19+
- PASS - No silent fallback, hidden default, page-local product data array, browser storage SSoT, fake login, MEM DB, custom auth, start_of_day edits, sample JSON edits, or inline HTML script/style/event handlers were added.
20+
- PASS - User-facing DEV copy references Local API and Local DB/SQLite where relevant.
21+
22+
## Validation Lane Report
23+
- PASS - `node --check assets/theme-v2/js/owner-operations.js`
24+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`
25+
- PASS - `node --check tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs`
26+
- PASS - `npx playwright test tests/playwright/tools/AdminPlatformToolsWireframes.spec.mjs -g "Owner Operations"`
27+
- INFO - `docs_build/dev/reports/playwright_v8_coverage_report.txt` included as the advisory Playwright V8 coverage report for changed runtime JavaScript; the final combined targeted run covered `toolbox/assets/assets.js` and reports advisory uncollected warnings for server/owner modules.
28+
- PASS - `npm run validate:browser-env-agnostic`
29+
- FAIL (known unrelated lane failures) - `npm run test:workspace-v2`: 3 passed, 2 failed in `RootToolsFutureState.spec.mjs` due root tools page error `Cannot read properties of undefined (reading 'length')` and unrelated Game Design/Controls repository 500s. This command name is legacy; user-facing language remains Project Workspace.
30+
31+
## Manual Validation Notes
32+
- Owner test user sees the promotion foundation table with DEV, UAT, PROD, Export, Import, and Validate planning.
33+
- Owner table text confirms Owner-only access, browser execution disabled, and destructive operations disabled.
34+
- Promotion action `promote-dev-to-uat` returns `SKIP` and `executed=false`.
35+
- Non-owner user remains blocked from Owner Operations and cannot see the promotion surface.
36+
37+
## Full Samples Decision
38+
- SKIP - Full samples smoke was not run because this PR changed the targeted Owner Operations planning/status surface and did not require shared samples runtime coverage.

0 commit comments

Comments
 (0)