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
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:
parent
cefc4d51c9
commit
c4089129c0
@ -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])
|
||||
}
|
||||
|
||||
@ -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 },
|
||||
|
||||
91
src/modules/compliance/compliance.controller.ts
Normal file
91
src/modules/compliance/compliance.controller.ts
Normal 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 });
|
||||
}
|
||||
}
|
||||
7
src/modules/compliance/compliance.module.ts
Normal file
7
src/modules/compliance/compliance.module.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ComplianceController } from './compliance.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [ComplianceController],
|
||||
})
|
||||
export class ComplianceModule {}
|
||||
Loading…
x
Reference in New Issue
Block a user