feat(10-05): add SourceConfigDto and TenderQueryDto
- SourceConfigDto: pollIntervalMin (@Min(5) @Max(1440)), isActive - TenderQueryDto: page/limit pagination (copied from DkvHistoryQueryDto) + status filter
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { IsBoolean, IsInt, IsOptional, Max, Min } from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO for reading/updating the singleton `doe-opendata` poll config
|
||||
* (`TenderSourcePollConfig`, `sourceType: 'doe-opendata'`).
|
||||
*
|
||||
* Security:
|
||||
* - T-10-15: pollIntervalMin bounded 5-1440 — same DoS-mitigation floor as
|
||||
* DkvConfigDto.pollIntervalMin (no sub-5-minute polling of the platform-wide
|
||||
* scheduler).
|
||||
*
|
||||
* Note: `pollIntervalMin` is the cron-tick frequency (D-04 default 60) —
|
||||
* NOT the DÖE fetch frequency. The actual upstream HTTP call is gated
|
||||
* separately by the day-cursor check inside TenderIngestionService
|
||||
* (Pitfall A: cron tick frequency != actual-fetch frequency for this
|
||||
* day-granular source).
|
||||
*/
|
||||
export class SourceConfigDto {
|
||||
/**
|
||||
* Cron-tick interval in minutes. Minimum 5 minutes (DoS mitigation, T-10-15).
|
||||
* Maximum 1440 (24h).
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(5)
|
||||
@Max(1440)
|
||||
pollIntervalMin?: number;
|
||||
|
||||
/**
|
||||
* Whether the platform-wide DÖE poll cron job is active.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isActive?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsIn, IsInt, IsOptional, Max, Min } from 'class-validator';
|
||||
|
||||
/**
|
||||
* Query DTO for paginating + filtering the global tender catalog.
|
||||
*
|
||||
* Security:
|
||||
* - T-10-15: pagination bounds (limit @Max(100)) mitigate oversized
|
||||
* result-set DoS — same convention as DkvHistoryQueryDto.
|
||||
*
|
||||
* Used for: GET /modules/tender-radar?page=1&limit=20&status=active
|
||||
*
|
||||
* No region/CPV filters here — rich filtering is Phase 11 (FILTER-*).
|
||||
*/
|
||||
export class TenderQueryDto {
|
||||
/**
|
||||
* Page number (1-based). Defaults to 1 when omitted.
|
||||
* @Type(() => Number) coerces the query-string value to a number before
|
||||
* validation — required because HTTP query params always arrive as strings.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
page?: number;
|
||||
|
||||
/**
|
||||
* Number of records per page. Defaults to 20 when omitted.
|
||||
* T-10-15: bounded integer mitigates oversized result-set DoS.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
@Type(() => Number)
|
||||
limit?: number;
|
||||
|
||||
/**
|
||||
* Status filter. Defaults to active-only at the query layer when omitted.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsIn(['active', 'expired'])
|
||||
status?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user