chore: fork from IRIS track 供 LICA 部门独立运行
- 复制来源: /home/yueli/track @ 192c8ee (feature/ai-audit-update) - 组织隔离目标: LICA - 端口规划: 前端 8030 / 后端 8031 / 数据库 8032 - 已排除 deploy.sh、deploy_full.sh、docker-compose.prod.yml(IRIS 生产发布脚本) - 已排除工作区未提交改动,取干净的 192c8ee 状态
This commit is contained in:
47
backend/app/models/user_daily_seen.py
Normal file
47
backend/app/models/user_daily_seen.py
Normal file
@ -0,0 +1,47 @@
|
||||
"""每日用户活动表 —— 一天一人一行,只记录"今天来过"这件事。
|
||||
|
||||
为什么需要它(而不是复用 audit_logs)
|
||||
--------------------------------------
|
||||
日活报表要的「上线时间 / 下线时间」,两个都不能从审计表直接得出:
|
||||
|
||||
1. **上线/下线时间不能取登录时间**:Refresh Token 有效期 7 天,用户不必每天
|
||||
重新登录。按登录算会出现「登录次数 0、上线时间空,但操作次数 35」的
|
||||
自相矛盾报表。
|
||||
|
||||
2. **也不能只取写操作时间**:审计中间件只记录写操作(及导出/打印这类敏感读),
|
||||
普通 GET 不入账。当天只翻看、没做写操作的人会被整条漏掉。
|
||||
|
||||
3. **更不能把活动记录写进 audit_logs**:
|
||||
· 「上线时间」是**事件**(INSERT 一次即可),但「下线时间」是**状态**
|
||||
(每次活动都要刷新同一个值)。往审计流水里做 UPDATE,等于承认审计记录
|
||||
可以被改写 —— 那审计本身就失去可信度了。
|
||||
· 若改为每个请求 INSERT 一条,表会随访问量线性膨胀。
|
||||
|
||||
于是单开一张"可变的小状态表":一人一天一行,首见 INSERT、其后只
|
||||
UPDATE last_seen_at。50 人 × 365 天 ≈ 1.8 万行/年,可忽略。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime
|
||||
|
||||
from sqlalchemy import Date, DateTime, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base
|
||||
|
||||
|
||||
class UserDailySeen(Base):
|
||||
"""用户在某个北京时间自然日的首末活动时刻"""
|
||||
|
||||
__tablename__ = "user_daily_seen"
|
||||
|
||||
# 联合主键即 UPSERT 的冲突目标,也是"一天一人一行"的保证
|
||||
user_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
day: Mapped[date] = mapped_column(Date, primary_key=True, comment="北京时间自然日")
|
||||
|
||||
first_seen_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, comment="当天首次活动时刻",
|
||||
)
|
||||
last_seen_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, comment="当天末次活动时刻",
|
||||
)
|
||||
Reference in New Issue
Block a user