"""ORM model for the light-app registry (轻应用中心). Global / shared — there is no ``user_id`` scoping; every account sees the same registered apps. ``created_by`` / ``updated_by`` are audit-only. """ from __future__ import annotations from datetime import UTC, datetime from sqlalchemy import Boolean, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from deerflow.persistence.base import Base from deerflow.persistence.types import BeijingDateTime, PortableJSON class LightAppRow(Base): __tablename__ = "light_apps" __table_args__ = (UniqueConstraint("name", name="uq_light_apps_name"),) app_id: Mapped[str] = mapped_column(String(64), primary_key=True) name: Mapped[str] = mapped_column(String(127)) description: Mapped[str | None] = mapped_column(Text) # "window_open" (open in a new tab) | "iframe" (embed under a parent menu) app_type: Mapped[str] = mapped_column(String(32)) url: Mapped[str] = mapped_column(Text) # List of route-param descriptors resolved at launch time by the frontend: # {"key": str, "paramType": "login"|"theme", "source": str, # "customValue": str, "themeValue": str} route_params_json: Mapped[list] = mapped_column(PortableJSON(), default=list) # iframe only: the parent sidebar menu id to mount under # (e.g. "xk-center-task" / "pg-center-task" / "ty-center-task" / # "comprehensive-management"). NULL for window_open apps. mount_location: Mapped[str | None] = mapped_column(String(64), index=True) icon: Mapped[str | None] = mapped_column(String(64)) enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True) sort_order: Mapped[int] = mapped_column(Integer, default=0) created_by: Mapped[str | None] = mapped_column(String(64)) updated_by: Mapped[str | None] = mapped_column(String(64)) created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC)) updated_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))