Files
wxmp_backend/src/main.ts
T
lhmin0604andClaude 0a3c8e834d feat(r2): 地址与设计清单完整 CRUD(事务/归属校验/状态机)
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>
2026-09-12 02:37:53 +08:00

54 lines
2.0 KiB
TypeScript
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.
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as express from 'express';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';
import { TransformInterceptor } from './common/interceptors/transform.interceptor';
async function bootstrap(): Promise<void> {
// 设计清单 designData 契约上限 1MBapi-contract-v1 §5),
// body 限制放宽到 2MB,超 1MB 的业务校验在 design-list service 返回 400
const app = await NestFactory.create(AppModule, { bodyParser: false });
app.use(express.json({ limit: '2mb' }));
app.use(express.urlencoded({ extended: true, limit: '2mb' }));
const config = app.get(ConfigService);
app.setGlobalPrefix('api', { exclude: ['health'] });
app.enableCors();
// 全局管道:剥离未声明字段 + 自动类型转换 + 拒绝多余字段
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
}),
);
// 统一响应包裹 + 统一异常输出
app.useGlobalInterceptors(new TransformInterceptor());
app.useGlobalFilters(new AllExceptionsFilter());
// Swagger 文档,生产环境可置空 SWAGGER_PATH 关闭
const swaggerPath = config.get<string>('app.swaggerPath');
if (swaggerPath) {
const docConfig = new DocumentBuilder()
.setTitle('wxmp-backend API')
.setDescription('微信小程序后端接口文档')
.setVersion('0.1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, docConfig);
SwaggerModule.setup(swaggerPath, app, document);
}
const port = config.get<number>('app.port') ?? 3000;
await app.listen(port);
// eslint-disable-next-line no-console
console.log(`应用已启动: http://localhost:${port} | Swagger: /${swaggerPath}`);
}
void bootstrap();