Skip to content

Commit d0ce8eb

Browse files
committed
Build game configuration foundation
1 parent 1420bc8 commit d0ce8eb

16 files changed

Lines changed: 1924 additions & 1430 deletions

assets/toolbox/game-configuration/js/index.js

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
readServerToolConstants,
44
requireServerConstant,
55
} from "../../../../src/api/server-api-client.js";
6+
import { getSessionCurrent } from "../../../../src/api/session-api-client.js";
67

78
const constants = readServerToolConstants("game-configuration");
89

@@ -32,25 +33,41 @@ const elements = {
3233
form: document.querySelector("[data-game-configuration-form]"),
3334
formCard: document.querySelector("[data-game-configuration-form-card]"),
3435
gameBasics: document.querySelector("[data-game-configuration-game-basics]"),
36+
gameDetails: document.querySelector("[data-game-configuration-game-details]"),
37+
gameName: document.querySelector("[data-game-configuration-game-name]"),
3538
gameRules: document.querySelector("[data-game-configuration-game-rules]"),
39+
gameType: document.querySelector("[data-game-configuration-game-type]"),
3640
handoffContext: document.querySelector("[data-game-configuration-handoff-context]"),
3741
handoffOverlay: document.querySelector("[data-game-configuration-handoff-overlay]"),
3842
missingItems: document.querySelector("[data-game-configuration-output-missing]"),
3943
objectSetup: document.querySelector("[data-game-configuration-object-setup]"),
4044
outputCapability: document.querySelector("[data-game-configuration-output-capability]"),
45+
outputDetails: document.querySelector("[data-game-configuration-output-details]"),
46+
outputGameType: document.querySelector("[data-game-configuration-output-game-type]"),
47+
outputName: document.querySelector("[data-game-configuration-output-name]"),
4148
outputNextStep: document.querySelector("[data-game-configuration-output-next-step]"),
49+
outputPlatforms: document.querySelector("[data-game-configuration-output-platforms]"),
4250
outputPlayerMode: document.querySelector("[data-game-configuration-output-player-mode]"),
4351
outputReadiness: document.querySelector("[data-game-configuration-output-readiness]"),
52+
outputResolution: document.querySelector("[data-game-configuration-output-resolution]"),
53+
outputStartup: document.querySelector("[data-game-configuration-output-startup]"),
4454
outputSummary: document.querySelector("[data-game-configuration-output-summary]"),
55+
outputVersion: document.querySelector("[data-game-configuration-output-version]"),
56+
outputVisibility: document.querySelector("[data-game-configuration-output-visibility]"),
57+
platforms: document.querySelector("[data-game-configuration-platforms]"),
4558
playerSetup: document.querySelector("[data-game-configuration-player-setup]"),
4659
progressCurrentFocus: document.querySelector("[data-game-configuration-current-focus]"),
4760
progressGame: document.querySelector("[data-game-configuration-game-progress]"),
4861
progressPublishing: document.querySelector("[data-game-configuration-publishing-progress]"),
4962
progressRecommended: document.querySelectorAll("[data-game-configuration-recommended-tool]"),
63+
resolution: document.querySelector("[data-game-configuration-resolution]"),
5064
statusLog: document.querySelector("[data-game-configuration-log]"),
65+
startupSettings: document.querySelector("[data-game-configuration-startup-settings]"),
5166
testReadiness: document.querySelector("[data-game-configuration-test-readiness]"),
5267
validationList: document.querySelector("[data-game-configuration-validation-list]"),
5368
validationOverlay: document.querySelector("[data-game-configuration-validation-overlay]"),
69+
version: document.querySelector("[data-game-configuration-version]"),
70+
visibility: document.querySelector("[data-game-configuration-visibility]"),
5471
worldSetup: document.querySelector("[data-game-configuration-world-setup]")
5572
};
5673

@@ -75,10 +92,16 @@ function readForm() {
7592
return {
7693
audioSetup: elements.audioSetup?.value,
7794
gameBasics: elements.gameBasics?.value,
95+
gameDetails: elements.gameDetails?.value,
7896
gameRules: elements.gameRules?.value,
7997
objectSetup: elements.objectSetup?.value,
98+
platforms: elements.platforms?.value,
8099
playerSetup: elements.playerSetup?.value,
100+
resolution: elements.resolution?.value,
101+
startupSettings: elements.startupSettings?.value,
81102
testReadiness: elements.testReadiness?.value,
103+
version: elements.version?.value,
104+
visibility: elements.visibility?.value,
82105
worldSetup: elements.worldSetup?.value
83106
};
84107
}
@@ -106,6 +129,23 @@ function applyConfigurationToForm(configuration) {
106129
});
107130
}
108131

