Merge Workstream C: unlocks + inventory items + sigils + essence
This commit is contained in:
@@ -3,6 +3,9 @@ from app.models.contact_session import ContactSession
|
||||
from app.models.entity import Entity
|
||||
from app.models.entity_sighting import EntitySighting
|
||||
from app.models.event import Event
|
||||
from app.models.inventory_item import InventoryItem
|
||||
from app.models.sigil import Sigil
|
||||
from app.models.unlock import UnlockRecord
|
||||
from app.models.user import User
|
||||
from app.models.waitlist_entry import WaitlistEntry
|
||||
|
||||
@@ -13,5 +16,8 @@ __all__ = [
|
||||
"Entity",
|
||||
"EntitySighting",
|
||||
"Event",
|
||||
"InventoryItem",
|
||||
"Sigil",
|
||||
"UnlockRecord",
|
||||
"WaitlistEntry",
|
||||
]
|
||||
|
||||
24
backend/app/models/inventory_item.py
Normal file
24
backend/app/models/inventory_item.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db import Base
|
||||
|
||||
|
||||
class InventoryItem(Base):
|
||||
"""An item a seeker has been dropped (see `app.inventory.roll_item_drop`)
|
||||
— a Reliquary trinket, not a purchased unlock."""
|
||||
|
||||
__tablename__ = "inventory_items"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("users.id"), index=True)
|
||||
item_type: Mapped[str] = mapped_column(String(32), index=True)
|
||||
item_key: Mapped[str] = mapped_column(String(64))
|
||||
payload: Mapped[dict] = mapped_column(JSONB, default=dict)
|
||||
obtained_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
25
backend/app/models/sigil.py
Normal file
25
backend/app/models/sigil.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db import Base
|
||||
|
||||
|
||||
class Sigil(Base):
|
||||
"""A seeker-designed sigil (Workstream F's constrained geometric
|
||||
builder). `design` is placeholder-shaped `{"points": [[x,y],...],
|
||||
"rune": str}` pending the frontend sigil-designer workstream landing —
|
||||
see `app.inventory.validate_sigil_design`."""
|
||||
|
||||
__tablename__ = "sigils"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("users.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(64))
|
||||
design: Mapped[dict] = mapped_column(JSONB, default=dict)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
21
backend/app/models/unlock.py
Normal file
21
backend/app/models/unlock.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db import Base
|
||||
|
||||
|
||||
class UnlockRecord(Base):
|
||||
"""A permanent unlock a seeker has purchased with essence (e.g. the
|
||||
listening tool). One row per (user, unlock_key)."""
|
||||
|
||||
__tablename__ = "unlocks"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("users.id"), index=True)
|
||||
unlock_key: Mapped[str] = mapped_column(String(64), index=True)
|
||||
unlocked_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, String
|
||||
from sqlalchemy import DateTime, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db import Base
|
||||
@@ -14,6 +14,13 @@ class User(Base):
|
||||
username: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
||||
password_hash: Mapped[str] = mapped_column(String(255))
|
||||
email: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
# NOTE: owned by Workstream B in the character-depth-ghost-log spec
|
||||
# (docs/superpowers/specs/2026-07-23-character-depth-ghost-log-design.md).
|
||||
# Added here so Workstream C (unlocks/items/sigils/drops) can build and
|
||||
# test against it in isolation; the merge controller reconciles this
|
||||
# against Workstream B's own edit to this file (which will also add
|
||||
# `favor: float` per the spec's Contract section).
|
||||
essence: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user