Skip to content

Commit fcec3ab

Browse files
committed
Merge PR_26177_ALFA_060-game-design-foundation
# Conflicts: # tests/playwright/tools/GameDesignApiBehavior.spec.mjs # tests/playwright/tools/GameDesignApiDb.spec.mjs # tests/playwright/tools/GameDesignMockRepository.spec.mjs
2 parents eb693c1 + 516e5b8 commit fcec3ab

20 files changed

Lines changed: 776 additions & 242 deletions

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

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ const elements = {
3131
capabilityDemoNotes: document.querySelector("[data-game-design-capability-notes]"),
3232
capabilityDemoPanel: document.querySelector("[data-game-design-capability-panel]"),
3333
configurationLink: document.querySelector("[data-game-design-configuration-link]"),
34+
coreLoop: document.querySelector("[data-game-design-core-loop]"),
3435
designSummary: document.querySelector("[data-game-design-summary]"),
36+
designNotes: document.querySelector("[data-game-design-notes]"),
3537
designStatus: document.querySelector("[data-game-design-status]"),
3638
form: document.querySelector("[data-game-design-form]"),
3739
gameType: document.querySelector("[data-game-design-type]"),
@@ -41,20 +43,30 @@ const elements = {
4143
handoffProgress: document.querySelector("[data-game-design-game-progress]"),
4244
handoffPublishing: document.querySelector("[data-game-design-publishing-progress]"),
4345
handoffRecommended: document.querySelector("[data-game-design-recommended-tool]"),
46+
loseCondition: document.querySelector("[data-game-design-lose-condition]"),
47+
outputAudience: document.querySelector("[data-game-design-output-audience]"),
4448
outputCapability: document.querySelector("[data-game-design-output-capability]"),
49+
outputCoreLoop: document.querySelector("[data-game-design-output-core-loop]"),
50+
outputLose: document.querySelector("[data-game-design-output-lose]"),
4551
outputMissing: document.querySelector("[data-game-design-output-missing]"),
4652
outputNextStep: document.querySelector("[data-game-design-output-next-step]"),
53+
outputNotes: document.querySelector("[data-game-design-output-notes]"),
4754
outputPlayerMode: document.querySelector("[data-game-design-output-player-mode]"),
55+
outputStory: document.querySelector("[data-game-design-output-story]"),
4856
outputSummary: document.querySelector("[data-game-design-output-summary]"),
4957
outputValidation: document.querySelector("[data-game-design-output-validation]"),
58+
outputWin: document.querySelector("[data-game-design-output-win]"),
5059
playerMode: document.querySelector("[data-game-design-player-mode]"),
5160
playStyle: document.querySelector("[data-game-design-play-style]"),
61+
story: document.querySelector("[data-game-design-story]"),
62+
targetAudience: document.querySelector("[data-game-design-target-audience]"),
5263
gameContext: document.querySelector("[data-game-design-game-context]"),
5364
gameOverlay: document.querySelector("[data-game-design-game-overlay]"),
5465
statusLog: document.querySelector("[data-game-design-log]"),
5566
tableCounts: document.querySelector("[data-game-design-table-counts]"),
5667
validationList: document.querySelector("[data-game-design-validation-list]"),
57-
validationOverlay: document.querySelector("[data-game-design-validation-overlay]")
68+
validationOverlay: document.querySelector("[data-game-design-validation-overlay]"),
69+
winCondition: document.querySelector("[data-game-design-win-condition]")
5870
};
5971

6072
function setText(element, value) {
@@ -110,11 +122,18 @@ function readForm() {
110122
return {
111123
capabilityDemoAuthoring: repository.getActiveGame()?.purpose === "Capability Demo",
112124
capabilityDemoNotes: elements.capabilityDemoNotes?.value,
125+
coreLoop: elements.coreLoop?.value,
126+
designNotes: elements.designNotes?.value,
113127
designSummary: elements.designSummary?.value,
114128
gameType: elements.gameType?.value,
115129
genre: elements.genre?.value,
130+
loseCondition: elements.loseCondition?.value,
116131
playerMode: elements.playerMode?.value,
117-
playStyle: elements.playStyle?.value
132+
playStyle: elements.playStyle?.value,
133+
story: elements.story?.value,
134+
summary: elements.designSummary?.value,
135+
targetAudience: elements.targetAudience?.value,
136+
winCondition: elements.winCondition?.value
118137
};
119138
}
120139

@@ -134,6 +153,24 @@ function clearForm() {
134153
if (elements.designSummary) {
135154
elements.designSummary.value = "";
136155
}
156+
if (elements.story) {
157+
elements.story.value = "";
158+
}
159+
if (elements.coreLoop) {
160+
elements.coreLoop.value = "";
161+
}
162+
if (elements.winCondition) {
163+
elements.winCondition.value = "";
164+
}
165+
if (elements.loseCondition) {
166+
elements.loseCondition.value = "";
167+
}
168+
if (elements.targetAudience) {
169+
elements.targetAudience.value = "";
170+
}
171+
if (elements.designNotes) {
172+
elements.designNotes.value = "";
173+
}
137174
if (elements.capabilityDemoNotes) {
138175
elements.capabilityDemoNotes.value = "";
139176
}
@@ -158,7 +195,25 @@ function applyDesignToForm(design) {
158195
elements.playerMode.value = design.playerMode || "1 Player";
159196
}
160197
if (elements.designSummary) {
161-
elements.designSummary.value = design.designSummary;
198+
elements.designSummary.value = design.summary || design.designSummary;
199+
}
200+
if (elements.story) {
201+
elements.story.value = design.story;
202+
}
203+
if (elements.coreLoop) {
204+
elements.coreLoop.value = design.coreLoop;
205+
}
206+
if (elements.winCondition) {
207+
elements.winCondition.value = design.winCondition;
208+
}
209+
if (elements.loseCondition) {
210+
elements.loseCondition.value = design.loseCondition;
211+
}
212+
if (elements.targetAudience) {
213+
elements.targetAudience.value = design.targetAudience;
214+
}
215+
if (elements.designNotes) {
216+
elements.designNotes.value = design.designNotes;
162217
}
163218
if (elements.capabilityDemoNotes) {
164219
elements.capabilityDemoNotes.value = design.capabilityDemoNotes;
@@ -243,7 +298,13 @@ function renderOutput(snapshot, validation) {
243298
const activeGame = snapshot.activeGame || snapshot.activeProject;
244299
const missingRequirements = validation.findings.map((finding) => finding.label).join(", ");
245300

246-
setText(elements.outputSummary, activeDesign?.designSummary || "No design summary saved yet.");
301+
setText(elements.outputSummary, activeDesign?.summary || activeDesign?.designSummary || "No design summary saved yet.");
302+
setText(elements.outputStory, activeDesign?.story || "No story saved yet.");
303+
setText(elements.outputCoreLoop, activeDesign?.coreLoop || "No core loop saved yet.");
304+
setText(elements.outputWin, activeDesign?.winCondition || "No win condition saved yet.");
305+
setText(elements.outputLose, activeDesign?.loseCondition || "No lose condition saved yet.");
306+
setText(elements.outputAudience, activeDesign?.targetAudience || "No audience saved yet.");
307+
setText(elements.outputNotes, activeDesign?.designNotes || "No notes saved yet.");
247308
setText(elements.outputPlayerMode, activeDesign?.playerMode || "1 Player");
248309
setText(elements.outputValidation, validation.status);
249310
setText(elements.outputNextStep, snapshot.progressHandoff.recommendedNextTool);

docs_build/database/ddl/game-design.sql

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,47 @@
44
-- Target DEV database: gamefoundry_dev
55
-- Scope: executable grouped table DDL for active Supabase/server API migration.
66
-- Authoritative key values are generated by the server/API layer unless a later DEV-only seed exception explicitly applies.
7-
-- Owned tables: game_design_documents, game_design_validation_items
7+
-- Owned tables: game_design_documents, game_design_validation_items, game_design_sections, game_design_capability_demos
88
CREATE TABLE IF NOT EXISTS game_design_documents (
99
key text PRIMARY KEY,
1010
"gameKey" text REFERENCES game_workspace_games(key),
1111
"title" text,
12+
"gamePurpose" text,
13+
"gameType" text,
14+
"genre" text,
15+
"playStyle" text,
16+
"playerMode" text,
17+
"summary" text,
18+
"story" text,
19+
"coreLoop" text,
20+
"winCondition" text,
21+
"loseCondition" text,
22+
"targetAudience" text,
23+
"designNotes" text,
24+
"capabilityDemoAuthoring" boolean NOT NULL DEFAULT false,
25+
"capabilityDemoNotes" text,
1226
"status" text,
1327
"createdAt" timestamptz NOT NULL DEFAULT now(),
1428
"updatedAt" timestamptz NOT NULL DEFAULT now(),
1529
"createdBy" text NOT NULL REFERENCES users(key),
1630
"updatedBy" text NOT NULL REFERENCES users(key)
1731
);
1832

33+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "gamePurpose" text;
34+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "gameType" text;
35+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "genre" text;
36+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "playStyle" text;
37+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "playerMode" text;
38+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "summary" text;
39+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "story" text;
40+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "coreLoop" text;
41+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "winCondition" text;
42+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "loseCondition" text;
43+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "targetAudience" text;
44+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "designNotes" text;
45+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "capabilityDemoAuthoring" boolean NOT NULL DEFAULT false;
46+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "capabilityDemoNotes" text;
47+
1948
CREATE INDEX IF NOT EXISTS idx_game_design_documents_gamekey ON game_design_documents ("gameKey");
2049
CREATE INDEX IF NOT EXISTS idx_game_design_documents_createdby ON game_design_documents ("createdBy");
2150
CREATE INDEX IF NOT EXISTS idx_game_design_documents_updatedby ON game_design_documents ("updatedBy");
@@ -32,6 +61,7 @@ ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "capabilityDemoNotes"
3261
CREATE TABLE IF NOT EXISTS game_design_validation_items (
3362
key text PRIMARY KEY,
3463
"gameKey" text REFERENCES game_workspace_games(key),
64+
"field" text,
3565
"label" text,
3666
"status" text,
3767
"action" text,
@@ -41,10 +71,30 @@ CREATE TABLE IF NOT EXISTS game_design_validation_items (
4171
"updatedBy" text NOT NULL REFERENCES users(key)
4272
);
4373

74+
ALTER TABLE game_design_validation_items ADD COLUMN IF NOT EXISTS "field" text;
75+
4476
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_gamekey ON game_design_validation_items ("gameKey");
4577
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_createdby ON game_design_validation_items ("createdBy");
4678
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_updatedby ON game_design_validation_items ("updatedBy");
47-
ALTER TABLE game_design_validation_items ADD COLUMN IF NOT EXISTS "field" text;
79+
80+
CREATE TABLE IF NOT EXISTS game_design_sections (
81+
key text PRIMARY KEY,
82+
"gameKey" text REFERENCES game_workspace_games(key),
83+
"documentKey" text REFERENCES game_design_documents(key),
84+
"sectionKey" text,
85+
"heading" text,
86+
"body" text,
87+
"sortOrder" integer NOT NULL DEFAULT 0,
88+
"createdAt" timestamptz NOT NULL DEFAULT now(),
89+
"updatedAt" timestamptz NOT NULL DEFAULT now(),
90+
"createdBy" text NOT NULL REFERENCES users(key),
91+
"updatedBy" text NOT NULL REFERENCES users(key)
92+
);
93+
94+
CREATE INDEX IF NOT EXISTS idx_game_design_sections_gamekey ON game_design_sections ("gameKey");
95+
CREATE INDEX IF NOT EXISTS idx_game_design_sections_documentkey ON game_design_sections ("documentKey");
96+
CREATE INDEX IF NOT EXISTS idx_game_design_sections_createdby ON game_design_sections ("createdBy");
97+
CREATE INDEX IF NOT EXISTS idx_game_design_sections_updatedby ON game_design_sections ("updatedBy");
4898

4999
CREATE TABLE IF NOT EXISTS game_design_capability_demos (
50100
key text PRIMARY KEY,

docs_build/database/dml/game-design.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
-- Runtime setup/seed operations for this group must run through server-side APIs.
55
-- Temporary scope: DEV/review artifact only until Admin Site Setup/server seed APIs fully own grouped setup.
66
-- Browser pages must not directly seed authoritative DB records.
7-
-- Owned tables: game_design_documents, game_design_validation_items
7+
-- Owned tables: game_design_documents, game_design_validation_items, game_design_sections, game_design_capability_demos
88

99
-- DML status: Server-seed-owned.
1010
-- Setup is performed through the Admin-owned server-side seed API.

docs_build/database/seed/game-design.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"browserAuthoritativeKeyGenerationAllowed": false,
77
"tables": {
88
"game_design_documents": [],
9-
"game_design_validation_items": []
9+
"game_design_validation_items": [],
10+
"game_design_sections": [],
11+
"game_design_capability_demos": []
1012
},
1113
"note": "Seed records for this group are intentionally empty until an Admin-owned server API seeds them."
1214
}

docs_build/database/seed/guest/game-design.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"signInRedirect": "account/sign-in.html",
88
"tables": {
99
"game_design_documents": [],
10-
"game_design_validation_items": []
10+
"game_design_validation_items": [],
11+
"game_design_sections": [],
12+
"game_design_capability_demos": []
1113
},
1214
"samplePackages": [
1315
{

docs_build/database/seed/tags.json

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,7 @@
77
"architecture": "Browser -> API -> Database",
88
"flatTagsOnly": true,
99
"tables": {
10-
"project_tags": [
11-
{
12-
"key": "01K2GFSJ0Y0000000000007201",
13-
"slug": "platformer",
14-
"label": "platformer",
15-
"description": "Platforming, jumping, and movement-focused projects.",
16-
"active": true,
17-
"createdBy": "01K2GFSJ0Y0000000000000054",
18-
"updatedBy": "01K2GFSJ0Y0000000000000054"
19-
},
20-
{
21-
"key": "01K2GFSJ0Y0000000000007202",
22-
"slug": "fantasy",
23-
"label": "fantasy",
24-
"description": "Magic, legends, and fantasy world themes.",
25-
"active": true,
26-
"createdBy": "01K2GFSJ0Y0000000000000054",
27-
"updatedBy": "01K2GFSJ0Y0000000000000054"
28-
},
29-
{
30-
"key": "01K2GFSJ0Y0000000000007203",
31-
"slug": "medium",
32-
"label": "medium",
33-
"description": "Medium-sized project scope.",
34-
"active": true,
35-
"createdBy": "01K2GFSJ0Y0000000000000054",
36-
"updatedBy": "01K2GFSJ0Y0000000000000054"
37-
},
38-
{
39-
"key": "01K2GFSJ0Y0000000000007204",
40-
"slug": "pixel-art",
41-
"label": "pixel-art",
42-
"description": "Pixel art visual direction.",
43-
"active": true,
44-
"createdBy": "01K2GFSJ0Y0000000000000054",
45-
"updatedBy": "01K2GFSJ0Y0000000000000054"
46-
},
47-
{
48-
"key": "01K2GFSJ0Y0000000000007205",
49-
"slug": "kids",
50-
"label": "kids",
51-
"description": "Designed for younger players.",
52-
"active": true,
53-
"createdBy": "01K2GFSJ0Y0000000000000054",
54-
"updatedBy": "01K2GFSJ0Y0000000000000054"
55-
},
56-
{
57-
"key": "01K2GFSJ0Y0000000000007206",
58-
"slug": "boss-fight",
59-
"label": "boss-fight",
60-
"description": "Includes a climactic boss encounter.",
61-
"active": true,
62-
"createdBy": "01K2GFSJ0Y0000000000000054",
63-
"updatedBy": "01K2GFSJ0Y0000000000000054"
64-
}
65-
],
10+
"project_tags": [],
6611
"project_tag_assignments": []
6712
},
6813
"note": "Flat reusable tag seed labels are server/API owned. Current-game starter assignments are created by the API repository at runtime so project keys stay server-owned."
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# PR_26177_ALFA_060-game-design-foundation Branch Validation
2+
3+
Generated: 2026-06-26 20:59:30 UTC
4+
5+
- Branch check: PASS - current branch is `PR_26177_ALFA_060-game-design-foundation`.
6+
- Scope check: PASS - runtime changes are limited to shared Alfa API/database services and affected Tags/Game Design/Game Configuration tool surfaces carried by the stack.
7+
- Mock repository check: PASS - retired Tags/Game Design/Game Configuration mock repository files are deleted and guardrail tests pass.
8+
- Mock DB expansion check: PASS - this branch does not add or expand mock-db-store as the source of truth for Tags, Game Design, or Game Configuration.
9+
- Architecture check: PASS - targeted validation proves Browser -> API -> Database persistence.
10+
- Validation result: PASS.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# PR_26177_ALFA_060-game-design-foundation Manual Validation Notes
2+
3+
Generated: 2026-06-26 20:59:30 UTC
4+
5+
- Loaded `/toolbox/game-design/index.html` and confirmed the selected Game Hub game context renders for Demo Game.
6+
- Confirmed the page is an editable tool surface, not a landing page.
7+
- Confirmed signed-in Creator edits save through the API and survive reload.
8+
- Verified `game_design_documents` and `game_design_sections` contain the saved current-game values.
9+
- Opened the missing-game scenario and confirmed the validation overlay blocks save until a Game Hub game exists.
10+
- Opened Gravity Demo context and confirmed capability demo data remains game-owned.
11+
- Confirmed guest browser save redirects to `account/sign-in.html`.
12+
- Confirmed direct guest API save returns 401 and does not write product data.
13+
- Confirmed retired Alfa mock repositories are absent and the guardrail test passes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# PR_26177_ALFA_060-game-design-foundation Report
2+
3+
Generated: 2026-06-26 20:59:30 UTC
4+
Branch: `PR_26177_ALFA_060-game-design-foundation`
5+
6+
## Summary
7+
PR060 reworks Game Design as a human-testable API/DB-backed tool while carrying forward the stack correction that removes retired Alfa mock repositories. The shared Alfa API service now persists Game Design documents, validation rows, capability demo rows, and design section rows through the database adapter.
8+
9+
## Implementation Notes
10+
- Removed the retired `game-design-mock-repository.js` file from the active stack and kept the router on `createGameDesignApiService`.
11+
- Persisted editable Game Design fields for the active Game Hub game: summary, story, core loop, win condition, lose condition, target audience, design notes, and capability demo notes.
12+
- Added `game_design_sections` to the shared Game Design service/table contract so section content persists through API/DB and can be validated directly.
13+
- Changed seeding to create starter data only when no Game Design record exists; incomplete Creator saves are no longer overwritten by starter data.
14+
- Kept guest browser saves redirecting to `account/sign-in.html` and direct guest API writes returning 401.
15+
- Preserved flat Tags API/DB behavior from the stack without adding a Tags mock repository or expanding mock-db-store usage for Tags.
16+
17+
## Validation
18+
- PASS - `node --check src/dev-runtime/toolbox-api/alfa-tool-services.mjs`
19+
- PASS - `node --check src/dev-runtime/server/local-api-router.mjs`
20+
- PASS - `node --check assets/toolbox/game-design/js/index.js`
21+
- PASS - `node --test tests/dev-runtime/DevRuntimeBoundary.test.mjs`
22+
- PASS - `npx playwright test tests/playwright/tools/GameDesignApiBehavior.spec.mjs --project=playwright --workers=1 --reporter=line` (6 passed)
23+
24+
## Notes
25+
- No SQLite or tmp runtime dependency was introduced.
26+
- No JSON source of truth or browser-owned product data was introduced.
27+
- No new `*-mock-repository.js` file was added for Tags, Game Crew, Game Design, or Game Configuration.
28+
- No `mock-db-store.js` or Admin DB viewer expansion is present in this PR.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PR_26177_ALFA_060-game-design-foundation Requirement Checklist
2+
3+
Generated: 2026-06-26 20:59:30 UTC
4+
5+
- PASS - Browser -> API -> Database is the active product-data path.
6+
- PASS - Game Design routes through the shared Alfa API service, not `game-design-mock-repository.js`.
7+
- PASS - Retired Tags/Game Design/Game Configuration mock repository files are deleted from this stack.
8+
- PASS - Router guardrail confirms Tags, Game Crew, Game Design, and Game Configuration are not routed to retired mock repositories.
9+
- PASS - Center title is `Design`; `Design Workspace` wording is absent.
10+
- PASS - Tool loads current selected Game Hub game context from the shared status/game context.
11+
- PASS - Signed-in Creator can edit Game Design fields, save through API/DB, reload, and see persisted values.
12+
- PASS - Editable fields include summary, story, core loop, win condition, lose condition, target audience, and design notes.
13+
- PASS - `game_design_sections` persists section rows through API/DB.
14+
- PASS - Guest browser save redirects to `account/sign-in.html`.
15+
- PASS - Direct guest API save returns 401 with Creator-safe sign-in wording.
16+
- PASS - No SQLite, tmp runtime dependency, JSON source of truth, browser-owned product data, or new mock repository source of truth was introduced.
17+
- PASS - No `mock-db-store.js` or Admin DB viewer expansion is present in this PR.
18+
- PASS - DDL/DML/seed artifacts remain under `docs_build/database/ddl`, `docs_build/database/dml`, and `docs_build/database/seed`.

0 commit comments

Comments
 (0)