Skip to content

Commit 62e76a7

Browse files
committed
Add Sprites API database foundation
1 parent 1420bc8 commit 62e76a7

19 files changed

Lines changed: 2480 additions & 1390 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
-- Game Foundry Studio DEV database DDL
2+
-- Group: Sprites
3+
-- Ownership: docs_build/database/ddl/sprites.sql
4+
-- Target DEV database: gamefoundry_dev
5+
-- Scope: executable grouped table DDL for active Supabase/server API migration.
6+
-- Authoritative key values are generated by the server/API layer.
7+
-- Owned tables: sprite_records, sprite_usage_references
8+
CREATE TABLE IF NOT EXISTS sprite_records (
9+
key text PRIMARY KEY,
10+
"gameId" text REFERENCES game_workspace_games(key),
11+
"ownerUserId" text REFERENCES users(key),
12+
"name" text NOT NULL,
13+
"status" text NOT NULL,
14+
"category" text NOT NULL DEFAULT '',
15+
"tagKeys" jsonb NOT NULL DEFAULT '[]'::jsonb,
16+
"source" text NOT NULL DEFAULT '',
17+
"storageObjectKey" text NOT NULL DEFAULT '',
18+
"storagePath" text NOT NULL DEFAULT '',
19+
"originalName" text NOT NULL DEFAULT '',
20+
"mimeType" text NOT NULL DEFAULT '',
21+
"width" integer,
22+
"height" integer,
23+
"sizeBytes" bigint,
24+
"checksum" text NOT NULL DEFAULT '',
25+
"paletteColorKeys" jsonb NOT NULL DEFAULT '[]'::jsonb,
26+
"archived" boolean NOT NULL DEFAULT false,
27+
"archivedAt" timestamptz,
28+
"createdAt" timestamptz NOT NULL DEFAULT now(),
29+
"updatedAt" timestamptz NOT NULL DEFAULT now(),
30+
"createdBy" text NOT NULL REFERENCES users(key),
31+
"updatedBy" text NOT NULL REFERENCES users(key)
32+
);
33+
34+
CREATE INDEX IF NOT EXISTS idx_sprite_records_gameid ON sprite_records ("gameId");
35+
CREATE INDEX IF NOT EXISTS idx_sprite_records_owneruserid ON sprite_records ("ownerUserId");
36+
CREATE INDEX IF NOT EXISTS idx_sprite_records_status ON sprite_records ("status");
37+
CREATE INDEX IF NOT EXISTS idx_sprite_records_createdby ON sprite_records ("createdBy");
38+
CREATE INDEX IF NOT EXISTS idx_sprite_records_updatedby ON sprite_records ("updatedBy");
39+
40+
CREATE TABLE IF NOT EXISTS sprite_usage_references (
41+
key text PRIMARY KEY,
42+
"spriteKey" text NOT NULL REFERENCES sprite_records(key),
43+
"sourceType" text NOT NULL,
44+
"sourceKey" text NOT NULL,
45+
"label" text NOT NULL DEFAULT '',
46+
"createdAt" timestamptz NOT NULL DEFAULT now(),
47+
"updatedAt" timestamptz NOT NULL DEFAULT now(),
48+
"createdBy" text NOT NULL REFERENCES users(key),
49+
"updatedBy" text NOT NULL REFERENCES users(key)
50+
);
51+
52+
CREATE INDEX IF NOT EXISTS idx_sprite_usage_references_spritekey ON sprite_usage_references ("spriteKey");
53+
CREATE INDEX IF NOT EXISTS idx_sprite_usage_references_source ON sprite_usage_references ("sourceType", "sourceKey");
54+
CREATE INDEX IF NOT EXISTS idx_sprite_usage_references_createdby ON sprite_usage_references ("createdBy");
55+
CREATE INDEX IF NOT EXISTS idx_sprite_usage_references_updatedby ON sprite_usage_references ("updatedBy");

