refactor(api): parsing out of runtime — pure-mirror sync, explicit organize, auto aggregate recompute

解析去运行时化(三层架构,plans/refactor/organize-script-refactor.md):
- 同步 = 纯镜像:upsertOriginGood 不再写解析列、不再自动挂族;详情同步仍触发重算
- 整理 = 显式人工动作(OrganizeService):解析列回填 → 派生标签(人工接管永不
  覆盖)→ auto-group 建族 → 全量重算;入口 CLI(pnpm --filter @inkreach/api
  organize)+ POST /product-families/organize + 后台「整理」按钮
- 重算 = 纯结构化聚合:不再按名称重派生标签(防上游改名倒灌,回归测试覆盖);
  矩阵维度只认标签/CUSTOM 显式标签,未整理成员不进矩阵;工艺=不打印时
  印花数量以单面占位(纯结构化规则);「恢复自动」走整理的单链接派生
- 派生默认补齐(脚本层假设):名称无单/双面且工艺非不打印 → 印花数量单面印花
- goods 服务建品/更新后仅镜像标签+重算(不派生);含商品名入库规范化
  (normalizeGoodName,管理员输入边界质检)
- organize.service.spec 由 tag-sync spec 迁移 + 防倒灌回归;sync/recompute/
  public/families spec 全部适配;API 173/173,admin typecheck+22/22
This commit is contained in:
yeuimu
2026-08-30 01:27:01 +08:00
parent 976f308e3c
commit 93ac525c55
24 changed files with 2280 additions and 1946 deletions
@@ -3,6 +3,8 @@ import { Prisma } from '@prisma/client';
import { PublicService } from './public.service';
import { PrismaService } from '../prisma/prisma.service';
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
import { ProductFamiliesService } from '../product-families/product-families.service';
import { OrganizeService } from '../product-families/organize.service';
/**
* 三期灰度族块集成测试:PUBLIC_DETAIL_FROM_FAMILY 开关两态行为、
@@ -68,7 +70,15 @@ describe('PublicService family block (PUBLIC_DETAIL_FROM_FAMILY)', () => {
familyId = family.id;
createdFamilyIds.push(family.id);
await prisma.originGood.update({ where: { id: og.id }, data: { familyId: family.id } });
await new FamilyRecomputeService(prisma).recomputeFamily(family.id);
// 解析去运行时化:先整理派生标签,再重算(重算只聚合不解析)
const recomputeSvc = new FamilyRecomputeService(prisma);
const organizeSvc = new OrganizeService(
prisma,
recomputeSvc,
new ProductFamiliesService(prisma, recomputeSvc),
);
await organizeSvc.deriveFamilyTags(family.id);
await recomputeSvc.recomputeFamily(family.id);
const good = await prisma.good.create({
data: {