feat: 初始化微信小程序后端骨架

- NestJS + TypeScript + Prisma + PostgreSQL 工程骨架
- 微信登录安全流程:服务端 code2Session 换 openid 后签发 JWT,
  session_key 缓存于 Redis,不信任前端 openid
- 统一响应/异常处理、JWT 全局鉴权(@Public 豁免)、Swagger 文档
- Prisma 全量核心 schema(用户/分类/商品/设计清单/地址/订单/支付/上传/定制任务)+ seed
- 业务模块空壳(商品/分类/设计清单/地址/订单/支付/上传/BullMQ 队列)
- Docker 多阶段镜像 + 本地/生产 docker-compose
- docs:密钥获取指南、COS SDK 移除记录

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-05 17:33:50 +08:00
co-authored by Claude Fable 5
commit deaa0c9ce4
73 changed files with 9533 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
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> {
const app = await NestFactory.create(AppModule);
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();