ci/woodpecker/push/main Pipeline was successful
- 表 strategy_charter(一账套一行,entity_id 唯一):mission/vision/vision_year/vision_measurable/values_text/value_items(JSON) 全 NOT NULL
- 迁移脚本 backend/scripts/migrate_strategy_charter_20261021.py:--check/--apply/--down(回滚先 mysqldump,有数据需 --force),零 INSERT
- API:GET 无行 → filled=false 空态(禁示例数据);PUT 字段白名单 + 账套隔离三道 + vision_year 4位年份 + value_items [{name,meaning}] 结构校验
- 前端:P 组「战略章程」入口 + MyDialog 编辑(ceo/finance 可写,其余只读);战略地图页顶部只读章程条
- 用例 43 条 + auth-surface 58 条 = 101 passed;vite build rc=0
65 lines
3.3 KiB
Python
65 lines
3.3 KiB
Python
"""战略基座 — 战略章程(使命 / 愿景 / 价值观)
|
||
|
||
任务:`project-20261021-cma-strategy-charter-p0-fullstack`(P0 战略基座)
|
||
依据:《2026-10-21 CMA 知识库 M0 与系统实现差距报告》§四 P0 —— 知识卡
|
||
`CMA-P1-B-009 愿景、使命与价值观`:使命=为何存在;愿景=要成为什么
|
||
(**带年份与可验证状态**);价值观=不可交易的底线,是决策冲突时的裁决依据。
|
||
|
||
单一事实源:每个账套(entity_id)**一条**章程行,唯一键 uq_strategy_charter_entity。
|
||
本模块只做「表结构 + 契约常量」;读写端点见 app/api/charter.py。
|
||
|
||
字段语义(派单表:语义不可减,类型可调整):
|
||
mission 使命 TEXT NOT NULL
|
||
vision 愿景 TEXT NOT NULL
|
||
vision_year 愿景达成年份 VARCHAR(20) NOT NULL(**不可空**;4 位年份)
|
||
vision_measurable 可验证状态 TEXT NOT NULL(**不可空**;用可核对的规模/业务口径描述)
|
||
values_text 价值观总述 TEXT NOT NULL
|
||
value_items 价值观条目 JSON NOT NULL `[{name, meaning}]`
|
||
—— 每条须能作"决策冲突时的裁决依据"
|
||
|
||
隔离:`entity_id NOT NULL` + 唯一键以 entity_id 打头(多租户隔离 + 索引可用性)。
|
||
禁止示例数据:本模块与迁移脚本**零 INSERT**;GET 无行返回 `filled=false` 空态。
|
||
"""
|
||
from sqlalchemy import Column, Integer, String, Text, JSON, DateTime, UniqueConstraint, func
|
||
from app.database import Base
|
||
|
||
# 愿景年度格式:4 位年份(不臆造业务上限;允许字符串以兼容前端输入)
|
||
VISION_YEAR_RE = r"^\d{4}$"
|
||
|
||
# 长文本上限(与列宽一致,避免 MySQL 截断静默丢字)
|
||
MISSION_MAX_LEN = 1000
|
||
VISION_MAX_LEN = 1000
|
||
VISION_MEASURABLE_MAX_LEN = 1000
|
||
VALUES_TEXT_MAX_LEN = 2000
|
||
VALUE_ITEM_NAME_MAX_LEN = 50
|
||
VALUE_ITEM_MEANING_MAX_LEN = 300
|
||
VALUE_ITEMS_MAX = 20
|
||
|
||
|
||
class StrategyCharter(Base):
|
||
"""战略章程 — 使命/愿景(年度+可验证状态)/价值观(每账套一行)"""
|
||
__tablename__ = "strategy_charter"
|
||
|
||
id = Column(Integer, primary_key=True)
|
||
entity_id = Column(Integer, nullable=False, comment="企业ID(账套,多租户隔离;唯一键已建索引)")
|
||
mission = Column(Text, nullable=False, comment="使命:我们为何存在(做什么、为谁做)")
|
||
vision = Column(Text, nullable=False, comment="愿景:要成为什么")
|
||
vision_year = Column(String(20), nullable=False, comment="愿景达成年份 YYYY(不可空)")
|
||
vision_measurable = Column(
|
||
Text, nullable=False,
|
||
comment="可验证状态:用可核对的规模/业务口径描述(不可空)",
|
||
)
|
||
values_text = Column(Text, nullable=False, comment="价值观总述(不可交易的底线)")
|
||
value_items = Column(
|
||
JSON, nullable=False,
|
||
comment="价值观条目数组 [{name, meaning}],每条可作决策冲突时的裁决依据",
|
||
)
|
||
updated_by = Column(Integer, nullable=True, comment="最后修改人 user.id")
|
||
updated_by_name = Column(String(50), nullable=True, comment="最后修改人姓名(快照)")
|
||
created_at = Column(DateTime, server_default=func.now())
|
||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint("entity_id", name="uq_strategy_charter_entity"),
|
||
)
|