132+
function currentSession() {
133+
try {
134+
return getSessionCurrent();
135+
} catch {
136+
return { authenticated: false };
137+
}
138+
}
139+
140+
function redirectGuestSaveAction() {
141+
if (currentSession()?.authenticated === true) {
142+
return false;
143+
}
144+
setText(elements.statusLog, "Sign in before saving Game Configuration.");
145+
window.location.href = new URL("/account/sign-in.html", window.location.href).href;
146+
return true;
147+
}
148+
109149
function renderValidation(validation) {
110150
if (!elements.validationList || !elements.validationOverlay) {
111151
return;
@@ -141,16 +181,36 @@ function renderHandoff(snapshot) {
141181
}
142182
}
143183

184+
function inheritedGameName(snapshot) {
185+
return snapshot.handoff.activeProject?.name || snapshot.handoff.activeGame?.name || "";
186+
}
187+
188+
function inheritedGameType(snapshot) {
189+
return snapshot.handoff.activeProject?.gameType || snapshot.handoff.activeDesign?.gameType || snapshot.handoff.activeProject?.purpose || "";
190+
}
191+
144192
function renderOutput(snapshot) {
145193
const configuration = snapshot.configuration;
146194
const validation = snapshot.validation;
195+
const gameName = configuration?.gameName || inheritedGameName(snapshot);
196+
const gameType = inheritedGameType(snapshot);
147197
const missing = validation.findings.map((finding) => finding.label).join(", ");
148198
const summary = configuration?.gameBasics || "No configuration summary saved yet.";
149199
const activeGame = snapshot.handoff.activeGame || snapshot.handoff.activeProject;
150200
const capability = activeGame?.purpose === "Capability Demo"
151201
? `${activeGame.name} remains a game-owned capability demo.`
152202
: "Standard game configuration.";
153203

204+
setText(elements.gameName, gameName || "From Game Hub");
205+
setText(elements.gameType, gameType || "From Game Hub");
206+
setText(elements.outputName, gameName || "No game name saved yet.");
207+
setText(elements.outputGameType, gameType || "No game type inherited yet.");
208+
setText(elements.outputDetails, configuration?.gameDetails || "No game details saved yet.");
209+
setText(elements.outputVersion, configuration?.version || "No version saved yet.");
210+
setText(elements.outputResolution, configuration?.resolution || "No resolution saved yet.");
211+
setText(elements.outputPlatforms, configuration?.platforms || "No platforms saved yet.");
212+
setText(elements.outputVisibility, configuration?.visibility || "No visibility saved yet.");
213+
setText(elements.outputStartup, configuration?.startupSettings || "No startup settings saved yet.");
154214
setText(elements.outputSummary, summary);
155215
setText(elements.outputPlayerMode, configuration?.playerMode || snapshot.handoff.activeDesign?.playerMode || "1 Player");
156216
setText(elements.outputReadiness, snapshot.progressHandoff.readinessStatus);
@@ -199,9 +259,13 @@ elements.form?.addEventListener("submit", (event) => {
199259
return;
200260
}
201261

262+
if (redirectGuestSaveAction()) {
263+
return;
264+
}
265+
202266
const configuration = repository.updateConfiguration(projectId, readForm());
203267
const nextSnapshot = repository.getSnapshot();
204-
const message = configuration?.status === "Ready"
268+
const message = configuration?.status === "Ready" || nextSnapshot.progressHandoff.readinessStatus === "Ready"
205269
? "Saved Game Configuration as ready. Assets is the recommended next tool."
206270
: `Saved Game Configuration with ${nextSnapshot.validation.findings.length} missing item${nextSnapshot.validation.findings.length === 1 ? "" : "s"}.`;
207271

docs_build/database/ddl/game-configuration.sql

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,52 @@
88
CREATE TABLE IF NOT EXISTS game_configuration_records (
99
key text PRIMARY KEY,
1010
"gameKey" text REFERENCES game_workspace_games(key),
11+
"gameDetails" text,
12+
"version" text,
13+
"resolution" text,
14+
"platforms" text,
15+
"visibility" text,
16+
"startupSettings" text,
1117
"status" text,
1218
"summary" text,
1319
"playerMode" text,
20+
"gameBasics" text,
21+
"gameRules" text,
22+
"playerSetup" text,
23+
"worldSetup" text,
24+
"objectSetup" text,
25+
"audioSetup" text,
26+
"testReadiness" text,
1427
"createdAt" timestamptz NOT NULL DEFAULT now(),
1528
"updatedAt" timestamptz NOT NULL DEFAULT now(),
1629
"createdBy" text NOT NULL REFERENCES users(key),
1730
"updatedBy" text NOT NULL REFERENCES users(key)
1831
);
1932

33+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameDetails" text;
34+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "version" text;
35+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "resolution" text;
36+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "platforms" text;
37+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "visibility" text;
38+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "startupSettings" text;
39+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "summary" text;
40+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playerMode" text;
41+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameBasics" text;
42+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameRules" text;
43+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playerSetup" text;
44+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "worldSetup" text;
45+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "objectSetup" text;
46+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "audioSetup" text;
47+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "testReadiness" text;
48+
2049
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_gamekey ON game_configuration_records ("gameKey");
2150
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_createdby ON game_configuration_records ("createdBy");
2251
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_updatedby ON game_configuration_records ("updatedBy");
2352

2453
CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
2554
key text PRIMARY KEY,
2655
"gameKey" text REFERENCES game_workspace_games(key),
56+
"section" text,
2757
"label" text,
2858
"status" text,
2959
"action" text,
@@ -33,6 +63,8 @@ CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
3363
"updatedBy" text NOT NULL REFERENCES users(key)
3464
);
3565

66+
ALTER TABLE game_configuration_validation_items ADD COLUMN IF NOT EXISTS "section" text;
67+
3668
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_gamekey ON game_configuration_validation_items ("gameKey");
3769
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_createdby ON game_configuration_validation_items ("createdBy");
3870
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_updatedby ON game_configuration_validation_items ("updatedBy");

docs_build/database/seed/game-configuration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"game_configuration_records": [],
99
"game_configuration_validation_items": []
1010
},
11-
"note": "Seed records for this group are intentionally empty until an Admin-owned server API seeds them."
11+
"note": "Game Configuration records are server/API-owned. Browser pages must not seed or generate authoritative configuration records."
1212
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Branch Validation
2+
3+
Generated: 2026-06-26 18:51:30 UTC
4+
5+
- Branch check: PASS - current branch is `PR_26177_ALFA_061-game-configuration-foundation`.
6+
- Scope check: PASS - changes are limited to Game Configuration seeded data behavior, targeted tests, reports, and package artifacts.
7+
- Architecture check: PASS - targeted validation proves Browser -> API -> Database persistence.
8+
- Current game check: PASS - status bar and Game Configuration handoff both show Demo Game.
9+
- Validation result: PASS.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Manual Validation Notes
2+
3+
Generated: 2026-06-26 18:51:30 UTC
4+
5+
- Loaded /toolbox/game-configuration/index.html and confirmed the status bar selected game is Demo Game.
6+
- Confirmed Game Name and Game Type render as read-only text, not editable inputs.
7+
- Confirmed seeded current-game configuration fields load before editing.
8+
- Edited configuration settings, saved through the API, and verified game_configuration_records rows.
9+
- Reloaded and confirmed Game Details and Game Basics persisted.
10+
- Cleared required fields to verify validation still reports missing sections.
11+
- Verified guest browser save redirects and direct guest API save returns 401.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Report
2+
3+
Generated: 2026-06-26 18:51:30 UTC
4+
Branch: `PR_26177_ALFA_061-game-configuration-foundation`
5+
Base: `main`
6+
Current HEAD before packaging: `72f8f181c`
7+
8+
## Summary
9+
PR061 makes Game Configuration a human-testable API/DB-backed tool with seeded current-game configuration data. Project identity stays read-only from Game Hub/Game Design handoff, editable configuration settings can be saved, database rows are asserted, and refresh/reload preserves saved values.
10+
11+
## Implementation Notes
12+
- `makeValidGameDesign()` seeds a current-game configuration only when the selected game has no existing configuration record.
13+
- Game Name and Game Type remain non-input status text.
14+
- Tests assert the shared status bar selected game and seeded Demo Game configuration values before editing.
15+
- Validation coverage clears fields explicitly to prove missing-section behavior despite the seeded ready state.
16+
- No SQLite, tmp runtime dependency, JSON source of truth, mock-db-store expansion, or new mock repository file was added.
17+
18+
## Validation
19+
- PASS - node --check assets/toolbox/game-configuration/js/index.js
20+
- PASS - node --check src/dev-runtime/persistence/tool-repositories/game-configuration-mock-repository.js
21+
- PASS - node --check src/dev-runtime/server/local-api-router.mjs
22+
- PASS - node --check tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs
23+
- PASS - git diff --check (line-ending notices only)
24+
- PASS - npx playwright test tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs --workers=1 --reporter=line (6 passed)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Requirement Checklist
2+
3+
Generated: 2026-06-26 18:51:30 UTC
4+
5+
- PASS - Center title is Configuration; Configuration Workspace wording is absent.
6+
- PASS - Game Name comes from Game Hub and is read-only/non-editable.
7+
- PASS - Game Type comes from the Game Hub/Game Design handoff and is read-only/non-editable.
8+
- PASS - Configuration owns editable settings only after project creation.
9+
- PASS - Tool loads seeded configuration data for the current selected Game Hub game.
10+
- PASS - Tool asserts the shared status bar selected game is Demo Game.
11+
- PASS - Read/write behavior remains scoped to the active current game configuration.
12+
- PASS - Signed-in Creator can edit fields, save through API/DB, reload, and see persisted values.
13+
- PASS - Guest browser save redirects to account/sign-in.html and direct guest API save returns 401.
14+
- PASS - No SQLite, tmp runtime dependency, JSON source of truth, mock-db-store expansion, or new mock repository file was added.
15+
- PASS - DDL/DML/seed artifacts remain under docs_build/database/ddl, dml, and seed paths.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# PR_26177_ALFA_061-game-configuration-foundation Validation Lane
2+
3+
Generated: 2026-06-26 18:51:30 UTC
4+
5+
- PASS - node --check assets/toolbox/game-configuration/js/index.js
6+
- PASS - node --check src/dev-runtime/persistence/tool-repositories/game-configuration-mock-repository.js
7+
- PASS - node --check src/dev-runtime/server/local-api-router.mjs
8+
- PASS - node --check tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs
9+
- PASS - git diff --check (line-ending notices only)
10+
- PASS - npx playwright test tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs --workers=1 --reporter=line (6 passed)
Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
M docs_build/dev/reports/PR_26177_OWNER_057-game-journey-metrics-regression-recovery_branch-validation.md
2-
M docs_build/dev/reports/PR_26177_OWNER_057-game-journey-metrics-regression-recovery_manual-validation-notes.md
3-
M docs_build/dev/reports/PR_26177_OWNER_057-game-journey-metrics-regression-recovery_report.md
4-
M docs_build/dev/reports/PR_26177_OWNER_057-game-journey-metrics-regression-recovery_requirement-checklist.md
5-
M docs_build/dev/reports/PR_26177_OWNER_057-game-journey-metrics-regression-recovery_validation-lane.md
6-
M docs_build/dev/reports/coverage_changed_js_guardrail.txt
7-
M docs_build/dev/reports/playwright_v8_coverage_report.txt
8-
D scripts/migrate-game-journey-completion-metrics-sqlite-to-postgres.mjs
9-
M scripts/validate-browser-env-agnostic.mjs
10-
D src/dev-runtime/persistence/game-journey-completion-metrics-migration.mjs
11-
D tests/dev-runtime/GameJourneyCompletionMetricsMigration.test.mjs
12-
M tests/dev-runtime/GameJourneyCompletionMetricsStore.test.mjs
13-
M tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
14-
M tests/playwright/tools/GameJourneyTool.spec.mjs
15-
M docs_build/dev/reports/codex_changed_files.txt
16-
M docs_build/dev/reports/codex_review.diff
1+
assets/toolbox/game-configuration/js/index.js
2+
docs_build/database/ddl/game-configuration.sql
3+
docs_build/database/seed/game-configuration.json
4+
docs_build/dev/reports/PR_26177_ALFA_061-game-configuration-foundation_branch-validation.md
5+
docs_build/dev/reports/PR_26177_ALFA_061-game-configuration-foundation_manual-validation-notes.md
6+
docs_build/dev/reports/PR_26177_ALFA_061-game-configuration-foundation_report.md
7+
docs_build/dev/reports/PR_26177_ALFA_061-game-configuration-foundation_requirement-checklist.md
8+
docs_build/dev/reports/PR_26177_ALFA_061-game-configuration-foundation_validation-lane.md
9+
docs_build/dev/reports/codex_changed_files.txt
10+
docs_build/dev/reports/codex_review.diff
11+
docs_build/dev/reports/coverage_changed_js_guardrail.txt
12+
docs_build/dev/reports/playwright_v8_coverage_report.txt
13+
src/dev-runtime/persistence/tool-repositories/game-configuration-mock-repository.js
14+
src/dev-runtime/server/local-api-router.mjs
15+
tests/playwright/tools/GameConfigurationApiBehavior.spec.mjs
16+
toolbox/game-configuration/index.html

0 commit comments

Comments
 (0)