feat(records): govern lifecycle recovery and transfer evidence

This commit is contained in:
2026-08-06 05:36:18 +02:00
parent f316523a1d
commit df51bb1787
22 changed files with 4954 additions and 66 deletions
+185
View File
@@ -12,6 +12,12 @@ export type FilePlanNode = {
valid_from?: string | null;
valid_to?: string | null;
recorded_at: string;
closed_at?: string | null;
retention_started_at?: string | null;
retention_due_at?: string | null;
retention_rule: Record<string, unknown>;
appraisal_state?: string | null;
appraisal: Record<string, unknown>;
institutional_context: Record<string, unknown>;
};
@@ -99,11 +105,63 @@ export type RecordChronology = {
payload: Record<string, unknown>;
};
export type RecordHold = {
hold_id: string;
record_id: string;
revision: number;
status: string;
reason: string;
authority: string;
scope: Record<string, unknown>;
effective_from: string;
effective_to?: string | null;
released_at?: string | null;
policy_refs: string[];
recorded_at: string;
};
export type RecordDisposition = {
disposition_id: string;
record_id: string;
revision: number;
action: "retain" | "transfer" | "destroy" | "reclassify";
status: string;
reason: string;
subject_revision: number;
subject_sha256: string;
consequence_preview: Record<string, unknown>;
policy_refs: string[];
approval_request_id?: string | null;
proposed_by?: string | null;
reviewed_by?: string | null;
reviewed_at?: string | null;
recorded_at: string;
};
export type RecordTransferPackage = {
package_id: string;
record_id: string;
disposition_id: string;
revision: number;
record_revision: number;
provider_id: string;
profile: string;
status: string;
manifest_sha256: string;
receipt_sha256?: string | null;
external_reference?: string | null;
simulated: boolean;
recorded_at: string;
};
export type RecordDetail = {
record: RecordEntry;
volumes: RecordVolume[];
items: RecordItem[];
chronology: RecordChronology[];
holds: RecordHold[];
dispositions: RecordDisposition[];
transfer_packages: RecordTransferPackage[];
access_explanation: {
decision: string;
reason: string;
@@ -120,6 +178,19 @@ export type RecordSourceProvider = {
resource_types: string[];
};
export type RecordArchiveProvider = {
id: string;
label: string;
profiles: string[];
authority_modes: string[];
healthy: boolean;
checked_at: string;
last_success_at?: string | null;
freshness_seconds?: number | null;
limitations: string[];
simulated: boolean;
};
export function listRecords(
settings: ApiSettings,
options: {
@@ -154,6 +225,24 @@ export function getRecordSources(settings: ApiSettings, signal?: AbortSignal): P
return apiFetch(settings, "/api/v1/records/sources", { signal });
}
export function getRecordArchiveProviders(settings: ApiSettings, signal?: AbortSignal): Promise<{ providers: RecordArchiveProvider[] }> {
return apiFetch(settings, "/api/v1/records/archive-providers", { signal });
}
export function writeFilePlanNode(settings: ApiSettings, payload: Record<string, unknown>): Promise<FilePlanNode> {
return apiFetch(settings, "/api/v1/records/catalog/file-plan", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function writeRecordClass(settings: ApiSettings, payload: Record<string, unknown>): Promise<RecordClass> {
return apiFetch(settings, "/api/v1/records/catalog/classes", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function createRecord(settings: ApiSettings, payload: Record<string, unknown>): Promise<RecordEntry> {
return apiFetch(settings, "/api/v1/records", {
method: "POST",
@@ -182,3 +271,99 @@ export function fileRecordItem(
body: JSON.stringify(payload)
});
}
export function createRecordVolume(
settings: ApiSettings,
recordId: string,
payload: Record<string, unknown>
): Promise<RecordVolume> {
return recordMutation(settings, recordId, "volumes", payload);
}
export function closeRecord(settings: ApiSettings, recordId: string, payload: Record<string, unknown>): Promise<RecordEntry> {
return recordMutation(settings, recordId, "close", payload);
}
export function reopenRecord(settings: ApiSettings, recordId: string, payload: Record<string, unknown>): Promise<RecordEntry> {
return recordMutation(settings, recordId, "reopen", payload);
}
export function appraiseRecord(settings: ApiSettings, recordId: string, payload: Record<string, unknown>): Promise<RecordEntry> {
return recordMutation(settings, recordId, "appraise", payload);
}
export function applyRecordHold(settings: ApiSettings, recordId: string, payload: Record<string, unknown>): Promise<RecordHold> {
return recordMutation(settings, recordId, "holds", payload);
}
export function releaseRecordHold(
settings: ApiSettings,
recordId: string,
holdId: string,
payload: Record<string, unknown>
): Promise<RecordHold> {
return recordMutation(settings, recordId, `holds/${encodeURIComponent(holdId)}/release`, payload);
}
export function proposeRecordDisposition(
settings: ApiSettings,
recordId: string,
payload: Record<string, unknown>
): Promise<RecordDisposition> {
return recordMutation(settings, recordId, "dispositions", payload);
}
export function finalizeRecordDisposition(
settings: ApiSettings,
recordId: string,
dispositionId: string,
payload: Record<string, unknown>
): Promise<{ disposition: RecordDisposition; record: RecordEntry }> {
return recordMutation(settings, recordId, `dispositions/${encodeURIComponent(dispositionId)}/finalize`, payload);
}
export function withdrawRecordDisposition(
settings: ApiSettings,
recordId: string,
dispositionId: string,
payload: Record<string, unknown>
): Promise<RecordDisposition> {
return recordMutation(settings, recordId, `dispositions/${encodeURIComponent(dispositionId)}/withdraw`, payload);
}
export function prepareRecordTransfer(
settings: ApiSettings,
recordId: string,
payload: Record<string, unknown>
): Promise<RecordTransferPackage> {
return recordMutation(settings, recordId, "transfer-packages", payload);
}
export function dispatchRecordTransfer(
settings: ApiSettings,
recordId: string,
packageId: string,
payload: Record<string, unknown>
): Promise<RecordTransferPackage> {
return recordMutation(settings, recordId, `transfer-packages/${encodeURIComponent(packageId)}/dispatch`, payload);
}
export function getRecordRecoveryStatus(
settings: ApiSettings,
recordId: string,
signal?: AbortSignal
): Promise<Record<string, unknown>> {
return apiFetch(settings, `/api/v1/records/${encodeURIComponent(recordId)}/recovery`, { signal });
}
function recordMutation<T>(
settings: ApiSettings,
recordId: string,
path: string,
payload: Record<string, unknown>
): Promise<T> {
return apiFetch(settings, `/api/v1/records/${encodeURIComponent(recordId)}/${path}`, {
method: "POST",
body: JSON.stringify(payload)
});
}