"""埋点/上报成功率自报计数快照表(append-only)。 客户端周期上报「自 epoch 起算的累计计数」;服务端只存原始快照,查询时在 Python 侧差分聚合 (见 app/admin/repositories/analytics_health.py)。与既有 analytics_event 表完全独立。 - analytics_selfstat :一快照一行(快照头 + 设备维度 + 设备级诊断量) - analytics_selfstat_event :一 event 一行(四类累计计数),外键指向快照头 """ from __future__ import annotations from datetime import datetime from sqlalchemy import BigInteger, DateTime, ForeignKey, Integer, String, func from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base class AnalyticsSelfStat(Base): __tablename__ = "analytics_selfstat" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) device_id: Mapped[str] = mapped_column(String(64), index=True, nullable=False) epoch_id: Mapped[str] = mapped_column(String(64), index=True, nullable=False) # 设备维度(每设备固定,下钻用) app_ver: Mapped[str | None] = mapped_column(String(32), nullable=True) oem: Mapped[str | None] = mapped_column(String(32), nullable=True) os: Mapped[str | None] = mapped_column(String(32), nullable=True) # 设备级诊断量(累计;queue_depth 是瞬时 gauge) batches_attempted: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) batches_ok: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) batches_fail: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) retries: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) queue_depth: Mapped[int] = mapped_column(Integer, nullable=False, default=0) sent_at: Mapped[int | None] = mapped_column(BigInteger, nullable=True) # 端上报时刻 epoch ms # 服务端接收时间(权威,用于时间分桶与分区排序) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), index=True, nullable=False ) def __repr__(self) -> str: # pragma: no cover return f"" class AnalyticsSelfStatEvent(Base): __tablename__ = "analytics_selfstat_event" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) snapshot_id: Mapped[int] = mapped_column( ForeignKey("analytics_selfstat.id"), index=True, nullable=False ) event: Mapped[str] = mapped_column(String(64), index=True, nullable=False) attempted: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) drop_capture: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) delivered: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) drop_undelivered: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) def __repr__(self) -> str: # pragma: no cover return f""