Compare commits

..

1 Commits

4 changed files with 8 additions and 45 deletions
-39
View File
@@ -1,39 +0,0 @@
"""Script model — game logic scripts owned by users and associated with worlds."""
from typing import Optional
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, func
from sqlalchemy.dialects.postgresql import ENUM, JSONB
from sqlalchemy.orm import relationship
import enum
from app.database import Base
class ScriptType(str, enum.Enum):
"""Type of script storage."""
GDSCRIPT = "gdscript"
DSL = "dsl"
class Script(Base):
"""A game script — either raw GDScript source or a DSL payload."""
__tablename__ = "scripts"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False)
world_id = Column(Integer, ForeignKey("worlds.id", ondelete="CASCADE"), nullable=True)
owner_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
source_code = Column(Text, nullable=True)
version = Column(Integer, nullable=False, server_default="1")
script_type = Column(
ENUM(ScriptType, name="script_type", create_type=False),
nullable=False,
default=ScriptType.GDSCRIPT,
)
dsl_payload = Column(JSONB, nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
owner = relationship("User", back_populates="scripts")
world = relationship("World", back_populates="scripts")
+8 -4
View File
@@ -23,10 +23,9 @@ explicitly out of scope.
| # | Type | Task | Depends on | | # | Type | Task | Depends on |
|---|------|------|-----------| |---|------|------|-----------|
| 1 | architecture | `ApiClient` autoload: HTTP + JWT storage + error contract | — | | 1 | architecture | `ApiClient` autoload: HTTP + JWT storage + error contract | — |
| 2 | implementation | Main-menu **login** wiring (form-encoded) | 1 | | 2 | implementation | Main-menu **login + register** UI built & wired (form-encoded + JSON/age gate) | 1 |
| 3 | implementation | Main-menu **register** wiring (JSON + age gate) | 2 | | 3 | implementation | **World list** screen consuming `GET /api/worlds` | 1 |
| 4 | implementation | **World list** screen consuming `GET /api/worlds` | 2 | | 4 | testing | End-to-end headless smoke test + manual verify | 1,2,3 |
| 5 | testing | End-to-end headless smoke test + manual verify | 1,3,4 |
## Design decisions captured (resolved in task 1) ## Design decisions captured (resolved in task 1)
- Token storage: in-memory singleton property for the MVP; a `save_to_disk` seam is left - Token storage: in-memory singleton property for the MVP; a `save_to_disk` seam is left
@@ -35,3 +34,8 @@ explicitly out of scope.
never crash on network failure; non-2xx surfaces `{status, detail}` from the backend. never crash on network failure; non-2xx surfaces `{status, detail}` from the backend.
- Base URL: read from a ProjectSetting, defaulting to `http://127.0.0.1:8000`. - Base URL: read from a ProjectSetting, defaulting to `http://127.0.0.1:8000`.
- Login is form-encoded; register is JSON — the client helper must support both content types. - Login is form-encoded; register is JSON — the client helper must support both content types.
## Notes
- The main-menu auth UI does **not** exist yet (main_menu.gd currently has only Play/Quit
stubs). Task 2 must **build** the login/register UI, not merely wire an existing one.
- The world-list screen also needs to be **built** (a new scene), not just wired.
-1
View File
@@ -1 +0,0 @@
uid://cjd0uhll7iylj
-1
View File
@@ -1 +0,0 @@
uid://bgnc3iamfgf6k