feat: M4-09 — compliance & safety module (policies, agreements, filings, data requests)
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 42s

- Add PrivacyPolicy, UserAgreement, FilingRecord, DataExportRequest Prisma models
- ComplianceController: privacy policies, user agreements, filings, deletion/export requests
- AAPI: /admin-api/compliance/* (6 resource groups)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
WangDL 2026-05-24 18:19:32 +08:00
parent cefc4d51c9
commit c4089129c0
4 changed files with 150 additions and 0 deletions

View File

@ -1468,3 +1468,53 @@ model ReleaseChecklist {
@@index([version])
}
model PrivacyPolicy {
id String @id @default(cuid())
version String @db.VarChar(50)
title String @db.VarChar(255)
content String @db.Text
effectiveAt DateTime
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([version])
}
model UserAgreement {
id String @id @default(cuid())
version String @db.VarChar(50)
title String @db.VarChar(255)
content String @db.Text
effectiveAt DateTime
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([version])
}
model FilingRecord {
id String @id @default(cuid())
type String @db.VarChar(64)
title String @db.VarChar(255)
filePath String? @db.VarChar(500)
status String @default("pending") @db.VarChar(16)
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model DataExportRequest {
id String @id @default(cuid())
userId String
status String @default("pending") @db.VarChar(16)
filePath String? @db.VarChar(500)
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
@@index([status])
}

View File

@ -57,6 +57,7 @@ import { ReportingModule } from './modules/reporting/reporting.module';
import { ProjectCenterModule } from './modules/project-center/project-center.module';
import { HermesAgentModule } from './modules/hermes-agent/hermes-agent.module';
import { ReleaseModule } from './modules/release/release.module';
import { ComplianceModule } from './modules/compliance/compliance.module';
import { JwtAuthGuard } from './common/guards/jwt-auth.guard';
import { RolesGuard } from './common/guards/roles.guard';
@ -159,6 +160,7 @@ import appleConfig from './config/apple.config';
ProjectCenterModule,
HermesAgentModule,
ReleaseModule,
ComplianceModule,
],
providers: [
{ provide: APP_GUARD, useClass: RateLimitGuard },

View File

@ -0,0 +1,91 @@
import { Controller, Get, Post, Patch, Param, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
@ApiTags('admin-compliance')
@ApiBearerAuth()
@Controller('admin-api/compliance')
@UseGuards(AdminAuthGuard, AdminRolesGuard)
export class ComplianceController {
constructor(private readonly prisma: PrismaService) {}
// ═══ Privacy Policy ═══
@Get('privacy-policies')
@ApiOperation({ summary: '隐私政策列表' })
async listPrivacyPolicies() {
return this.prisma.privacyPolicy.findMany({ orderBy: { createdAt: 'desc' } });
}
@Post('privacy-policies')
@ApiOperation({ summary: '创建隐私政策版本' })
async createPrivacyPolicy(@Body() dto: { version: string; title: string; content: string; effectiveAt: string }) {
return this.prisma.privacyPolicy.create({ data: { ...dto, effectiveAt: new Date(dto.effectiveAt) } });
}
@Patch('privacy-policies/:id')
@ApiOperation({ summary: '更新隐私政策' })
async updatePrivacyPolicy(@Param('id') id: string, @Body() dto: Record<string, any>) {
return this.prisma.privacyPolicy.update({ where: { id }, data: dto });
}
// ═══ User Agreement ═══
@Get('user-agreements')
@ApiOperation({ summary: '用户协议列表' })
async listUserAgreements() {
return this.prisma.userAgreement.findMany({ orderBy: { createdAt: 'desc' } });
}
@Post('user-agreements')
@ApiOperation({ summary: '创建用户协议版本' })
async createUserAgreement(@Body() dto: { version: string; title: string; content: string; effectiveAt: string }) {
return this.prisma.userAgreement.create({ data: { ...dto, effectiveAt: new Date(dto.effectiveAt) } });
}
// ═══ Filing Records ═══
@Get('filings')
@ApiOperation({ summary: '备案台账列表' })
async listFilings() {
return this.prisma.filingRecord.findMany({ orderBy: { createdAt: 'desc' } });
}
@Post('filings')
@ApiOperation({ summary: '创建备案记录' })
async createFiling(@Body() dto: { type: string; title: string; notes?: string }) {
return this.prisma.filingRecord.create({ data: dto });
}
// ═══ Data Deletion Requests ═══
@Get('deletion-requests')
@ApiOperation({ summary: '用户数据删除请求' })
async listDeletionRequests() {
return this.prisma.accountDeletionRequest.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
}
@Post('deletion-requests/:id/approve')
@ApiOperation({ summary: '批准删除请求' })
async approveDeletion(@Param('id') id: string) {
return this.prisma.accountDeletionRequest.update({ where: { id }, data: { status: 'APPROVED', reviewedAt: new Date() } });
}
// ═══ Data Export Requests ═══
@Get('export-requests')
@ApiOperation({ summary: '用户数据导出请求' })
async listExportRequests() {
return this.prisma.dataExportRequest.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
}
// ═══ Security Events ═══
@Get('security-events')
@ApiOperation({ summary: '安全事件列表' })
async listSecurityEvents() {
return this.prisma.securityEvent.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
}
}

View File

@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { ComplianceController } from './compliance.controller';
@Module({
controllers: [ComplianceController],
})
export class ComplianceModule {}