# ============================================================ # 主数据表模型(moduleId: db-models, 可重生 ✅) # 设计:projects 多项目隔离;master_records 宽表承载 world 主数据键 # (payload=完整记录 JSON,投影零损耗;code/name 建索引供查询); # routing_templates 行业工艺路线模板库(平台级,跨项目共享)。 # ============================================================ from __future__ import annotations from sqlalchemy import ( JSON, BigInteger, Boolean, Float, ForeignKey, Index, Integer, String, Text, UniqueConstraint, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class TenantAuditMixin: tenant_uuid: Mapped[str] = mapped_column(String(32), nullable=False, index=True, default="platform") creator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) updater_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) updated_at: Mapped[str] = mapped_column(String(32), default="") deleted: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) class Project(TenantAuditMixin, Base): """项目/租户:康尼、演示厂……主数据按项目隔离。""" __tablename__ = "projects" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), index=True) name: Mapped[str] = mapped_column(String(128), default="") industry: Mapped[str] = mapped_column(String(64), default="machining") active: Mapped[bool] = mapped_column(Boolean, default=False) owner_user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) data_version: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( UniqueConstraint("tenant_uuid", "code", "deleted", name="uk_projects_tenant_code"), ) class MasterRecord(TenantAuditMixin, Base): """主数据宽表:一行 = world 某主数据表的一条记录(payload 全量 JSON)。 table_key 对齐 world 键名(factories/routingSteps/flexRoutings/salesOrders…), 投影时按 (project_id, table_key, seq) 还原顺序,保证与导入时零差异。 """ __tablename__ = "master_records" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"), index=True) table_key: Mapped[str] = mapped_column(String(64), index=True) seq: Mapped[int] = mapped_column(Integer, default=0) rec_id: Mapped[str] = mapped_column(String(64), default="") # 原记录 id/code(辅助定位) code: Mapped[str] = mapped_column(String(128), default="", index=True) name: Mapped[str] = mapped_column(String(256), default="") payload: Mapped[dict] = mapped_column(JSON) __table_args__ = ( Index("ix_master_tenant_project_table", "tenant_uuid", "project_id", "table_key"), ) class ProjectSetting(TenantAuditMixin, Base): """项目级字典配置:scheduleParams / constraintProfile / flexParams。""" __tablename__ = "project_settings" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"), index=True) key: Mapped[str] = mapped_column(String(64), index=True) payload: Mapped[dict] = mapped_column(JSON) __table_args__ = ( Index("ix_settings_tenant_project_key", "tenant_uuid", "project_id", "key", unique=True), ) class RoutingTemplate(TenantAuditMixin, Base): """行业工艺路线模板(平台级):机加工车/铣/钻/磨/装配等生成模式的结构化形态。""" __tablename__ = "routing_templates" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), index=True) name: Mapped[str] = mapped_column(String(128)) industry: Mapped[str] = mapped_column(String(64), default="machining") category: Mapped[str] = mapped_column(String(64), default="") # 车削/铣削/装配… keywords: Mapped[str] = mapped_column(Text, default="") # 逗号分隔,检索匹配 description: Mapped[str] = mapped_column(Text, default="") asset_id: Mapped[str] = mapped_column(String(32), default="") # 关联知识资产(RAG 出处) source: Mapped[str] = mapped_column(String(128), default="builtin") __table_args__ = ( UniqueConstraint("tenant_uuid", "code", "deleted", name="uk_routing_template_tenant_code"), ) class RoutingTemplateStep(TenantAuditMixin, Base): """模板工步:含推荐工时区间与设备类型(供小工厂一键生成路线)。""" __tablename__ = "routing_template_steps" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) template_id: Mapped[int] = mapped_column(ForeignKey("routing_templates.id"), index=True) seq: Mapped[int] = mapped_column(Integer) operation_code: Mapped[str] = mapped_column(String(64)) operation_name: Mapped[str] = mapped_column(String(128)) equipment_type: Mapped[str] = mapped_column(String(128), default="") std_min_low: Mapped[float] = mapped_column(Float, default=0) # 推荐单件工时下限(分钟) std_min_high: Mapped[float] = mapped_column(Float, default=0) # 上限 setup_min: Mapped[float] = mapped_column(Float, default=10) changeover_min: Mapped[float] = mapped_column(Float, default=10) note: Mapped[str] = mapped_column(Text, default="") class WorkspaceProject(TenantAuditMixin, Base): __tablename__ = "aps_workspace_projects" id: Mapped[str] = mapped_column(String(64), primary_key=True) name: Mapped[str] = mapped_column(String(128), default="") scope_label: Mapped[str] = mapped_column(String(128), default="未设定作用域") owner_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) work_dir: Mapped[str] = mapped_column(String(512), default="") archived: Mapped[bool] = mapped_column(Boolean, default=False) data_version: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( Index("ix_workspace_projects_tenant_owner", "tenant_uuid", "owner_user_id", "deleted"), ) class ProjectMember(TenantAuditMixin, Base): __tablename__ = "aps_project_members" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) project_id: Mapped[str] = mapped_column(ForeignKey("aps_workspace_projects.id"), index=True) user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) role: Mapped[str] = mapped_column(String(16), nullable=False, default="viewer") status: Mapped[str] = mapped_column(String(16), nullable=False, default="active") invited_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( UniqueConstraint("tenant_uuid", "project_id", "user_id", "deleted", name="uk_project_member"), Index("ix_project_member_access", "tenant_uuid", "user_id", "status", "deleted"), ) class UserWorkspace(TenantAuditMixin, Base): __tablename__ = "aps_user_workspaces" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[int] = mapped_column(BigInteger, nullable=False) active_project_id: Mapped[str] = mapped_column(String(64), default="__personal__") active_session_id: Mapped[str | None] = mapped_column(String(64), nullable=True) settings: Mapped[dict] = mapped_column(JSON, default=dict) version: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( UniqueConstraint("tenant_uuid", "user_id", "deleted", name="uk_user_workspace"), ) class ChatSessionRecord(TenantAuditMixin, Base): __tablename__ = "aps_chat_sessions" id: Mapped[str] = mapped_column(String(64), primary_key=True) project_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) owner_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) scope: Mapped[str] = mapped_column(String(16), nullable=False, default="personal") title: Mapped[str] = mapped_column(String(200), default="新话题") status: Mapped[str] = mapped_column(String(16), default="running") created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( Index("ix_chat_session_personal", "tenant_uuid", "owner_user_id", "scope", "deleted"), Index("ix_chat_session_project", "tenant_uuid", "project_id", "scope", "deleted"), ) class ChatMessageRecord(TenantAuditMixin, Base): __tablename__ = "aps_chat_messages" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) session_id: Mapped[str] = mapped_column(ForeignKey("aps_chat_sessions.id"), index=True) sender_user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) seq: Mapped[int] = mapped_column(Integer, nullable=False, default=0) payload: Mapped[dict] = mapped_column(JSON) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( Index("ix_chat_message_tenant_session_seq", "tenant_uuid", "session_id", "seq", unique=True), ) class ProjectFileRecord(TenantAuditMixin, Base): __tablename__ = "aps_project_files" id: Mapped[str] = mapped_column(String(64), primary_key=True) project_id: Mapped[str] = mapped_column(ForeignKey("aps_workspace_projects.id"), index=True) name: Mapped[str] = mapped_column(String(256), default="") kind: Mapped[str] = mapped_column(String(32), default="other") note: Mapped[str] = mapped_column(Text, default="") storage_key: Mapped[str] = mapped_column(String(512), default="") created_at: Mapped[str] = mapped_column(String(32), default="") class ScheduleRun(TenantAuditMixin, Base): __tablename__ = "aps_schedule_runs" id: Mapped[str] = mapped_column(String(64), primary_key=True) project_id: Mapped[str] = mapped_column(ForeignKey("aps_workspace_projects.id"), index=True) triggered_by: Mapped[int] = mapped_column(BigInteger, nullable=False) input_version: Mapped[int] = mapped_column(Integer, nullable=False, default=0) status: Mapped[str] = mapped_column(String(24), nullable=False, default="pending") started_at: Mapped[str] = mapped_column(String(32), default="") finished_at: Mapped[str] = mapped_column(String(32), default="") error: Mapped[str] = mapped_column(Text, default="") created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( Index("ix_schedule_run_project_status", "tenant_uuid", "project_id", "status"), ) class ScheduleResult(TenantAuditMixin, Base): __tablename__ = "aps_schedule_results" id: Mapped[str] = mapped_column(String(64), primary_key=True) project_id: Mapped[str] = mapped_column(ForeignKey("aps_workspace_projects.id"), index=True) run_id: Mapped[str] = mapped_column(ForeignKey("aps_schedule_runs.id"), index=True) input_version: Mapped[int] = mapped_column(Integer, nullable=False) result_version: Mapped[str] = mapped_column(String(64), nullable=False) payload: Mapped[dict] = mapped_column(JSON) created_at: Mapped[str] = mapped_column(String(32), default="") class AuditEventRecord(TenantAuditMixin, Base): __tablename__ = "aps_audit_events" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) actor_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False) project_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) action: Mapped[str] = mapped_column(String(128), nullable=False) resource_type: Mapped[str] = mapped_column(String(64), nullable=False) resource_id: Mapped[str] = mapped_column(String(128), default="") detail: Mapped[dict] = mapped_column(JSON, default=dict) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( Index("ix_audit_tenant_actor_created", "tenant_uuid", "actor_user_id", "created_at"), ) class LicenseActivation(TenantAuditMixin, Base): """A server-validated desktop entitlement bound to one installation.""" __tablename__ = "aps_license_activations" id: Mapped[str] = mapped_column(String(64), primary_key=True) code_hash: Mapped[str] = mapped_column(String(64), nullable=False) code_hint: Mapped[str] = mapped_column(String(32), default="") device_hash: Mapped[str] = mapped_column(String(64), nullable=False, index=True) user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) license_type: Mapped[str] = mapped_column(String(16), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False, default="active") activated_at: Mapped[int] = mapped_column(BigInteger, nullable=False) expires_at: Mapped[int | None] = mapped_column(BigInteger, nullable=True) last_seen_at: Mapped[int] = mapped_column(BigInteger, nullable=False) revoked_at: Mapped[int | None] = mapped_column(BigInteger, nullable=True) created_at: Mapped[str] = mapped_column(String(32), default="") __table_args__ = ( UniqueConstraint("code_hash", "deleted", name="uk_license_activation_code"), Index("ix_license_device_status", "device_hash", "status", "deleted"), Index("ix_license_tenant_user", "tenant_uuid", "user_id", "deleted"), )