ๆ็จ NestJS + Vue3 + Prisma + PostgreSQL ๆ้ ไบไธไธชไผไธ็บง sass ๅค็งๆทๅนณๅฐ
Source: Juejin Frontend Hottest
๐ฏ ๆ็จ NestJS + Vue3 + Prisma + PostgreSQL ๆ้ ไบไธไธชไผไธ็บง sass ๅค็งๆทๅนณๅฐ
ไธไธช็ไบง็บง็ๅ จๆ ็ฎก็็ณป็ปๅผๆบ้กน็ฎ๏ผไป้ถๅฐไธ็ๅฎๆๅไบซ
ๅ่จ
่ฟๆฏไธไธชๅบไบ NestJS + Vue3 + Prisma + PostgreSQL ** ๆๅปบ็ๅ จๆ ็ฎก็็ณป็ป๏ผไธๆฏ็ฎๅ็ CRUD๏ผ่ๆฏไธไธช็ไบง็บงๅซ**็่งฃๅณๆนๆกใๅฎๅ ๅซไบๅค็งๆทๆถๆใRBACๆ้็ฎก็ใ่ฏทๆฑๅ ๅฏใๅฎๅ็ๆฅๅฟ็ๆง็ญไผไธ็บง็นๆงใ
๐ ้กน็ฎ้พๆฅ
๐ GitHub ๅผๆบๅฐๅ๏ผgithub.com/linlingqin7โฆ
๐ฎ ๅจ็บฟไฝ้ชๅฐๅ๏ผwww.linlingqin.top/
๐ ้กน็ฎๆๆกฃๅฐๅ๏ผ้กน็ฎๆๆกฃ
ไฝ้ช่ดฆๅท๏ผdemo / demo123 (็งๆท 000000)
ๅฎๆดๆ้่ดฆๅท๏ผadmin / admin123 (็งๆท 000000)
๐ฑ ๅ ็ๆๆ
็ปๅฝ้กต้ข
ๆฏๆ่ดฆๅทๅฏ็ ็ปๅฝใ้ช่ฏ็ ้ช่ฏใ่ฎฐไฝๅฏ็
้ฆ้กตไปช่กจๆฟ
็ณป็ปๆฆ่งใๅฟซๆทๅ ฅๅฃใๆฐๆฎ็ป่ฎกใๅพ่กจๅฑ็คบ
็จๆท็ฎก็
็จๆทๅ่กจใ่ง่ฒๅ้ ใ้จ้จ้ๆฉใ็ถๆ็ฎก็
่ง่ฒ็ฎก็
่ง่ฒๆ้้ ็ฝฎใ่ๅๆ้ๆ ใๆฐๆฎๆ้่ๅด
- โจ ็ฐไปฃๅ็็้ข่ฎพ่ฎก๏ผๆฏๆๆทฑ่ฒๆจกๅผ
- ๐ฑ ๅๅบๅผๅธๅฑ๏ผๅฎ็พ้้ ๅ็งๅฑๅน
- ๐จ ไธฐๅฏ็็ปไปถๅไบคไบๆๆ
๏ฟฝ ๅฎๆดๅ่ฝๆชๅพ
่ๅ็ฎก็
่ๅๆ ๅฝข็ปๆใ่ทฏ็ฑ้ ็ฝฎใๅพๆ ้ๆฉใๆ้ๆ ่ฏ
้จ้จ็ฎก็
็ป็ปๆถๆๆ ใ้จ้จไบบๅใๆฐๆฎๆ้
ๅฒไฝ็ฎก็
ๅฒไฝ้ ็ฝฎใๅฒไฝๆๅบใ็ถๆ็ฎก็
ๅญๅ ธ็ฎก็
ๆฐๆฎๅญๅ ธ็ปดๆคใๅญๅ ธ้กน้ ็ฝฎ
ๅๆฐ้ ็ฝฎ
็ณป็ปๅๆฐใๅจๆ้ ็ฝฎใๅๆฐๅ็ฑป
้็ฅๅ ฌๅ
ๅ ฌๅๅๅธใ้็ฅ็ฎก็ใ็ฑปๅๅ็ฑป
็งๆท็ฎก็
ๅค็งๆทๅ่กจใๅฅ้ค้ ็ฝฎใ็งๆท็ถๆ
ๅฎๆถไปปๅก
Cron ไปปๅก้ ็ฝฎใๆง่กๆฅๅฟใไปปๅก็ฎก็
็ณป็ป็ๆง
ๆๅกๅจ็ถๆใCPU/ๅ ๅญไฝฟ็จ็ใ็ฃ็ไฟกๆฏ
็ผๅญ็ๆง
Redis ็ผๅญไฟกๆฏใๅฝไปค็ป่ฎกใ้ฎๅผ็ฎก็
ๅจ็บฟ็จๆท
ๅฎๆถๅจ็บฟ็จๆทใไผ่ฏ็ฎก็ใๅผบๅถไธ็บฟ
ๆไฝๆฅๅฟ
ๆไฝ่ฎฐๅฝใ่ฏทๆฑๅๆฐใๅๅบ็ปๆใๅผๅธธๆ่ท
็ปๅฝๆฅๅฟ
็ปๅฝๅๅฒใIP ๅฐๅใๆต่งๅจไฟกๆฏใ็ปๅฝ็ถๆ
็ผๅญๅ่กจ
็ผๅญ้ฎ็ฎก็ใ่ฟๆๆถ้ดใ็ผๅญๆธ ็
ไธป้ข้ ็ฝฎ
ๅคไธป้ขๅๆขใๆทฑ่ฒๆจกๅผใไธป้ข่ฒ้ ็ฝฎใๅธๅฑๆจกๅผ
โจ ๆ ธๅฟ็นๆง
๐ข ๅค็งๆท SaaS ๆถๆ
่ฟๆฏๆฌ้กน็ฎ็ไธๅคงไบฎ็นใๅฎ็ฐไบๅฎๆด็็งๆทๆฐๆฎ้็ฆป๏ผ
// ๆๆๆฐๆฎๅบๆฅ่ฏข่ชๅจๆ็งๆท่ฟๆปค
const users = await prisma.sysUser.findMany({
where: { name: 'John' }
// tenantId ไผ่ชๅจๆณจๅ
ฅ๏ผๆ ้ๆๅจๆทปๅ
});
// ่ทณ่ฟ็งๆท่ฟๆปค๏ผ็นๆฎๅบๆฏ๏ผ
@IgnoreTenant()
async getAllTenants() {
return await this.prisma.tenant.findMany();
}
ๆๆฏๅฎ็ฐ๏ผ
- ๅบไบ Prisma Extension ๅฎ็ฐ้ๆ็็งๆท่ฟๆปค
- ้่ฟ TenantGuard ไป่ฏทๆฑๅคด่ชๅจ่ฏๅซ็งๆท
- ่ถ ็บง็ฎก็ๅ๏ผ็งๆท 000000๏ผๅฏ่ทจ็งๆท็ฎก็
้็จๅบๆฏ๏ผ
- SaaS ๅนณๅฐ
- ไผไธๅ ้จๅค้จ้จ็ณป็ป
- ็ฝๆ ไบงๅ
๐ RBAC ๆ้็ฎก็
ไธๅชๆฏ็ฎๅ็่ง่ฒๆ้๏ผ่ๆฏๅคๅฑ็บงใ็ป็ฒๅบฆ็ๆ้ๆงๅถ๏ผ
@Controller('users')
export class UserController {
// ้่ฆ็นๅฎๆ้ๆ่ฝ่ฎฟ้ฎ
@RequirePermission('system:user:add')
@Post()
create(@Body() dto: CreateUserDto) {
return this.userService.create(dto);
}
// ้่ฆ็นๅฎ่ง่ฒ
@RequireRole('admin')
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(id);
}
}
ๆ้ๅฑ็บง๏ผ
- ่ๅ็บงๅซ๏ผๆงๅถ่ๅๆพ็คบ/้่
- ๆ้ฎ็บงๅซ๏ผๆงๅถ้กต้ขๅ ๆ้ฎๆ้
- ๆฐๆฎ็บงๅซ๏ผๅ จ้จ/ๆฌ้จ้จ/ไป ๆฌไบบ็ญๆฐๆฎ่ๅด
ๅ็ซฏๆ้ๆงๅถ๏ผ
<template>
<!-- ๆ้ฎ็บงๆ้ -->
<n-button v-if="hasPermission('system:user:add')">
ๆทปๅ ็จๆท
</n-button>
</template>
๐ ่ฏทๆฑๅ ๅฏๆบๅถ
ๆๆๆฐๆฎไผ ่พ้็จ AES + RSA ๆททๅๅ ๅฏ๏ผ
ๅ ๅฏๆต็จ๏ผ
- ๅ็ซฏ็ๆ้ๆบ AES ๅฏ้ฅ
- ็จ AES-CBC ๅ ๅฏ่ฏทๆฑๆฐๆฎ
- ็จๆๅก็ซฏ RSA ๅ ฌ้ฅๅ ๅฏ AES ๅฏ้ฅ
- ๅ้
{encryptedKey, encryptedData}+ headerx-encrypted: true
// ๅ็ซฏ่ชๅจ่งฃๅฏ
@Post('login')
async login(@Body() dto: LoginDto) {
// dto ๅทฒ่ชๅจ่งฃๅฏ๏ผ็ดๆฅไฝฟ็จ
return this.authService.login(dto);
}
// ่ทณ่ฟ่งฃๅฏ๏ผ้ๆๆๆฅๅฃ๏ผ
@SkipDecrypt()
@Get('captcha')
async getCaptcha() {
return this.captchaService.generate();
}
ไผๅฟ๏ผ
- ไฟๆคๅฏ็ ใToken ็ญๆๆไฟกๆฏ
- ้ฒๆญขไธญ้ดไบบๆปๅป
- ๅฏนไธๅกไปฃ็ ้ๆ๏ผ็ฑๆฆๆชๅจ็ปไธๅค็
๐ ๅฎๅ็ๆฅๅฟ็ๆง
ๅบไบ Pino ๅฎ็ฐ็้ซๆง่ฝ็ปๆๅๆฅๅฟ๏ผ
// ่ชๅจ่ฎฐๅฝๆไฝๆฅๅฟ
@Operlog({
businessType: BusinessTypeEnum.UPDATE,
title: 'ไฟฎๆน็จๆท'
})
@Put(':id')
async update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
return this.userService.update(id, dto);
}
็ๆง่ฝๅ๏ผ
- ็ปๆๅๆฅๅฟ๏ผ่ชๅจ่ฎฐๅฝ requestIdใtenantIdใusername
- ๆๆๅญๆฎต่ฑๆ๏ผpasswordใtoken ็ญ่ชๅจ้่
- ๆไฝๅฎก่ฎก๏ผ่ฎฐๅฝ่ฐๅจไปไนๆถ้ดๅไบไปไน
- ็ปๅฝๆฅๅฟ๏ผ็ปๅฝๅๅฒใIPใๆต่งๅจ็ญไฟกๆฏ
- ๅฅๅบทๆฃๆฅ๏ผK8s liveness/readiness ๆข้
- Prometheus ๆๆ ๏ผๆด้ฒ
/api/metrics็ซฏ็น
ๆฅๅฟ่พๅบ็คบไพ๏ผ
{
"level": "info",
"time": "2025-12-22T10:30:00.000Z",
"requestId": "a1b2c3d4",
"tenantId": "000001",
"username": "admin",
"method": "POST",
"url": "/api/system/user",
"statusCode": 200,
"duration": 45
}
๐ญ ๆผ็คบ่ดฆๆท็ณป็ป
ไธไธบไบงๅๆผ็คบ่ฎพ่ฎก็ๅช่ฏป่ดฆๆทๆบๅถ๏ผ
// Demo ่ดฆๆทๆฆๆชๅจ
@UseInterceptors(DemoInterceptor)
@Controller('users')
export class UserController {
@Post() // Demo ่ดฆๆทไผ่ขซ่ชๅจๆฆๆช
create(@Body() dto: CreateUserDto) {
return this.userService.create(dto);
}
@Get() // ๆฅ่ฏขๆไฝไธๅๅฝฑๅ
findAll() {
return this.userService.findAll();
}
}
็นๆง๏ผ
- 52 ไธชๅช่ฏปๆ้๏ผๅฏๆฅ็ๆๆๆจกๅ
- ่ชๅจๆฆๆชๆๆๅๆไฝ๏ผPOST/PUT/DELETE/PATCH๏ผ
- ่ฟๅๅๅฅฝ็ๆ็คบไฟกๆฏ
- ้ๅๆผ็คบ็ซ็นใไบงๅ Demo
๐ ๅฝ้ ๅๆฏๆ
ๅๅ็ซฏๅฎๆด็ i18n ๆนๆก๏ผ
// ๅ็ซฏ
throw new ApiException(ErrorEnum.USER_NOT_FOUND);
// ่ชๅจ่ฟๅๅฏนๅบ่ฏญ่จ็้่ฏฏไฟกๆฏ
// ๅ็ซฏ
const { t } = useI18n();
console.log(t('system.user.name')); // ๆ นๆฎ่ฏญ่จ่ฟๅๅฏนๅบๆๆฌ
ๆฏๆไธญๆใ่ฑๆ๏ผๅฏ่ฝปๆพๆฉๅฑๅ ถไป่ฏญ่จใ
๐ ๏ธ ๆๆฏๆ ่ฏฆ่งฃ
ๅ็ซฏๆๆฏๆ
| ๆๆฏ | ็ๆฌ | ๆ ธๅฟๅบ็จๅบๆฏ | ๆๆฏไบฎ็น |
|---|---|---|---|
| NestJS | 10.x | ไผไธ็บงๆกๆถ๏ผๆๅปบๅฏๆฉๅฑ็ๆๅก็ซฏๅบ็จ | โข ไพ่ตๆณจๅ
ฅ โข ๆจกๅๅ่ฎพ่ฎก โข ่ฃ ้ฅฐๅจ่ฏญๆณ โข ๅ ็ฝฎ TypeScript |
| Prisma | 5.x | ็ฑปๅๅฎๅ จ็ๆฐๆฎๅบ ORM | โข ่ชๅจ็ๆ็ฑปๅ โข ๆฐๆฎๅบ่ฟ็งป โข ๅผบๅคง็ๆฅ่ฏขๆๅปบๅจ โข ๅคๆฐๆฎๅบๆฏๆ |
| PostgreSQL | 14+ | ไธปๆฐๆฎๅบ๏ผๅญๅจๆ ธๅฟไธๅกๆฐๆฎ | โข ACID ไบๅก โข JSON ๆฏๆ โข ไธฐๅฏ็ๆฐๆฎ็ฑปๅ โข ๅผบๅคง็ๆฅ่ฏขไผๅ |
| Redis | 7+ | ็ผๅญใSessionใๅๅธๅผ้ | โข ้ซๆง่ฝ็ผๅญ โข ๆฐๆฎ่ฟๆ็ญ็ฅ โข ๅๅธ่ฎข้ โข ๅๅธๅผ้ |
| JWT | - | ๆ ็ถๆ่บซไปฝ่ฎค่ฏ | โข Token ่ฎค่ฏ โข Refresh Token โข ่ทจๅ่ฎค่ฏ โข ็งปๅจ็ซฏๅๅฅฝ |
| Passport | - | ่ฎค่ฏไธญ้ดไปถ | โข ็ญ็ฅๆจกๅผ โข ๅค็ง่ฎค่ฏๆนๅผ โข ๆไบๆฉๅฑ |
| Pino | - | ้ซๆง่ฝ็ปๆๅๆฅๅฟ | โข JSON ๆฅๅฟ โข ไฝๅผ้ โข ๆฅๅฟ่ฝฎ่ฝฌ โข ๅคไผ ่พ้้ |
| Swagger | - | API ๆๆกฃ่ชๅจ็ๆ | โข ไบคไบๅผๆๆกฃ โข ่ชๅจ็ฑปๅๆจๅฏผ โข ๅจ็บฟๆต่ฏ |
| Terminus | - | ๅฅๅบทๆฃๆฅไธ็ๆง | โข K8s ๆข้ โข ๆฐๆฎๅบๆฃๆฅ โข ๅ ๅญ็ๆง โข ่ชๅฎไนๆฃๆฅ |
| class-validator | - | ๆฐๆฎ้ช่ฏ | โข ่ฃ
้ฅฐๅจ้ช่ฏ โข ่ชๅฎไน่งๅ โข ๅตๅฅ้ช่ฏ |
| class-transformer | - | ๆฐๆฎ่ฝฌๆข | โข DTO ่ฝฌๆข โข ็ฑปๅๆ ๅฐ โข ๆฐๆฎ่ฑๆ |
| @nestjs/schedule | - | ๅฎๆถไปปๅก่ฐๅบฆ | โข Cron ่กจ่พพๅผ โข ้ด้ไปปๅก โข ่ถ ๆถๆงๅถ |
| nestjs-cls | - | ่ฏทๆฑไธไธๆ็ฎก็ | โข ่ฏทๆฑ่ฟฝ่ธช โข ็จๆทไธไธๆ โข ็งๆทไธไธๆ |
ๅ็ซฏๆๆฏๆ
| ๆๆฏ | ็ๆฌ | ๆ ธๅฟๅบ็จๅบๆฏ | ๆๆฏไบฎ็น |
|---|---|---|---|
| Vue 3 | 3.5+ | ๆธ่ฟๅผๅ็ซฏๆกๆถ | โข Composition API โข ๅๅบๅผ็ณป็ป โข ่ๆ DOM โข ็ปไปถๅๅผๅ |
| Vite | 7+ | ๆฐไธไปฃๆๅปบๅทฅๅ ท | โข ๆ้ๅทๅฏๅจ โข HMR ็ญๆดๆฐ โข ๆ้็ผ่ฏ โข Rollup ๆๅ |
| Naive UI | ๆๆฐ | ไผไธ็บง็ปไปถๅบ | โข Vue 3 ็ปๅๅผ API โข TypeScript ๆฏๆ โข ไธป้ขๅฎๅถ โข 200+ ็ปไปถ |
| UnoCSS | ๆๆฐ | ๅณๆถๅๅญๅ CSS ๅผๆ | โข ้ถ่ฟ่กๆถ โข ้ซๆง่ฝ โข ้ข่ฎพ็ณป็ป โข ๆ้็ๆ |
| Pinia | ๆๆฐ | ไธไธไปฃ็ถๆ็ฎก็ | โข ่ฝป้็บง โข TypeScript ๆฏๆ โข ๆจกๅๅ โข DevTools ๆฏๆ |
| Vue Router | 4+ | ๅฎๆน่ทฏ็ฑ็ฎก็ | โข ๅจๆ่ทฏ็ฑ โข ่ทฏ็ฑๅฎๅซ โข ๆๅ ่ฝฝ โข ๅตๅฅ่ทฏ็ฑ |
| Axios | ๆๆฐ | HTTP ่ฏทๆฑๅบ | โข Promise API โข ๆฆๆชๅจ โข ่ฏทๆฑๅๆถ โข ่ชๅจ่ฝฌๆข |
| TypeScript | 5.x | ็ฑปๅๅฎๅ จ็ JavaScript | โข ้ๆ็ฑปๅๆฃๆฅ โข IDE ๆบ่ฝๆ็คบ โข ้ๆๆฏๆ โข ๆฅๅฃๅฎไน |
| VueUse | ๆๆฐ | Vue ็ปๅๅผๅฝๆฐ้ๅ | โข ๅธธ็จ Hooks โข ๅๅบๅผๅทฅๅ ท โข ๆต่งๅจ API ๅฐ่ฃ |
| Elegant Router | ๆๆฐ | ๅบไบๆไปถ็่ทฏ็ฑ็ณป็ป | โข ่ชๅจ็ๆ่ทฏ็ฑ โข ็บฆๅฎๅผ่ทฏ็ฑ โข ็ฑปๅๅฎๅ จ |
| ECharts | 5+ | ๆฐๆฎๅฏ่งๅๅพ่กจ | โข ไธฐๅฏ็ๅพ่กจ็ฑปๅ โข ๅๅบๅผ่ฎพ่ฎก โข ไธป้ขๅฎๅถ |
| CryptoJS | - | ๅ ๅฏ็ฎๆณๅบ | โข AES ๅ ๅฏ โข RSA ๅ ๅฏ โข MD5/SHA ๅๅธ |
๐๏ธ ็ณป็ปๆถๆ่ฏฆ่งฃ
๐ ๆดไฝๆถๆๅพ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ็จๆท/ๅฎขๆท็ซฏๅฑ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ ๆต่งๅจ โ โ ็งปๅจ็ซฏApp โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ HTTPS
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ CDN / Nginx ็ฝๅ
ณ โ
โ โข ้ๆ่ตๆบ็ผๅญ โ
โ โข ๅๅไปฃ็ โ
โ โข ่ด่ฝฝๅ่กก โ
โ โข SSL ่ฏไนฆ โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโ
โ ๅ็ซฏๅบ็จ (Vue3) โ โ ๅ็ซฏๅบ็จ (NestJS) โ
โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ UI ๅฑ (Naive UI) โ โ โ โ ๆงๅถๅจๅฑ (Controllers)โ โ
โ โ โข ็ปไปถๅบ โ โ โ โ โข ่ทฏ็ฑๅฎไน โ โ
โ โ โข ไธป้ขๅฎๅถ โ โ โ โ โข ่ฏทๆฑ้ช่ฏ โ โ
โ โ โข ๅๅบๅผๅธๅฑ โ โ โ โ โข ๅๆฐ่ฝฌๆข โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโผโโโโโโโโโโโโโโ โ
โ โ ็ถๆๅฑ (Pinia Store) โ โ โ โ ๅฎๅซๅฑ (Guards) โ โ
โ โ โข ๅ
จๅฑ็ถๆ โ โ โ โ 1. TenantGuard โ โ
โ โ โข ็จๆทไฟกๆฏ โ โ โ โ 2. AuthGuard โ โ
โ โ โข ๆ้ๆฐๆฎ โ โ โ โ 3. RolesGuard โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ 4. PermissionGuard โ โ
โ โ โ โโโโโโโโโโโโโฌโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ โ
โ โ ่ทฏ็ฑๅฑ (Vue Router) โ โ โ โโโโโโโโโโโโโผโโโโโโโโโโโโโโ โ
โ โ โข ๅจๆ่ทฏ็ฑ โ โ โ โ ๆฆๆชๅจๅฑ (Interceptors)โ โ
โ โ โข ่ทฏ็ฑๅฎๅซ โ โ โ โ 1. DecryptInterceptor โ โ
โ โ โข ๆๅ ่ฝฝ โ โ โ โ 2. DemoInterceptor โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ 3. TransformInter... โ โ
โ โ โ โ 4. LoggingInterceptor โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโฌโโโโโโโโโโโโโโ โ
โ โ ่ฏทๆฑๅฑ (Axios) โ โ โ โ โ
โ โ โข ่ฏทๆฑๆฆๆช โโโโผโโโโโโโโผโโโโโโโโโโโโโโโค โ
โ โ โข ๅๅบๆฆๆช โ โ โ โโโโโโโโโโโโโผโโโโโโโโโโโโโโ โ
โ โ โข ้่ฏฏๅค็ โ โ โ โ ไธๅกๅฑ (Services) โ โ
โ โ โข ่ฏทๆฑๅ ๅฏ โ โ โ โ โข ็ณป็ป็ฎก็ Service โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ โข ๆ้็ฎก็ Service โ โ
โ โ โ โ โข ็ๆง็ฎก็ Service โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โข ็งๆท็ฎก็ Service โ โ
โ โโโโโโโโโโโโโฌโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโผโโโโโโโโโโโโโโ โ
โ โ ๆฐๆฎ่ฎฟ้ฎๅฑ (Prisma) โ โ
โ โ โข Schema ๅฎไน โ โ
โ โ โข ็ฑปๅ็ๆ โ โ
โ โ โข ๆฅ่ฏขๆๅปบๅจ โ โ
โ โ โข ็งๆทๆฉๅฑ โ โ
โ โโโโโโโโโโโโโฌโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโผโโโโโโโโโโโ โโโโโโโโโโโโผโโโโโโโโโโโ โ
โ PostgreSQL ๆฐๆฎๅบ โ โ Redis ็ผๅญ โ โ
โ โข ไธปๆฐๆฎๅญๅจ โ โ โข ไผ่ฏๅญๅจ โ โ
โ โข ไบๅกๆฏๆ โ โ โข ๆฐๆฎ็ผๅญ โ โ
โ โข ็ดขๅผไผๅ โ โ โข ๅๅธๅผ้ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ ๅค้จๆๅก้ๆ โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โ โ
โ โ OSS ๅฏน่ฑกๅญๅจโ โ ้ฎไปถๆๅก โ โ ็ญไฟกๆๅก โ โ โ
โ โ โข ้ฟ้ไบ โ โ โข SMTP โ โ โข ้ฟ้ไบ โ โ โ
โ โ โข ไธ็ไบ โ โ โข SendGrid โ โ โข ่
พ่ฎฏไบ โ โ โ
โ โ โข MinIO โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ็ๆงไธๆฅๅฟ โโ โ
โ โ โข Prometheus (ๆๆ ้้) โโ โ
โ โ โข Grafana (ๅฏ่งๅ) โโ โ
โ โ โข Pino Logger (ๆฅๅฟ) โโ โ
โ โ โข Terminus (ๅฅๅบทๆฃๆฅ) โโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ้จ็ฝฒ็ฏๅข (ๅฏ้)
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ Docker ๅฎนๅจๅ โ
โ โ โข ๅบ็จๅฎนๅจ โ
โ โ โข ๆฐๆฎๅบๅฎนๅจ โ
โ โ โข Redis ๅฎนๅจ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ Kubernetes ็ผๆ โ
โ โ โข Pod ็ฎก็ โ
โ โ โข Service ๆด้ฒ โ
โ โ โข Ingress ่ทฏ็ฑ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ ๅฎๆด่ฏทๆฑๅค็ๆต็จ
โโโโโโโโโโโโโโโ
โ 1. ๅฎขๆท็ซฏ โ ๅ่ตท HTTP ่ฏทๆฑ
โโโโโโโโฌโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. ๅ็ซฏ่ฏทๆฑๆฆๆชๅจ โ
โ โข ๆทปๅ Authorization Token โ
โ โข ๆทปๅ ็งๆท ID (x-tenant-id) โ
โ โข ๆๆๆฐๆฎ AES+RSA ๅ ๅฏ โ
โ โข ๆทปๅ ่ฏทๆฑ ID (x-request-id) โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Nginx ็ฝๅ
ณ โ
โ โข SSL ็ปๆญข โ
โ โข ้ๆ่ตๆบๆๅก โ
โ โข ๅๅไปฃ็ๅฐๅ็ซฏ โ
โ โข ่ฏทๆฑๆฅๅฟ่ฎฐๅฝ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. NestJS ไธญ้ดไปถๅฑ โ
โ โข CORS ๅค็ โ
โ โข Body ่งฃๆ โ
โ โข Helmet ๅฎๅ
จๅคด โ
โ โข Request ID ็ๆ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. ๅฎๅซๅฑ (Guards) - ๆ้กบๅบๆง่ก โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5.1 TenantGuard โ โ
โ โ โข ๆๅ่ฏทๆฑๅคดไธญ็็งๆท ID โ โ
โ โ โข ้ช่ฏ็งๆทๆฏๅฆๅญๅจไธๆๆ โ โ
โ โ โข ่ฎพ็ฝฎ็งๆทไธไธๆ (CLS) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5.2 JwtAuthGuard โ โ
โ โ โข ้ช่ฏ JWT Token ๆๆๆง โ โ
โ โ โข ่งฃๆ็จๆทไฟกๆฏ โ โ
โ โ โข ่ฎพ็ฝฎ็จๆทไธไธๆ โ โ
โ โ โข ๆฃๆฅ Token ๆฏๅฆ่ฟๆ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5.3 RolesGuard (ๅฏ้) โ โ
โ โ โข ๆฃๆฅ็จๆท่ง่ฒ โ โ
โ โ โข ้ช่ฏๆฏๅฆๆปก่ถณ่ง่ฒ่ฆๆฑ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5.4 PermissionGuard โ โ
โ โ โข ๆฃๆฅ็จๆทๆ้ โ โ
โ โ โข ้ช่ฏๆฏๅฆๆๆฅๅฃ่ฎฟ้ฎๆ้ โ โ
โ โ โข ๆฏๆๆ้็ปๅ (AND/OR) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. ๆฆๆชๅจๅฑ (Interceptors) - ๅ็ฝฎ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 6.1 DecryptInterceptor โ โ
โ โ โข ๆฃๆตๅ ๅฏ่ฏทๆฑๅคด โ โ
โ โ โข RSA ่งฃๅฏ AES ๅฏ้ฅ โ โ
โ โ โข AES ่งฃๅฏ่ฏทๆฑไฝ โ โ
โ โ โข ๆฟๆขๅๅง่ฏทๆฑๆฐๆฎ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 6.2 DemoInterceptor โ โ
โ โ โข ๆฃๆตๆฏๅฆไธบๆผ็คบ่ดฆๆท โ โ
โ โ โข ๆฆๆชๅๆไฝ (POST/PUT/DELETE) โ โ
โ โ โข ่ฟๅๅๅฅฝๆ็คบไฟกๆฏ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 6.3 LoggingInterceptor (ๅผๅง) โ โ
โ โ โข ่ฎฐๅฝ่ฏทๆฑๅผๅงๆถ้ด โ โ
โ โ โข ่ฎฐๅฝ่ฏทๆฑๅบๆฌไฟกๆฏ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 7. Pipe ็ฎก้้ช่ฏ โ
โ โข ValidationPipe (DTO ้ช่ฏ) โ
โ โข ParseIntPipe (ๅๆฐ่ฝฌๆข) โ
โ โข ่ชๅฎไน้ช่ฏ็ฎก้ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 8. Controller ๆงๅถๅจ โ
โ โข ๆฅๆถ่ฏทๆฑๅๆฐ โ
โ โข ่ฐ็จ Service ๆนๆณ โ
โ โข ๅบ็จ่ฃ
้ฅฐๅจ (@Operlog ็ญ) โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 9. Service ไธๅกๅฑ โ
โ โข ไธๅก้ป่พๅค็ โ
โ โข ๆฐๆฎ้ช่ฏ โ
โ โข ่ฐ็จ Prisma ๆฅ่ฏข โ
โ โข ็ผๅญๆไฝ (Redis) โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 10. Prisma ORM ๅฑ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 10.1 Tenant Extension โ โ
โ โ โข ่ชๅจๆณจๅ
ฅ็งๆท่ฟๆปคๆกไปถ โ โ
โ โ โข ๆๆๆฅ่ฏข่ชๅจๆทปๅ tenantId โ โ
โ โ โข ๆฏๆ @IgnoreTenant ่ทณ่ฟ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 10.2 ๆฅ่ฏขๆง่ก โ โ
โ โ โข ๅๆฐๅๆฅ่ฏข (้ฒ SQL ๆณจๅ
ฅ) โ โ
โ โ โข ไบๅกๆฏๆ โ โ
โ โ โข ๆฅ่ฏขไผๅ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 11. ๆฐๆฎๅบๅฑ โ
โ โข PostgreSQL ๆฅ่ฏขๆง่ก โ
โ โข ็ดขๅผๆฅๆพ โ
โ โข ไบๅกๆไบค/ๅๆป โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ (่ฟๅๆฐๆฎ)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 12. ๆฆๆชๅจๅฑ (Interceptors) - ๅ็ฝฎ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 12.1 TransformInterceptor โ โ
โ โ โข ็ปไธๅๅบๆ ผๅผ โ โ
โ โ โข {code, msg, data, timestamp} โ โ
โ โ โข ่ฑๆๅค็ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 12.2 LoggingInterceptor (็ปๆ) โ โ
โ โ โข ่ฎก็ฎ่ฏทๆฑ่ๆถ โ โ
โ โ โข ่ฎฐๅฝๅๅบ็ถๆ็ โ โ
โ โ โข ่ฎฐๅฝๅฐๆไฝๆฅๅฟ่กจ โ โ
โ โ โข ่พๅบ็ปๆๅๆฅๅฟ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 13. ๅผๅธธ่ฟๆปคๅจ (Exception Filters) โ
โ โข ๆ่ทๅผๅธธ โ
โ โข ๆ ผๅผๅ้่ฏฏๅๅบ โ
โ โข ่ฎฐๅฝ้่ฏฏๆฅๅฟ โ
โ โข ่ฟๅๅๅฅฝ้่ฏฏไฟกๆฏ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 14. ๅๅบ่ฟๅๅฎขๆท็ซฏ โ
โ โข HTTP Response โ
โ โข ็ถๆ็ + ๅๅบไฝ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ข ๅค็งๆทๆถๆๅพ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ็งๆท A ็จๆท โ
โ (tenantId: 000001) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ็งๆท B ็จๆท โ
โ (tenantId: 000002) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NestJS ๅบ็จ - TenantGuard โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 1. ๆๅ่ฏทๆฑๅคดไธญ็็งๆท ID (x-tenant-id) โ โ
โ โ 2. ้ช่ฏ็งๆทๆฏๅฆๅญๅจไธ็ถๆไธบๅฏ็จ โ โ
โ โ 3. ๅฐ็งๆท ID ๅญๅ
ฅ่ฏทๆฑไธไธๆ (CLS) โ โ
โ โ 4. ๅ็ปญๆๆๆไฝ่ชๅจไฝฟ็จ่ฏฅ็งๆทไธไธๆ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Prisma Client - Tenant Extension โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ๆๆๆฐๆฎๅบๆฅ่ฏข่ชๅจๆณจๅ
ฅ็งๆท่ฟๆปค: โ โ
โ โ โ โ
โ โ ๅๅงๆฅ่ฏข: โ โ
โ โ prisma.sysUser.findMany({ where: { ... } }) โ โ
โ โ โ โ
โ โ ่ชๅจ่ฝฌๆขไธบ: โ โ
โ โ prisma.sysUser.findMany({ โ โ
โ โ where: { โ โ
โ โ tenantId: '000001', // ่ชๅจๆณจๅ
ฅ โ โ
โ โ ... โ โ
โ โ } โ โ
โ โ }) โ โ
โ โ โ โ
โ โ ๆฏๆ็ๆไฝ: โ โ
โ โ โข findMany / findUnique / findFirst โ โ
โ โ โข create / createMany โ โ
โ โ โข update / updateMany โ โ
โ โ โข delete / deleteMany โ โ
โ โ โข count / aggregate โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PostgreSQL ๆฐๆฎๅบ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ็งๆท A ๆฐๆฎ โ โ ็งๆท B ๆฐๆฎ โ โ
โ โ โโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโ โ โ
โ โ โ tenantId: 0001 โ โ โ โ tenantId: 0002 โ โ โ
โ โ โ user_id: 1 โ โ โ โ user_id: 100 โ โ โ
โ โ โ name: ๅผ ไธ โ โ โ โ name: ๆๅ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโ โ โ
โ โ โโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโ โ โ
โ โ โ tenantId: 0001 โ โ โ โ tenantId: 0002 โ โ โ
โ โ โ user_id: 2 โ โ โ โ user_id: 101 โ โ โ
โ โ โ name: ็ไบ โ โ โ โ name: ่ตตๅ
ญ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โ ๆฐๆฎๅฎๅ
จ้็ฆป๏ผไบไธๅนฒๆฐ โ
โ โ ๅ
ฑไบซๆฐๆฎๅบ๏ผ้ไฝๆๆฌ โ
โ โ tenantId ๅญๆฎตๅปบ็ซ็ดขๅผ๏ผๆฅ่ฏข้ซๆ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
็นๆฎๅบๆฏ: ่ถ
็บง็ฎก็ๅๆฅ่ฏข
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ @IgnoreTenant() // ่ทณ่ฟ็งๆท่ฟๆปค โ
โ async getAllTenants() { โ
โ return await this.prisma.tenant.findMany(); โ
โ } โ
โ // ๅฏไปฅๆฅ่ฏขๆๆ็งๆท็ๆฐๆฎ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ ๆ้ๆงๅถๆถๆๅพ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ็จๆท็ปๅฝๆๅ โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ JWT Token ็ๆ (ๅ
ๅซ็จๆทๅบๆฌไฟกๆฏ) โ
โ { โ
โ userId: 1, โ
โ username: 'admin', โ
โ tenantId: '000000', โ
โ roles: ['admin'], โ
โ exp: 1640000000 // ่ฟๆๆถ้ด โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ็ซฏๅญๅจ Token โ
โ โข localStorage.setItem('token', token) โ
โ โข ๆฏๆฌก่ฏทๆฑ่ชๅจๆบๅธฆ: Authorization: Bearer ${token} โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ็ซฏๆฅๆถ่ฏทๆฑ - ๆ้ๆฃๆฅๆต็จ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Step 1: JwtAuthGuard โ โ
โ โ โโ ้ช่ฏ Token ็ญพๅ โ โ
โ โ โโ ๆฃๆฅ Token ๆฏๅฆ่ฟๆ โ โ
โ โ โโ ่งฃๆ็จๆทไฟกๆฏ โ โ
โ โ โโ ไป Redis ๅ ่ฝฝๅฎๆด็จๆทๆ้ โ โ
โ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Redis ็ผๅญ็็จๆทๆ้ๆฐๆฎ โ โ โ
โ โ โ user:permissions:1 โ โ โ
โ โ โ { โ โ โ
โ โ โ roles: ['admin', 'user'], โ โ โ
โ โ โ permissions: [ โ โ โ
โ โ โ 'system:user:add', โ โ โ
โ โ โ 'system:user:edit', โ โ โ
โ โ โ 'system:user:delete', โ โ โ
โ โ โ 'system:user:query', โ โ โ
โ โ โ 'system:role:*', // ้้
็ฌฆ โ โ โ
โ โ โ ... โ โ โ
โ โ โ ], โ โ โ
โ โ โ menuIds: [1,2,3,4,5,...], โ โ โ
โ โ โ dataScope: 'DEPT_AND_CHILD' โ โ โ
โ โ โ } โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Step 2: RolesGuard (ๅฏ้) โ โ
โ โ @RequireRole('admin') โ โ
โ โ โโ ๆฃๆฅ็จๆทๆฏๅฆๆฅๆๆๅฎ่ง่ฒ โ โ
โ โ โโ ๆฏๆๅค่ง่ฒ: @RequireRole('admin', 'manager') โ โ
โ โ โโ ๆฏๆ่ง่ฒ็ปๅ: AND / OR โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Step 3: PermissionGuard โ โ
โ โ @RequirePermission('system:user:edit') โ โ
โ โ โโ ๆๅๆฅๅฃๆ้ๆ้ โ โ
โ โ โโ ๆฃๆฅ็จๆทๆ้ๅ่กจ โ โ
โ โ โโ ๆฏๆ้้
็ฌฆๅน้
(system:user:*) โ โ
โ โ โโ ๆฏๆๆ้็ปๅ: AND / OR โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โ ๆ้้ช่ฏ้่ฟ โ ๆ้้ช่ฏๅคฑ่ดฅ
โผ โผ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆง่กไธๅก้ป่พ โ โ ่ฟๅ 403 Forbidden โ
โ โข Controller โ โ { code: 403, โ
โ โข Service โ โ msg: 'ๆ ๆ้่ฎฟ้ฎ' }โ
โ โข Prisma โ โโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโ
ๆฐๆฎๆ้ๆงๅถ (Data Scope):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅจ Service ๅฑๆ นๆฎ็จๆท็ dataScope ่ฟๆปคๆฐๆฎ: โ
โ โ
โ async findUsers(query, user) { โ
โ const where = { ...query }; โ
โ โ
โ if (user.dataScope === 'ALL') { โ
โ // ๆฅ่ฏขๆๆๆฐๆฎ (่ถ
็บง็ฎก็ๅ) โ
โ } else if (user.dataScope === 'DEPT_AND_CHILD') { โ
โ // ๆฅ่ฏขๆฌ้จ้จๅๅญ้จ้จๆฐๆฎ โ
โ where.deptId = { in: user.deptIds }; โ
โ } else if (user.dataScope === 'DEPT') { โ
โ // ๅชๆฅ่ฏขๆฌ้จ้จๆฐๆฎ โ
โ where.deptId = user.deptId; โ
โ } else if (user.dataScope === 'SELF') { โ
โ // ๅชๆฅ่ฏข่ชๅทฑ็ๆฐๆฎ โ
โ where.userId = user.userId; โ
โ } โ
โ โ
โ return await this.prisma.user.findMany({ where }); โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ ่ฏทๆฑๅ ๅฏๆถๆๅพ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ็ซฏ - ๅ ๅฏๆต็จ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 1. ๅๅคๆๆๆฐๆฎ โ โ
โ โ const data = { โ โ
โ โ username: 'admin', โ โ
โ โ password: 'admin123' // ๆๆไฟกๆฏ โ โ
โ โ }; โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 2. ็ๆ้ๆบ AES ๅฏ้ฅ (ๆฏๆฌก่ฏทๆฑ้ฝไธๅ) โ โ
โ โ const aesKey = CryptoJS.lib.WordArray.random(16); โ โ
โ โ // ไพ: "a1b2c3d4e5f6g7h8" โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 3. ็จ AES ๅฏ้ฅๅ ๅฏๆฐๆฎ โ โ
โ โ const encryptedData = CryptoJS.AES.encrypt( โ โ
โ โ JSON.stringify(data), โ โ
โ โ aesKey, โ โ
โ โ { mode: CryptoJS.mode.CBC, iv: randomIV } โ โ
โ โ ); โ โ
โ โ // ็ปๆ: "U2FsdGVkX1+..." (Base64) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 4. ็จๆๅก็ซฏ RSA ๅ
ฌ้ฅๅ ๅฏ AES ๅฏ้ฅ โ โ
โ โ const encryptedKey = RSA.encrypt( โ โ
โ โ aesKey.toString(), โ โ
โ โ serverPublicKey // ๆๅก็ซฏๆไพ็ๅ
ฌ้ฅ โ โ
โ โ ); โ โ
โ โ // RSA 2048 ๅ ๅฏ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5. ๅ้ๅ ๅฏ่ฏทๆฑ โ โ
โ โ POST /api/login โ โ
โ โ Headers: โ โ
โ โ x-encrypted: true // ๆ ่ฏๅ ๅฏ่ฏทๆฑ โ โ
โ โ Body: โ โ
โ โ { โ โ
โ โ encryptedKey: "MIIBIj...", // RSA ๅ ๅฏ็ๅฏ้ฅ โ โ
โ โ encryptedData: "U2FsdG..." // AES ๅ ๅฏ็ๆฐๆฎ โ โ
โ โ } โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ HTTPS ๅ ๅฏไผ ่พ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ็ซฏ - ่งฃๅฏๆต็จ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 1. DecryptInterceptor ๆฆๆช่ฏทๆฑ โ โ
โ โ if (request.headers['x-encrypted'] === 'true') { โ โ
โ โ // ๆง่ก่งฃๅฏๆต็จ โ โ
โ โ } โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 2. ็จๆๅก็ซฏ RSA ็ง้ฅ่งฃๅฏ AES ๅฏ้ฅ โ โ
โ โ const aesKey = RSA.decrypt( โ โ
โ โ encryptedKey, โ โ
โ โ serverPrivateKey // ๆๅก็ซฏ็็ง้ฅ โ โ
โ โ ); โ โ
โ โ // ๅพๅฐ: "a1b2c3d4e5f6g7h8" โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 3. ็จ AES ๅฏ้ฅ่งฃๅฏๆฐๆฎ โ โ
โ โ const decryptedData = AES.decrypt( โ โ
โ โ encryptedData, โ โ
โ โ aesKey โ โ
โ โ ); โ โ
โ โ // ๅพๅฐๅๅงๆฐๆฎ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 4. ่งฃๆ JSON ๅนถๆฟๆข request.body โ โ
โ โ request.body = JSON.parse(decryptedData); โ โ
โ โ // { โ โ
โ โ // username: 'admin', โ โ
โ โ // password: 'admin123' โ โ
โ โ // } โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ 5. ๅ็ปญๆต็จไฝฟ็จ่งฃๅฏๅ็ๆฐๆฎ โ โ
โ โ Controller ๅ Service ็ดๆฅไฝฟ็จ request.body โ โ
โ โ ๅฎๅ
จ้ๆ,ๆ ้ๅ
ณๅฟๅ ่งฃๅฏ้ป่พ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ๅฎๅ
จไผๅฟ:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ ๅ้ๅ ๅฏ: AES (ๅฏน็งฐ) + RSA (้ๅฏน็งฐ) โ
โ โ ๆฏๆฌก่ฏทๆฑ็ AES ๅฏ้ฅ้ฝไธๅ,ๆ ๆณ้ๆพๆปๅป โ
โ โ RSA ็ง้ฅๅชๅญๅจๆๅก็ซฏ,ๅ็ซฏๆ ๆณ่งฃๅฏ โ
โ โ ๅณไฝฟ HTTPS ่ขซ็ ด่งฃ,ๆฐๆฎไป็ถๅ ๅฏ โ
โ โ ๅฏ็ ็ญๆๆไฟกๆฏๆฐธไธๆๆไผ ่พ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ฏ ๆ ธๅฟๅ่ฝๆจกๅ่ฏฆ่งฃ
1๏ธโฃ ็ณป็ป็ฎก็ๆจกๅ
๐ค ็จๆท็ฎก็
ๅฎๆด็็จๆท็ๅฝๅจๆ็ฎก็๏ผๆฏๆไผไธ็บง็จๆทไฝ็ณป๏ผ
- ็จๆท CRUD๏ผๆฐๅขใ็ผ่พใๅ ้คใๆน้ๆไฝ
- ่ง่ฒๅ้ ๏ผๆฏๆไธไธช็จๆทๅคไธช่ง่ฒ
- ้จ้จๅฝๅฑ๏ผๅ ณ่็ป็ปๆถๆ๏ผๅฎ็ฐๆฐๆฎๆ้้็ฆป
- ๅฏ็ ็ฎก็๏ผๅฏ็ ้็ฝฎใๅฏ็ ๅผบๅบฆ้ช่ฏใๅฎๆไฟฎๆนๆ้
- ็ถๆ็ฎก็๏ผๅฏ็จ/็ฆ็จใ้ๅฎ/่งฃ้
- ๅฏผๅ ฅๅฏผๅบ๏ผๆน้ๅฏผๅ ฅ็จๆทใๅฏผๅบ Excel
- ็จๆท็ปๅ๏ผ็ปๅฝ็ป่ฎกใๆไฝ่ฎฐๅฝใๆ้่งๅพ
๐ญ ่ง่ฒ็ฎก็
ๅบไบ RBAC ็็ตๆดปๆ้ๆงๅถ๏ผ
- ๆ้ๅ้ ๏ผ่ๅๆ้ๆ ้ๆฉ๏ผๆฏๆๅ้็ถๆ
- ๆฐๆฎๆ้๏ผๅ จ้จๆฐๆฎ/ๆฌ้จ้จ/ๆฌ้จ้จๅๅญ้จ้จ/ไป ๆฌไบบ
- ่ง่ฒ็ปงๆฟ๏ผๆฏๆ่ง่ฒ้ด็ๆ้็ปงๆฟๅ ณ็ณป
- ๅจๆๆ้๏ผๆ้ๅๆดๅฎๆถ็ๆ๏ผๆ ้้ๆฐ็ปๅฝ
- ๆ้้ข่ง๏ผๅฏ่งๅๅฑ็คบ่ง่ฒๆฅๆ็ๆๆๆ้
๐ ่ๅ็ฎก็
ๅจๆ่ๅ้ ็ฝฎ๏ผๆฏๆๆ ้ๅฑ็บง๏ผ
- ๆ ๅฝข็ปๆ๏ผๅฏ่งๅ็่ๅๆ ็ผ่พ
- ่ๅ็ฑปๅ๏ผ็ฎๅฝใ่ๅใๆ้ฎไธ็ง็ฑปๅ
- ๅพๆ ้ๆฉ๏ผๅ ็ฝฎๅพๆ ๅบ๏ผๆฏๆ่ชๅฎไน
- ่ทฏ็ฑ้ ็ฝฎ๏ผๅ็ซฏ่ทฏ็ฑ่ทฏๅพใ็ปไปถ่ทฏๅพ
- ๆ้ๆ ่ฏ๏ผๆ้ฎ็บงๆ้ๆงๅถๆ ่ฏ
- ๆพ็คบๆงๅถ๏ผ่ๅๆพ็คบ/้่ใ็ผๅญๆงๅถ
- ๅค้พ่ๅ๏ผๆฏๆๅค้จ้พๆฅ่ๅ
๐ข ้จ้จ็ฎก็
ไผไธ็ป็ปๆถๆ็ฎก็๏ผ
- ๆ ๅฝข็ปๆ๏ผๆ ้ๅฑ็บง็้จ้จๆ
- ้จ้จ่ด่ดฃไบบ๏ผ่ฎพ็ฝฎ้จ้จ่ด่ดฃไบบ
- ๆๅบๆงๅถ๏ผ่ชๅฎไน้จ้จๆพ็คบ้กบๅบ
- ๆฐๆฎๆ้๏ผๅบไบ้จ้จ็ๆฐๆฎ้็ฆป
- ไบบๅ็ป่ฎก๏ผ้จ้จไบบๅๆฐ้็ป่ฎก
๐ผ ๅฒไฝ็ฎก็
ๅฒไฝไฝ็ณป็ฎก็๏ผ
- ๅฒไฝๅฎไน๏ผๅฒไฝๅ็งฐใ็ผ็ ใๆๅบ
- ็ถๆ็ฎก็๏ผๅฏ็จ/ๅ็จๅฒไฝ
- ไบบๅๅ ณ่๏ผๆฅ็ๅฒไฝไธ็ๆๆไบบๅ
๐ ๅญๅ ธ็ฎก็
็ณป็ปๆฐๆฎๅญๅ ธ็ปไธ็ฎก็๏ผ
- ๅญๅ ธ็ฑปๅ๏ผๅฎไนๅญๅ ธๅ็ฑป๏ผๅฆ๏ผ็จๆท็ถๆใๆงๅซ็ญ๏ผ
- ๅญๅ ธๆฐๆฎ๏ผ็ปดๆคๅ ทไฝ็ๅญๅ ธ้กน
- ็ผๅญๆฏๆ๏ผๅญๅ ธๆฐๆฎ่ชๅจ็ผๅญ๏ผๆๅๆง่ฝ
- ๅ็ซฏไฝฟ็จ๏ผๅ็ซฏ็ปไธ่ฐ็จๅญๅ ธๆฅๅฃ
โ๏ธ ๅๆฐ้ ็ฝฎ
็ณป็ปๅๆฐๅจๆ้ ็ฝฎ๏ผ
- ้ ็ฝฎ้กน็ฎก็๏ผๆฐๅขใ็ผ่พใๅ ้ค้ ็ฝฎ้กน
- ้ ็ฝฎๅ็ฑป๏ผ็ณป็ป้ ็ฝฎใไธๅก้ ็ฝฎ็ญ
- ็ผๅญๅทๆฐ๏ผ้ ็ฝฎๅๆด่ชๅจๅทๆฐ็ผๅญ
- ้ ็ฝฎๆ ก้ช๏ผๆฏๆ้ ็ฝฎๅผๆ ผๅผ้ช่ฏ
๐ข ้็ฅๅ ฌๅ
็ณป็ปๅ ฌๅๅๅธไธ็ฎก็๏ผ
- ๅ ฌๅๅๅธ๏ผๅฏๆๆฌ็ผ่พๅจ๏ผๆฏๆๅพๆๆททๆ
- ๅ ฌๅ็ฑปๅ๏ผ้็ฅใๅ ฌๅใ็ณป็ปๆถๆฏ
- ๅๅธๆงๅถ๏ผ็ซๅณๅๅธใๅฎๆถๅๅธ
- ้ ่ฏป็ถๆ๏ผๅทฒ่ฏป/ๆช่ฏป็ถๆ่ท่ธช
2๏ธโฃ ็ณป็ป็ๆงๆจกๅ
๐ฅ ๅจ็บฟ็จๆท
ๅฎๆถ็ๆงๅจ็บฟ็จๆท็ถๆ๏ผ
- ๅจ็บฟๅ่กจ๏ผๆพ็คบๅฝๅๆๆๅจ็บฟ็จๆท
- ็จๆทไฟกๆฏ๏ผ็จๆทๅใIP ๅฐๅใ็ปๅฝๆถ้ดใๆต่งๅจ
- ๅผบๅถไธ็บฟ๏ผ็ฎก็ๅๅฏๅผบๅถ็จๆทไธ็บฟ
- ไผ่ฏ็ฎก็๏ผๆฅ็็จๆทไผ่ฏไฟกๆฏ
- ๅฎๆถ็ป่ฎก๏ผๅจ็บฟ็จๆทๆฐ้็ป่ฎก
๐ ๆไฝๆฅๅฟ
ๅฎๆด็ๆไฝๅฎก่ฎก็ณป็ป๏ผ
- ่ชๅจ่ฎฐๅฝ๏ผ้่ฟ่ฃ ้ฅฐๅจ่ชๅจ่ฎฐๅฝๆไฝ
- ่ฏฆ็ปไฟกๆฏ๏ผๆไฝไบบใๆไฝๆถ้ดใๆไฝ็ฑปๅใ่ฏทๆฑๅๆฐใๅๅบ็ปๆ
- ๅผๅธธๆ่ท๏ผ่ชๅจ่ฎฐๅฝๅผๅธธๆไฝๅ้่ฏฏๅ ๆ
- ๆกไปถๆฅ่ฏข๏ผๆ็จๆทใๆถ้ดใๆจกๅใๆไฝ็ฑปๅๆฅ่ฏข
- ๆฐๆฎๅฏผๅบ๏ผๅฏผๅบๆฅๅฟ็จไบๅฎก่ฎก
๐ ็ปๅฝๆฅๅฟ
็ปๅฝๅฎๅ จๅฎก่ฎก๏ผ
- ็ปๅฝ่ฎฐๅฝ๏ผๆๅ/ๅคฑ่ดฅ็็ปๅฝ่ฎฐๅฝ
- ๅฎๅ จไฟกๆฏ๏ผIP ๅฐๅใๅฐ็ไฝ็ฝฎใๆต่งๅจใๆไฝ็ณป็ป
- ๅผๅธธๆฃๆต๏ผๅผๅธธ็ปๅฝ่กไธบๆ้
- ็ป่ฎกๅๆ๏ผ็ปๅฝๆถๆฎตๅๆใๅฐๅๅๆ
โฐ ๅฎๆถไปปๅก
็ตๆดป็ไปปๅก่ฐๅบฆ็ณป็ป๏ผ
- Cron ่กจ่พพๅผ๏ผๆฏๆๆ ๅ Cron ่กจ่พพๅผ
- ไปปๅก็ฎก็๏ผๅฏๅจใๅๆญขใ็ซๅณๆง่ก
- ๆง่กๆฅๅฟ๏ผไปปๅกๆง่กๅๅฒใๆๅ/ๅคฑ่ดฅ่ฎฐๅฝ
- ๅนถๅๆงๅถ๏ผไปปๅกๅนถๅๆง่กๆงๅถ
- ่ถ ๆถ่ฎพ็ฝฎ๏ผไปปๅกๆง่ก่ถ ๆถๆถ้ด่ฎพ็ฝฎ
- ้่ฏฏ้่ฏ๏ผๅคฑ่ดฅ่ชๅจ้่ฏๆบๅถ
๐ฅ๏ธ ็ณป็ป็ๆง
ๆๅกๅจ่ฟ่ก็ถๆ็ๆง๏ผ
- CPU ็ๆง๏ผCPU ไฝฟ็จ็ใๆ ธๅฟๆฐ
- ๅ ๅญ็ๆง๏ผๅ ๅญไฝฟ็จๆ ๅตใJVM ไฟกๆฏ
- ็ฃ็็ๆง๏ผ็ฃ็ไฝฟ็จ็ใ่ฏปๅ้ๅบฆ
- ็ฝ็ป็ๆง๏ผ็ฝ็ปๆต้็ป่ฎก
- ่ฟ็จไฟกๆฏ๏ผ่ฟ็จ PIDใ่ฟ่กๆถ้ฟ
๐ ๅฅๅบทๆฃๆฅ
K8s ๅๅฅฝ็ๅฅๅบทๆฃๆฅ๏ผ
- Liveness ๆข้๏ผๅบ็จๅญๆดปๆฃๆฅ
- Readiness ๆข้๏ผๅบ็จๅฐฑ็ปชๆฃๆฅ
- ๆฐๆฎๅบๆฃๆฅ๏ผPostgreSQL ่ฟๆฅ็ถๆ
- Redis ๆฃๆฅ๏ผRedis ่ฟๆฅ็ถๆ
- ็ฃ็ๆฃๆฅ๏ผ็ฃ็็ฉบ้ดๆฃๆฅ
- ๅ ๅญๆฃๆฅ๏ผๅ ๅญไฝฟ็จๆฃๆฅ
- Prometheus ๆๆ ๏ผๆด้ฒ
/api/metrics็ซฏ็น
๐ ๆไปถไธไผ
ๅคๅญๅจๆฏๆ็ๆไปถ็ฎก็๏ผ
- ๆฌๅฐๅญๅจ๏ผๅญๅจๅฐๆๅกๅจๆฌๅฐ
- ้ฟ้ไบ OSS๏ผๅญๅจๅฐ้ฟ้ไบๅฏน่ฑกๅญๅจ
- ไธ็ไบ๏ผๅญๅจๅฐไธ็ไบ
- MinIO๏ผ็งๆๅๅฏน่ฑกๅญๅจ
- ๆไปถ้ข่ง๏ผๅพ็ใPDF ็ญๅจ็บฟ้ข่ง
- ็ผฉ็ฅๅพ๏ผ่ชๅจ็ๆๅพ็็ผฉ็ฅๅพ
3๏ธโฃ ๅค็งๆท็ฎก็ๆจกๅ
๐๏ธ ็งๆท็ฎก็
ๅฎๆด็ SaaS ็งๆท็ฎก็๏ผ
- ็งๆท CRUD๏ผๆฐๅขใ็ผ่พใๅ ้ค็งๆท
- ็งๆทไฟกๆฏ๏ผ็งๆทๅ็งฐใ่็ณปไบบใๅฐๆๆถ้ด
- ๅฅ้ค็ปๅฎ๏ผไธบ็งๆทๅ้ ๅ่ฝๅฅ้ค
- ็ถๆ็ฎก็๏ผๅฏ็จใๅ็จใ่ฟๆๆงๅถ
- ๆฐๆฎ้็ฆป๏ผ่ชๅจ็็งๆทๆฐๆฎ้็ฆป
- ๅฎน้้ๅถ๏ผ็จๆทๆฐใๅญๅจ็ฉบ้ด้ๅถ
๐ฆ ็งๆทๅฅ้ค
็ตๆดป็ๅฅ้คไฝ็ณป๏ผ
- ๅฅ้คๅฎไน๏ผๅบ็ก็ใๆ ๅ็ใไผไธ็
- ๅ่ฝๆ้๏ผ่ๅๆ้ๆๅฅ้คๅ้
- ่ตๆบ้ๅถ๏ผ็จๆทๆฐใๅญๅจ็ฉบ้ด้ๅถ
- ๅฅ้คๅ็บง๏ผๆฏๆๅฅ้คๅจ็บฟๅ็บง
๐ ๆฐๆฎ้็ฆป
ๅฎๅ จ็ๅค็งๆทๆฐๆฎ้็ฆป๏ผ
- ่ชๅจ่ฟๆปค๏ผๆฐๆฎๅบๆฅ่ฏข่ชๅจๆ็งๆท่ฟๆปค
- ่ทจ็งๆทๆฅ่ฏข๏ผ่ถ ็บง็ฎก็ๅๅฏๆฅ่ฏขๆๆ็งๆท
- ็งๆทๅๆข๏ผๆฏๆๅๆขๆฅ็ไธๅ็งๆทๆฐๆฎ
- ๆฐๆฎ่ฟ็งป๏ผ็งๆทๆฐๆฎๅฏผๅ ฅๅฏผๅบ
4๏ธโฃ ๆผ็คบ่ดฆๆท็ณป็ป
ไธไธบไบงๅๆผ็คบ่ฎพ่ฎก็ๅฎๅ จๆบๅถ๏ผ
- ๅช่ฏปๆ้๏ผ52 ไธชๆฅ่ฏขๆ้๏ผๅฏๆฅ็ๆๆๆจกๅ
- ๅๆไฝๆฆๆช๏ผ่ชๅจๆฆๆชๆๆ POST/PUT/DELETE/PATCH ่ฏทๆฑ
- ๅๅฅฝๆ็คบ๏ผๆไฝ่ขซๆฆๆชๆถ็ปๅบๅๅฅฝๆ็คบ
- ็ตๆดป้ ็ฝฎ๏ผๅบไบ RBAC ๅฏ้ๆถ่ฐๆดๆ้่ๅด
- ๆผ็คบ้็ฝฎ๏ผๅฎๆถ้็ฝฎๆผ็คบๆฐๆฎ๏ผๅฏ้๏ผ
๐ ๅฟซ้ๅผๅง
็ฏๅข่ฆๆฑ
- Node.js >= 20.19.0
- PostgreSQL >= 14
- Redis >= 7
- pnpm >= 8.0
ๅฎ่ฃ ๆญฅ้ชค
1. ๅ ้้กน็ฎ
git clone https://github.com/your-repo/nest-admin-soybean.git
cd nest-admin-soybean
2. ๅ็ซฏ้ ็ฝฎ
cd server
pnpm install
# ็ๆ RSA ๅฏ้ฅๅฏน๏ผ็จไบๅ ๅฏ๏ผ
pnpm generate:keys
# ้
็ฝฎๆฐๆฎๅบ่ฟๆฅ
# ็ผ่พ src/config/index.ts ไธญ็ๆฐๆฎๅบ้
็ฝฎ
# ๅๅงๅๆฐๆฎๅบ
pnpm prisma:seed
3. ๅ็ซฏ้ ็ฝฎ
cd admin-naive-ui
pnpm install
# ้
็ฝฎๅ็ซฏๆฅๅฃๅฐๅ
# ็ผ่พ .env.development ๆไปถ
4. ๅฏๅจ้กน็ฎ
# ๅฏๅจๅ็ซฏ (8080็ซฏๅฃ)
cd server
pnpm start:dev
# ๅฏๅจๅ็ซฏ (9527็ซฏๅฃ)
cd admin-naive-ui
pnpm dev
5. ่ฎฟ้ฎ็ณป็ป
- ๅ็ซฏๅฐๅ๏ผhttp://localhost:9527
- ๅ็ซฏๆฅๅฃ๏ผhttp://localhost:8080/api
- API ๆๆกฃ๏ผhttp://localhost:8080/api-docs
้ป่ฎค่ดฆๅท๏ผ
- ่ถ ็บง็ฎก็ๅ๏ผadmin / admin123 (็งๆท 000000)
- ๆผ็คบ่ดฆๆท๏ผdemo / demo123 (็งๆท 000000)
๐ช ๆๆฏไบฎ็น่ฏฆ่งฃ
1. ๅค็งๆทๅฎ็ฐๅ็
ๆ ธๅฟๆ่ทฏ๏ผ้่ฟ Prisma Extension ๅจ ORM ๅฑ้ขๅฎ็ฐ้ๆ็็งๆท่ฟๆปคใ
// tenant.extension.ts
export function tenantExtension(tenantId: string) {
return Prisma.defineExtension({
query: {
// ๅฏนๆๆๆจกๅ็ๆฅ่ฏข่ชๅจๆทปๅ ็งๆท่ฟๆปค
$allModels: {
async findMany({ args, query }) {
args.where = { ...args.where, tenantId };
return query(args);
},
// ... findUnique, create, update, delete ๅ็
}
}
});
}
// prisma.service.ts
get client() {
const tenantId = TenantContext.getTenantId();
if (!tenantId) return this._client;
return this._client.$extends(tenantExtension(tenantId));
}
ไผๅฟ๏ผ
- ไธๅกไปฃ็ ๆ ้ๅ ณๅฟ็งๆท้ป่พ
- ้ฟๅ ๅฟ่ฎฐๆทปๅ ็งๆทๆกไปถๅฏผ่ด็ๆฐๆฎๆณ้ฒ
- ็ปไธ็ฎก็๏ผๆไบ็ปดๆค
2. ่ฏทๆฑๅ ๅฏ็ๅฎ็ฐ
ๅ็ซฏๅ ๅฏ๏ผ
// encryption.ts
export function encryptRequest(data: any) {
// 1. ็ๆ้ๆบ AES ๅฏ้ฅ
const aesKey = CryptoJS.lib.WordArray.random(16);
// 2. AES ๅ ๅฏๆฐๆฎ
const encryptedData = CryptoJS.AES.encrypt(
JSON.stringify(data),
aesKey,
{ mode: CryptoJS.mode.CBC }
).toString();
// 3. RSA ๅ ๅฏ AES ๅฏ้ฅ
const encryptedKey = rsaEncrypt(aesKey.toString(), serverPublicKey);
return { encryptedKey, encryptedData };
}
ๅ็ซฏ่งฃๅฏ๏ผ
// decrypt.interceptor.ts
@Injectable()
export class DecryptInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest();
if (request.headers['x-encrypted'] === 'true') {
const { encryptedKey, encryptedData } = request.body;
// 1. RSA ่งฃๅฏ AES ๅฏ้ฅ
const aesKey = rsaDecrypt(encryptedKey, privateKey);
// 2. AES ่งฃๅฏๆฐๆฎ
const decryptedData = aesDecrypt(encryptedData, aesKey);
// 3. ๆฟๆข body
request.body = JSON.parse(decryptedData);
}
return next.handle();
}
}
3. ๆ้็ณป็ป็่ฎพ่ฎก
้็จ่ฃ ้ฅฐๅจ + ๅฎๅซ็็ปๅๆจกๅผ๏ผ
// permission.guard.ts
@Injectable()
export class PermissionGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const requiredPermission = this.reflector.get(
'permission',
context.getHandler()
);
if (!requiredPermission) return true;
const user = context.switchToHttp().getRequest().user;
return user.permissions.includes(requiredPermission);
}
}
// ไฝฟ็จ
@RequirePermission('system:user:edit')
@Put(':id')
updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto) {
return this.userService.update(id, dto);
}
ๆ้ๆฐๆฎ็ปๆ๏ผ
// ๆ้ๆ ่ฏ๏ผๆจกๅ:ๅ่ฝ:ๆไฝ
'system:user:add' // ๆทปๅ ็จๆท
'system:user:edit' // ็ผ่พ็จๆท
'system:user:delete' // ๅ ้ค็จๆท
'system:user:query' // ๆฅ่ฏข็จๆท
4. ๆฅๅฟ็ณป็ป็ไผๅ
่ชๅจๆฅๅฟๆถ้๏ผ
// logging.interceptor.ts
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
constructor(private logger: Logger) {}
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest();
const startTime = Date.now();
return next.handle().pipe(
tap(() => {
const duration = Date.now() - startTime;
this.logger.info({
requestId: request.id,
tenantId: request.tenantId,
username: request.user?.username,
method: request.method,
url: request.url,
statusCode: context.switchToHttp().getResponse().statusCode,
duration,
});
})
);
}
}
ๆๆๅญๆฎต่ฑๆ๏ผ
// ่ชๅจ้่ๆๆๅญๆฎต
const sensitiveFields = ['password', 'token', 'secret'];
this.logger.info(redactSensitive(data, sensitiveFields));
๐จ ๅ็ซฏ็น่ฒ
1. ๆไปถ่ทฏ็ฑ็ณป็ป
ไฝฟ็จ @elegant-router/vue ๅฎ็ฐๅบไบๆไปถ็่ทฏ็ฑ๏ผ
src/views/
โโโ system/
โ โโโ user/
โ โ โโโ index.vue โ /system/user
โ โโโ role/
โ โ โโโ index.vue โ /system/role
โ โโโ menu/
โ โโโ index.vue โ /system/menu
่ชๅจ็ๆ่ทฏ็ฑ๏ผ
pnpm gen-route
2. ๅๅญๅ CSS
ไฝฟ็จ UnoCSS๏ผๆฏๆ Tailwind ้ฃๆ ผ๏ผ
<template>
<div class="flex items-center justify-between p-4 bg-white dark:bg-dark">
<span class="text-lg font-bold">็จๆท็ฎก็</span>
<n-button type="primary">ๆทปๅ ็จๆท</n-button>
</div>
</template>
3. ็ถๆ็ฎก็
Pinia setup ่ฏญๆณ๏ผ
// useAuthStore.ts
export const useAuthStore = defineStore('auth', () => {
const token = ref(getToken());
const userInfo = ref<UserInfo | null>(null);
async function login(credentials: LoginDto) {
const { token: newToken, user } = await api.login(credentials);
token.value = newToken;
userInfo.value = user;
setToken(newToken);
}
return { token, userInfo, login };
});
4. ่ฏทๆฑๅฐ่ฃ
็ปไธ็ Axios ๅฐ่ฃ ๏ผๆฏๆ่ชๅจๅ ๅฏ๏ผ
// api.ts
export function fetchUserList(params: UserQueryDto) {
return request<PageResult<User>>({
url: '/system/user',
method: 'GET',
params
});
}
export function createUser(data: CreateUserDto) {
return request({
url: '/system/user',
method: 'POST',
data,
encrypt: true // ่ชๅจๅ ๅฏ
});
}
๐ฎ ๆชๆฅ่งๅ
- ๅพฎๆๅกๆถๆ๏ผๆๅไธบ็ฌ็ซ็ๅพฎๆๅก
- ๆถๆฏ้ๅ๏ผ้ๆ RabbitMQ/Kafka
- ๅๅธๅผ่ฟฝ่ธช๏ผๆฅๅ ฅ OpenTelemetry
- GraphQL API๏ผๆไพ GraphQL ๆฅๅฃ
- ็งปๅจ็ซฏ๏ผๅผๅ้ ๅฅ็็งปๅจๅบ็จ
- ไฝไปฃ็ ๅนณๅฐ๏ผๅฏ่งๅ่กจๅ่ฎพ่ฎกๅจ
- ๆดๅคๆฐๆฎๅบ๏ผๆฏๆ MySQLใMongoDB
- ไบๅ็๏ผK8s Helm Chart
ๅฆๆ่งๅพไธ้๏ผๆฌข่ฟ Star โญ๏ธ๏ผgithub.com/linlingqin7โฆ
#NestJS #Vue3 #ๅๅฐ็ฎก็็ณป็ป #ๅ จๆ ๅผๅ #ๅผๆบ้กน็ฎ