addresses: - 补 PATCH /:id、DELETE /:id(契约 §4 全路由齐备) - 默认地址唯一性事务:create/update/setDefault 先清旧默认再写入 - 首个地址自动设为默认;删除默认地址事务内补偿最新一条 - 归属校验统一:不存在 404,非本人 403 design-list: - 补 PATCH /:id、DELETE /:id、POST /batch-delete(宽松语义返回 deleted 数) - items 强制恰好 1 个元素(一条设计=一条清单,阶段0 决策#1) - designData 白名单 7 键放行、单条 ≤1MB 校验(400) - 单向状态机 DRAFT→SUBMITTED→PROCESSING→DONE,回退/跳级 400 - PATCH 部分更新语义,不传 items 不清 designData(R4 wordcloud 保护) infra: - main.ts: JSON body 上限 100KB→2MB,使契约 1MB 设计数据可达(>2MB 返回 413) - exceptions filter: body-parser entity.too.large 映射 413 - api-contract-v1.md §5 补实现说明(非契约变更) 验证:nest build 通过;本地 3091 实例 + mock 登录实测 35 项全过 (CRUD/默认地址补偿/越权 403/404/状态机/1MB 边界/413/未登录 401) Co-Authored-By: Claude <noreply@anthropic.com>
65 lines
1.4 KiB
TypeScript
65 lines
1.4 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||
import { Type } from 'class-transformer';
|
||
import {
|
||
ArrayMaxSize,
|
||
ArrayMinSize,
|
||
IsArray,
|
||
IsNotEmpty,
|
||
IsNumber,
|
||
IsObject,
|
||
IsOptional,
|
||
IsString,
|
||
Max,
|
||
Min,
|
||
ValidateNested,
|
||
} from 'class-validator';
|
||
|
||
/**
|
||
* 清单条目(api-contract-v1 §5)。
|
||
* 阶段0 决策#1:一条前端 DesignItem = 一条后端 DesignList,items 固定 1 个元素;
|
||
* 决策#3:productIcon 不入库,由客户端按 productId 推导。
|
||
*/
|
||
export class DesignListEntryDto {
|
||
@ApiProperty()
|
||
@IsString()
|
||
@IsNotEmpty()
|
||
productId!: string;
|
||
|
||
@ApiProperty()
|
||
@IsString()
|
||
@IsNotEmpty()
|
||
productName!: string;
|
||
|
||
@ApiProperty()
|
||
@IsNumber()
|
||
@Min(0)
|
||
unitPrice!: number;
|
||
|
||
@ApiProperty()
|
||
@IsNumber()
|
||
@Min(1)
|
||
@Max(999)
|
||
count!: number;
|
||
|
||
/** 结构白名单与大小校验在 service 层做(设计数据契约 v1) */
|
||
@ApiPropertyOptional()
|
||
@IsOptional()
|
||
@IsObject()
|
||
designData?: Record<string, unknown>;
|
||
}
|
||
|
||
export class CreateDesignListDto {
|
||
@ApiProperty({ description: '清单标题;前端传 productName(阶段0 决策#4)' })
|
||
@IsString()
|
||
@IsNotEmpty()
|
||
title!: string;
|
||
|
||
@ApiProperty({ type: [DesignListEntryDto] })
|
||
@IsArray()
|
||
@ArrayMinSize(1)
|
||
@ArrayMaxSize(1)
|
||
@ValidateNested({ each: true })
|
||
@Type(() => DesignListEntryDto)
|
||
items!: DesignListEntryDto[];
|
||
}
|