Data Flows Backend¶
Ce document décrit les flux de données spécifiques au backend. Voir les flux globaux pour la vue d'ensemble.
Flux de requête API¶
Request HTTP
│
▼
┌─────────────────┐
│ Middleware │ Helmet, CORS, Compression
└────────┬────────┘
│
▼
┌─────────────────┐
│ Auth Guard │ JWT validation
└────────┬────────┘
│
▼
┌─────────────────┐
│ Interceptors │ Logging, Transform
└────────┬────────┘
│
▼
┌─────────────────┐
│ Validation │ DTO validation (class-validator)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Controller │ Route handling
└────────┬────────┘
│
▼
┌─────────────────┐
│ Service │ Business logic
└────────┬────────┘
│
▼
┌─────────────────┐
│ Repository │ Data access (TypeORM)
└────────┬────────┘
│
▼
Database
Flux de création document¶
// Controller
@Post()
async create(@Body() dto: CreateDocumentDto, @CurrentUser() user) {
return this.documentsService.create(dto, user.id);
}
// Service
async create(dto: CreateDocumentDto, userId: string) {
// 1. Valider format hash
if (!this.hashService.isValidFormat(dto.hashDoc)) {
throw new BadRequestException('Invalid hash format');
}
// 2. Vérifier unicité hash
const existing = await this.repo.findOne({ hashDoc: dto.hashDoc });
if (existing) {
throw new ConflictException('Document already exists');
}
// 3. Upload vers S3
const s3Key = await this.storageService.upload(dto.encryptedData);
// 4. Créer entrée DB
const document = this.repo.create({
...dto,
ownerId: userId,
s3Key,
});
// 5. Audit log
await this.auditService.log('document.created', { documentId: document.id });
return this.repo.save(document);
}
Flux de certification HSM¶
// CryptoService
async certifyDocument(documentId: string) {
const document = await this.documentsRepo.findOne(documentId);
// 1. Préparer données à signer
const dataToSign = this.prepareSigningData(document);
// 2. Signer avec HSM (PKCS#11)
const signature = await this.hsmService.sign(dataToSign, HSM_KEY_ID);
// 3. Obtenir horodatage TSA
const timestamp = await this.tsaService.getTimestamp(signature);
// 4. Créer preuve composite
const proof = {
hash: document.hashDoc,
signature: signature.toString('base64'),
timestamp: timestamp,
keyId: HSM_KEY_ID,
algorithm: 'RSA-PSS-SHA256',
};
// 5. Sauvegarder preuve
await this.proofsRepo.save({ documentId, proof });
return proof;
}
Flux de vérification RLS¶
// Interceptor appliqué globalement
@Injectable()
export class RlsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest();
const userId = request.user?.id;
// Configurer RLS pour cette requête
return from(
this.dataSource.query(
`SET LOCAL app.current_user_id = '${userId}'`
)
).pipe(
switchMap(() => next.handle())
);
}
}
Gestion des erreurs¶
// Exception filter global
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception instanceof HttpException
? exception.getStatus()
: 500;
const message = exception instanceof HttpException
? exception.message
: 'Internal server error';
// Log sans données sensibles
this.logger.error({
status,
message,
path: ctx.getRequest().url,
// PAS de body, params, ou données utilisateur
});
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
});
}
}