docs_build/database/dml/DML_INDEX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Direct SQL setup is intentionally narrow. Account DEV users now require server-s
1818
| Objects | `objects.sql` | Server-seed-owned | Server-side seed API |
1919
| Palette | `palette.sql` | Server-seed-owned | Server-side seed API |
2020
| Support Tickets | `support-tickets.sql` | Server-seed-owned | Admin Site Setup/server-side seed API |
21+
| Sprites | `sprites.sql` | Server-seed-owned | Sprites Local API/server-side Postgres service |
2122
| Tags | `tags.sql` | Server-seed-owned | Server-side seed API |
2223
| Tool Metadata | `tool-metadata.sql` | Server-seed-owned | Server-side seed API |
2324
| Tool Planning | `tool-planning.sql` | Server-seed-owned | Server-side seed API |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Game Foundry Studio DEV database DML / seed review
2+
-- Group: Sprites
3+
-- Ownership: docs_build/database/dml/sprites.sql
4+
-- Runtime setup/seed operations for this group must run through server-side APIs.
5+
-- Browser pages must not directly seed authoritative DB records.
6+
-- Owned tables: sprite_records, sprite_usage_references
7+
8+
-- DML status: Server-seed-owned.
9+
-- Setup is performed through the Admin-owned server-side seed API and Sprites Local API/server-side Postgres service.
10+
-- Browser pages must not seed authoritative records.
11+
-- The server/API layer generates all non-user keys.
12+
-- This SQL file intentionally has no direct INSERT statements because direct SQL would bypass key/audit ownership.
13+
-- Direct SQL setup for this group remains deferred until a later migration-runner PR explicitly owns it.

