feat(10-06): tender-radar-api client + admin source-config settings form
- tender-radar-api.ts: fetchSourceConfig/saveSourceConfig hitting GET/PUT /modules/tender-radar/source-config (Plan 05 endpoint) - SourceConfigForm: load-on-mount, numeric interval (5-1440 min, mirrors backend SourceConfigDto bounds) + isActive toggle, read-only sourceType/ lastIngestedDay display - settings/page.tsx: standard App Router route rendering the form, no module-loader whitelist change needed
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Ausschreibungs-Radar (tender-radar) module API client.
|
||||
* Consumes the /modules/tender-radar/* REST surface built in Plan 05.
|
||||
* All calls use credentials: 'include' for cookie-based auth.
|
||||
*
|
||||
* Security: the DÖE source config carries no secrets (no username/password
|
||||
* field, unlike DkvConfig) — T-10-18 accepts this as low-risk information
|
||||
* disclosure since the config fetch response is auth-free by nature.
|
||||
*/
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// --- Types mirroring the Plan 05 backend contract (TenderSourcePollConfig) ---
|
||||
|
||||
/**
|
||||
* Singleton `doe-opendata` poll config.
|
||||
* `pollIntervalMin` is the cron-tick frequency (D-04 default 60) — NOT the
|
||||
* DÖE fetch frequency, which is gated separately by the day-cursor inside
|
||||
* the backend's TenderIngestionService (day-granular source).
|
||||
*/
|
||||
export interface SourceConfig {
|
||||
/** Fixed slug identifying the source, e.g. 'doe-opendata'. Read-only display field. */
|
||||
sourceType: string;
|
||||
pollIntervalMin: number;
|
||||
isActive: boolean;
|
||||
/** Day-cursor of the last successfully ingested day. Read-only display field. */
|
||||
lastIngestedDay?: string | null;
|
||||
}
|
||||
|
||||
/** Payload accepted by PUT /modules/tender-radar/source-config. */
|
||||
export interface SaveSourceConfigPayload {
|
||||
pollIntervalMin: number;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
// --- API functions ---
|
||||
|
||||
/**
|
||||
* Fetch the current shared DÖE source poll config.
|
||||
* GET /modules/tender-radar/source-config
|
||||
*/
|
||||
export async function fetchSourceConfig(): Promise<SourceConfig> {
|
||||
const res = await fetch(`${API_URL}/modules/tender-radar/source-config`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to fetch tender-radar source config');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the shared DÖE source poll config.
|
||||
* PUT /modules/tender-radar/source-config
|
||||
* Saving live-applies the change to the running scheduler (INGEST-06,
|
||||
* no restart required — see Plan 05).
|
||||
*/
|
||||
export async function saveSourceConfig(
|
||||
payload: SaveSourceConfigPayload,
|
||||
): Promise<SourceConfig> {
|
||||
const res = await fetch(`${API_URL}/modules/tender-radar/source-config`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to save tender-radar source config');
|
||||
return res.json();
|
||||
}
|
||||
Reference in New Issue
Block a user