Files
mindfulness/server/alembic/versions/0002_init_push_tables.py
2026-02-03 17:43:58 +08:00

124 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""init push tables
Revision ID: 0002_init_push_tables
Revises: 0001_init_content_tables
Create Date: 2026-02-03
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = "0002_init_push_tables"
down_revision = "0001_init_content_tables"
branch_labels = None
depends_on = None
def upgrade() -> None:
# push_tokens
op.create_table(
"push_tokens",
sa.Column(
"id",
mysql.BIGINT(unsigned=True),
primary_key=True,
autoincrement=True,
comment="主键",
),
sa.Column("client_user_id", sa.String(length=64), nullable=False, comment="客户端用户标识UUID"),
sa.Column(
"platform",
sa.Enum("ios", "android", name="push_platform"),
nullable=False,
comment="平台",
),
sa.Column("push_token", sa.String(length=255), nullable=False, comment="Expo Push Token"),
sa.Column("app_id", sa.String(length=255), nullable=False, comment="bundle id / package name用于隔离"),
sa.Column(
"env",
sa.Enum("dev", "prod", name="push_env"),
nullable=False,
comment="环境隔离",
),
sa.Column(
"is_active",
sa.Boolean(),
server_default=sa.text("1"),
nullable=False,
comment="是否有效(发送失败且不可恢复时置为 false",
),
sa.Column("last_seen_at", sa.DateTime(), server_default=sa.func.now(), nullable=False, comment="最后一次上报时间"),
sa.UniqueConstraint("env", "app_id", "push_token", name="uniq_env_app_token"),
mysql_charset="utf8mb4",
)
op.create_index("idx_push_tokens_client_user_id", "push_tokens", ["client_user_id"], unique=False)
op.create_index("idx_push_tokens_is_active", "push_tokens", ["is_active"], unique=False)
# push_preferences
op.create_table(
"push_preferences",
sa.Column("client_user_id", sa.String(length=64), primary_key=True, comment="客户端用户标识UUID"),
sa.Column(
"enabled",
sa.Boolean(),
server_default=sa.text("0"),
nullable=False,
comment="是否开启每日提醒enabled=false 或 times_per_day=0 均视为关闭)",
),
sa.Column(
"times_per_day",
sa.SmallInteger(),
server_default="0",
nullable=False,
comment="每天推送次数05",
),
sa.Column("timezone", sa.String(length=64), nullable=True, comment="IANA 时区(例如 Asia/Shanghai来自客户端上报"),
sa.Column("locale", sa.String(length=32), nullable=True, comment="客户端语言(例如 zh-CN/en/zh-TW用于文案语言选择"),
sa.Column("user_profile_json", sa.JSON(), nullable=True, comment="用户画像V1.2;可选)。用于 Push 场景推荐文案生成。"),
sa.Column("updated_at", sa.DateTime(), server_default=sa.func.now(), nullable=False, comment="更新时间"),
mysql_charset="utf8mb4",
)
# push_send_log
op.create_table(
"push_send_log",
sa.Column(
"id",
mysql.BIGINT(unsigned=True),
primary_key=True,
autoincrement=True,
comment="主键",
),
sa.Column("client_user_id", sa.String(length=64), nullable=False, comment="客户端用户标识UUID"),
sa.Column("local_date", sa.Date(), nullable=False, comment="用户时区的本地日期(用于幂等)"),
sa.Column("slot_index", sa.SmallInteger(), nullable=False, comment="当天第几条1..times_per_day"),
sa.Column("scheduled_at", sa.DateTime(), nullable=False, comment="计划发送时间UTC"),
sa.Column("sent_at", sa.DateTime(), nullable=True, comment="实际发送时间UTC"),
sa.Column("status", sa.String(length=16), server_default="scheduled", nullable=False, comment="scheduled/sent/failed"),
sa.Column("error", sa.Text(), nullable=True, comment="失败原因(可选)"),
sa.Column("created_at", sa.DateTime(), server_default=sa.func.now(), nullable=False, comment="创建时间"),
sa.UniqueConstraint("client_user_id", "local_date", "slot_index", name="uniq_user_date_slot"),
mysql_charset="utf8mb4",
)
op.create_index("idx_push_log_user_date", "push_send_log", ["client_user_id", "local_date"], unique=False)
op.create_index("idx_push_log_status", "push_send_log", ["status"], unique=False)
def downgrade() -> None:
op.drop_index("idx_push_log_status", table_name="push_send_log")
op.drop_index("idx_push_log_user_date", table_name="push_send_log")
op.drop_table("push_send_log")
op.drop_table("push_preferences")
op.drop_index("idx_push_tokens_is_active", table_name="push_tokens")
op.drop_index("idx_push_tokens_client_user_id", table_name="push_tokens")
op.drop_table("push_tokens")