docs_build/database/seed/guest/sprites.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"readOnly": true,
66
"writableByGuest": false,
77
"signInRedirect": "account/sign-in.html",
8-
"tables": {},
8+
"tables": {
9+
"sprite_records": [],
10+
"sprite_usage_references": []
11+
},
912
"samplePackages": [
1013
{
1114
"key": "guest-sprites-starter",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"group": "Sprites",
3+
"groupKey": "sprites",
4+
"owner": "docs_build/database/seed",
5+
"serverSideSeedRequired": true,
6+
"browserAuthoritativeKeyGenerationAllowed": false,
7+
"colorOwnership": "Palette/Colors owns reusable color definitions; Sprites stores Palette/Colors keys only.",
8+
"tables": {
9+
"sprite_records": [],
10+
"sprite_usage_references": []
11+
},
12+
"note": "Seed records for this group are intentionally empty until a server/API seed path owns them."
13+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# PR_26177_CHARLIE_010-sprites-api-db-foundation
2+
3+
Status: PASS
4+
Team: Charlie
5+
Branch: PR_26177_CHARLIE_010-sprites-api-db-foundation
6+
Date: 2026-06-26
7+
Base branch: main
8+
9+
## Scope
10+
11+
This PR adds the Sprites API and database foundation only. It does not change the Sprites UI and does not implement import, preview, search, reference viewer, or final Playwright polish.
12+
13+
## Implementation Summary
14+
15+
- Added `src/dev-runtime/sprites/sprites-postgres-service.mjs`.
16+
- Exposed shared Local API routes under `/api/sprites/records`.
17+
- Added Postgres DDL/DML/seed artifacts for grouped Sprites ownership.
18+
- Registered Sprites product data tables for provider/product snapshots.
19+
- Added targeted service and Local API contract tests.
20+
21+
## API Contract
22+
23+
The foundation exposes:
24+
25+
- `GET /api/sprites/records`
26+
- `GET /api/sprites/records/:key`
27+
- `POST /api/sprites/records`
28+
- `POST /api/sprites/records/:key`
29+
- `POST /api/sprites/records/:key/archive`
30+
- `POST /api/sprites/records/:key/delete`
31+
32+
Guest browsing is allowed through GET routes. Write routes require a signed-in actor key through the server API session.
33+
34+
## Database Foundation
35+
36+
Grouped database artifacts:
37+
38+
- `docs_build/database/ddl/sprites.sql`
39+
- `docs_build/database/dml/sprites.sql`
40+
- `docs_build/database/seed/sprites.json`
41+
- `docs_build/database/seed/guest/sprites.json`
42+
43+
Owned tables:
44+
45+
- `sprite_records`
46+
- `sprite_usage_references`
47+
48+
`sprite_records` includes server-owned audit fields:
49+
50+
- `key`
51+
- `createdAt`
52+
- `updatedAt`
53+
- `createdBy`
54+
- `updatedBy`
55+
56+
The API/service layer generates record keys and audit values. Browser-created keys are ignored and never trusted as authoritative.
57+
58+
## Palette/Colors Boundary
59+
60+
Sprites does not store reusable color definitions. It stores Palette/Colors references only through `paletteColorKeys`.
61+
62+
The service rejects payload keys that would transfer reusable color ownership into Sprites:
63+
64+
- `colors`
65+
- `hex`
66+
- `palette`
67+
- `paletteColors`
68+
- `swatches`
69+
70+
## Validation Summary
71+
72+
- PASS: `node ./scripts/run-node-test-files.mjs tests/dev-runtime/SpritesPostgresService.test.mjs tests/api/sprites/contract.test.mjs`
73+
- PASS: `git diff --check`
74+
- PASS: no `start_of_day` paths changed.
75+
- PASS: no browser storage SSoT, MEM DB, local-mem, fake-login, imageDataUrl, or silent fallback terms added in Sprites foundation files.
76+
- PASS: no runtime UI changes.
77+
- NOTE: `tests/dev-runtime/SupabaseProductDataCutover.test.mjs` was attempted twice because product table metadata changed. It timed out both times before producing a failure payload, so it is recorded as a non-blocking broader-lane limitation. Required Sprites API/unit validation passed.
78+
79+
## Playwright
80+
81+
Playwright impacted: No. This PR adds API/database foundation only. UI consumption starts in PR_26177_CHARLIE_011.
82+
83+
## ZIP Artifact
84+
85+
`tmp/PR_26177_CHARLIE_010-sprites-api-db-foundation_delta.zip`
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# PR_26177_CHARLIE_010 Branch Validation
2+
3+
Status: PASS
4+
Team: Charlie
5+
Branch: PR_26177_CHARLIE_010-sprites-api-db-foundation
6+
Date: 2026-06-26
7+
8+
| Gate | Result | Evidence |
9+
| --- | --- | --- |
10+
| Started from `main` | PASS | Gate verified before branch creation. |
11+
| Worktree clean before branch | PASS | `git status --short` returned no files before branch creation. |
12+
| Local/origin sync before branch | PASS | `git rev-list --left-right --count main...origin/main` returned `0 0`. |
13+
| One PR purpose | PASS | API/database foundation only. |
14+
| No `start_of_day` changes | PASS | Changed-file check found no `start_of_day` paths. |
15+
| No UI changes | PASS | No HTML/CSS/toolbox UI files changed. |
16+
| Required ZIP exists | PASS | `tmp/PR_26177_CHARLIE_010-sprites-api-db-foundation_delta.zip`. |
17+
18+
## Branch Disposition
19+
20+
Source branch retained for draft PR review.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PR_26177_CHARLIE_010 Manual Validation Notes
2+
3+
Status: PASS
4+
Team: Charlie
5+
Branch: PR_26177_CHARLIE_010-sprites-api-db-foundation
6+
7+
## Manual Review
8+
9+
- Verified the API foundation is server-side and does not add browser-owned product data.
10+
- Verified the Sprites service generates authoritative ULID keys.
11+
- Verified writes require an authenticated server API session actor.
12+
- Verified reusable colors remain owned by Palette/Colors.
13+
- Verified DML artifacts contain no direct INSERT statements.
14+
- Verified no UI, CSS, HTML, or page-local script behavior changed in this PR.
15+
16+
## Notes For PR_26177_CHARLIE_011
17+
18+
The Sprites UI shell should consume only `/api/sprites/records` and show visible unavailable/error states when the API is unavailable. It should not use page-local product arrays or browser storage as product data.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# PR_26177_CHARLIE_010 Requirements Checklist
2+
3+
Status: PASS
4+
Team: Charlie
5+
Branch: PR_26177_CHARLIE_010-sprites-api-db-foundation
6+
7+
| Requirement | Result | Notes |
8+
| --- | --- | --- |
9+
| Add Sprites API/database foundation | PASS | Added service module and `/api/sprites/records` contract. |
10+
| Add sprite records with audit fields | PASS | `sprite_records` includes key, createdAt, updatedAt, createdBy, updatedBy. |
11+
| API/server owns key generation | PASS | Service generates ULID keys and ignores browser-supplied keys. |
12+
| List/read/create/update/archive/delete contract | PASS | Contract covered in service and API tests. |
13+
| Metadata fields for MVP | PASS | Name, status, category, tags, storage/source, mime, dimensions, size, checksum, and Palette key refs included. |
14+
| Do not store color definitions in Sprites | PASS | Service rejects color definition fields and stores only `paletteColorKeys`. |
15+
| Add DDL/DML/seed files | PASS | Added grouped `sprites` artifacts under `docs_build/database/`. |
16+
| Add targeted API/unit tests | PASS | Added service and `/api/sprites` contract tests. |
17+
| Guest browsing allowed | PASS | GET list route works without session. |
18+
| Guest saving blocked | PASS | POST create returns 401 without signed-in actor. |
19+
| No browser-owned product data | PASS | Browser/UI not changed; API/server owns records. |
20+
| No SQLite direction | PASS | Foundation targets Postgres only. |
21+
| No `start_of_day` changes | PASS | Changed-file check clean. |
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# PR_26177_CHARLIE_010 Validation Lane
2+
3+
Status: PASS
4+
Team: Charlie
5+
Branch: PR_26177_CHARLIE_010-sprites-api-db-foundation
6+
7+
## Commands
8+
9+
```powershell
10+
node ./scripts/run-node-test-files.mjs tests/dev-runtime/SpritesPostgresService.test.mjs tests/api/sprites/contract.test.mjs
11+
git diff --check
12+
git diff --name-only
13+
git diff --name-only | rg "(^|/)start_of_day(/|$)"
14+
rg -n "MEM DB|local-mem|fake-login|localStorage|sessionStorage|indexedDB|imageDataUrl|silent fallback|Mock DB" src/dev-runtime/sprites tests/dev-runtime/SpritesPostgresService.test.mjs tests/api/sprites/contract.test.mjs docs_build/database/ddl/sprites.sql docs_build/database/dml/sprites.sql docs_build/database/seed/sprites.json
15+
```
16+
17+
## Results
18+
19+
| Validation | Result | Notes |
20+
| --- | --- | --- |
21+
| Sprites service tests | PASS | 4 service tests passed. |
22+
| Sprites Local API contract test | PASS | 1 API contract test passed. |
23+
| `git diff --check` | PASS | No whitespace errors. |
24+
| `start_of_day` check | PASS | No matches. |
25+
| Forbidden runtime term scan | PASS | No forbidden terms found in new Sprites foundation files. |
26+
| Palette/Colors ownership check | PASS | Color definition fields are rejected; `paletteColorKeys` only. |
27+
| Playwright | PASS | Not impacted; no UI changes. |
28+
29+
## Broader Lane Attempt
30+
31+
`node ./scripts/run-node-test-files.mjs tests/dev-runtime/SupabaseProductDataCutover.test.mjs` was attempted twice because product table metadata changed. Both attempts timed out before producing a test failure payload. Required targeted Sprites validation passed.

0 commit comments

Comments
 (0)