export type TBackupStatus = 'pending' | 'running' | 'replicating' | 'replicated' | 'ready' | 'failed' | 'restoring' | 'restored'; export type TBackupTrigger = 'manual' | 'scheduled'; export type TBackupResourceType = 'volume' | 'database' | 'objectstorage'; export interface IBackupSnapshotBase { type: TBackupResourceType; snapshotId: string; snapshotName?: string; originalSize: number; storedSize: number; createdAt: number; tags?: Record; } export interface IBackupVolumeSnapshot extends IBackupSnapshotBase { type: 'volume'; volumeName: string; mountPath: string; } export interface IBackupDatabaseSnapshot extends IBackupSnapshotBase { type: 'database'; resourceName: string; databaseName: string; } export interface IBackupObjectStorageSnapshot extends IBackupSnapshotBase { type: 'objectstorage'; resourceName: string; bucketName: string; } export type TBackupSnapshot = IBackupVolumeSnapshot | IBackupDatabaseSnapshot | IBackupObjectStorageSnapshot; export type TBackupReplicationTargetType = 's3' | 'smb' | 'nfs'; export interface IBackupArchiveObject { path: string; size: number; sha256: string; } export interface IBackupArchiveManifest { version: 1; backupId: string; createdAt: number; objects: IBackupArchiveObject[]; totalSize: number; } export interface IBackupReplicationResult { targetType: TBackupReplicationTargetType; targetPath: string; manifestPath: string; manifestSha256: string; objectCount: number; totalSize: number; completedAt: number; } export interface IBackupRestoreEvent { restoredAt: number; status: 'restored' | 'failed'; errorText?: string; } /** * Durable retention hold owned by one isolated restore. An entry is active * while `releasedAt` is absent. Active holds never expire implicitly: * retention may neither claim nor delete the backup until every active hold * has been released after successful scratch-resource and staging cleanup. */ export interface IBackupRestoreHold { restoreId: string; idempotencyKey: string; acquiredAt: number; releasedAt?: number; releaseReason?: string; } export interface IBackupRecord { id: string; serviceId: string; serviceName?: string; clusterId?: string; status: TBackupStatus; trigger: TBackupTrigger; snapshots: TBackupSnapshot[]; replication?: IBackupReplicationResult; /** * Storage tier of the replicated archive: 'cache' = the platform S3 * binding next to cloudly; 'external' = the configured long-term target * (external S3, NFS path, SMB). Offload moves cache -> external and then * deletes the cache copy. */ tier?: 'cache' | 'external'; offloadedAt?: number; createdAt: number; updatedAt: number; completedAt?: number; requestedBy?: string; errorText?: string; restoreHistory?: IBackupRestoreEvent[]; /** * Authoritative isolated-restore holds. Cloudly atomically appends the * active entry with restore creation. Failed archive cleanup must retain * this backup record so hold recovery remains possible. */ restoreHolds?: IBackupRestoreHold[]; tags?: Record; } /** Retention policy understood by containerarchive prune. */ export interface IArchiveRetentionPolicy { keepLast?: number; keepDays?: number; keepWeeks?: number; keepMonths?: number; } export interface IArchivePruneResult { removedSnapshots: number; removedPacks: number; rewrittenPacks: number; freedBytes: number; dryRun: boolean; } /** * JWT-free actor projection persisted with isolated-restore audit data. * Authentication credentials must never be copied into restore records. */ export interface IIsolatedRestoreActor { userId: string; type: 'human' | 'machine' | 'system'; role?: 'admin' | 'user' | 'api' | 'cluster'; } export type TIsolatedRestoreStatus = 'pending' | 'preparing' | 'staging' | 'restoring' | 'verifying' | 'ready' | 'failed' | 'cleanup-pending' | 'cleaning' | 'cleaned' | 'cleanup-failed'; export type TIsolatedRestoreErrorPhase = 'validation' | 'source-backup-hold' | 'preparation' | 'staging' | 'restoring' | 'verifying' | 'cleanup'; /** Append-only structured failure entry for one isolated restore. */ export interface IIsolatedRestoreError { sequence: number; phase: TIsolatedRestoreErrorPhase; code: string; message: string; retryable: boolean; occurredAt: number; } export type TIsolatedRestoreAuditAction = 'created' | 'status-transitioned' | 'source-backup-hold-acquired' | 'cleanup-requested' | 'expired' | 'source-backup-hold-release-requested' | 'source-backup-hold-released'; /** Append-only lifecycle event. `sequence` is strictly increasing per restore. */ export interface IIsolatedRestoreAuditEvent { sequence: number; action: TIsolatedRestoreAuditAction; actor: IIsolatedRestoreActor; occurredAt: number; fromStatus?: TIsolatedRestoreStatus; toStatus?: TIsolatedRestoreStatus; reason?: string; } export interface IIsolatedRestoreVolumeMapping { /** Stable server-generated id used by verification and cleanup progress. */ id: string; type: 'volume'; source: { snapshotId: string; volumeName: string; mountPath: string; }; target: { volumeName: string; mountPath: string; }; } export interface IIsolatedRestoreDatabaseMapping { /** Stable server-generated id used by verification and cleanup progress. */ id: string; type: 'database'; source: { snapshotId: string; resourceName: string; databaseName: string; }; target: { resourceName: string; databaseName: string; }; } export interface IIsolatedRestoreObjectStorageMapping { /** Stable server-generated id used by verification and cleanup progress. */ id: string; type: 'objectstorage'; source: { snapshotId: string; resourceName: string; bucketName: string; }; target: { resourceName: string; bucketName: string; }; } export type TIsolatedRestoreResourceMapping = IIsolatedRestoreVolumeMapping | IIsolatedRestoreDatabaseMapping | IIsolatedRestoreObjectStorageMapping; export type TIsolatedRestoreVerificationStatus = 'pending' | 'running' | 'passed' | 'failed'; export interface IIsolatedRestoreVerificationCheck { /** Stable machine-readable check code. */ code: string; status: 'passed' | 'failed'; message?: string; } export interface IIsolatedRestoreResourceVerification { resourceMappingId: string; resourceType: TBackupResourceType; status: TIsolatedRestoreVerificationStatus; checks: IIsolatedRestoreVerificationCheck[]; checkedAt?: number; } /** Complete verification state returned by the target data plane. */ export interface IIsolatedRestoreVerification { status: TIsolatedRestoreVerificationStatus; results: IIsolatedRestoreResourceVerification[]; startedAt?: number; completedAt?: number; } export type TIsolatedRestoreCleanupTrigger = 'manual' | 'expired' | 'restore-failed' | 'policy'; export type TIsolatedRestoreCleanupProgressStatus = 'pending' | 'running' | 'succeeded' | 'failed'; export interface IIsolatedRestoreResourceCleanupProgress { resourceMappingId: string; resourceType: TBackupResourceType; status: TIsolatedRestoreCleanupProgressStatus; attempts: number; updatedAt?: number; errorCode?: string; errorMessage?: string; } export interface IIsolatedRestoreStagingCleanupProgress { stagingArchiveId: string; status: TIsolatedRestoreCleanupProgressStatus; attempts: number; updatedAt?: number; errorCode?: string; errorMessage?: string; } /** Data-plane cleanup progress shared by public and internal status views. */ export interface IIsolatedRestoreCleanupProgress { resources: IIsolatedRestoreResourceCleanupProgress[]; stagingArchive: IIsolatedRestoreStagingCleanupProgress; } /** * Cleanup metadata. The source-backup hold remains active until every * resource entry and the staging entry report `succeeded`. `cleanup-failed` * is retryable and must not release the hold. */ export interface IIsolatedRestoreCleanup extends IIsolatedRestoreCleanupProgress { trigger: TIsolatedRestoreCleanupTrigger; reason: string; requestedBy: IIsolatedRestoreActor; requestedAt: number; startedAt?: number; completedAt?: number; } export type TIsolatedRestoreSourceBackupHoldStatus = 'acquired' | 'release-pending' | 'released'; /** * Restore-side projection of the authoritative IBackupRecord hold. The hold * is non-expiring and may enter `released` only after exact cleanup success. */ export interface IIsolatedRestoreSourceBackupHold { status: TIsolatedRestoreSourceBackupHoldStatus; acquiredAt: number; releaseRequestedAt?: number; releasedAt?: number; releaseReason?: string; } export type TIsolatedRestoreNodeStatus = 'preparing' | 'prepared' | 'staging' | 'restoring' | 'verifying' | 'ready' | 'failed' | 'cleaning' | 'cleaned' | 'cleanup-failed'; /** * Data-plane state for one exact cluster/node/restore routing key. `revision` * advances after every mutation and is the compare-and-swap value used by * prepare, execute, and cleanup requests. */ export interface IIsolatedRestoreNodeState { restoreId: string; clusterId: string; targetNodeName: string; sourceBackupId: string; sourceServiceId: string; scratchNamespaceId: string; stagingArchiveId: string; revision: number; status: TIsolatedRestoreNodeStatus; completedResourceMappingIds: string[]; verification: IIsolatedRestoreVerification; cleanup?: IIsolatedRestoreCleanupProgress; preparedAt?: number; readyAt?: number; updatedAt: number; lastErrorCode?: string; lastErrorMessage?: string; } /** * Durable control-plane record for a restore into a generated data-plane * scratch namespace. The namespace is not an IService and carries no image, * runtime, route, port, environment, or secret authority. * * `clusterId` and `sourceServiceId` are copied from the authoritative source * backup, never accepted from the caller. `revision` advances monotonically * for optimistic lifecycle updates. A restore execution failure (`failed`) * must proceed through cleanup before its source-backup hold can be released. */ export interface IIsolatedRestoreRecord { /** Server-generated restore id. */ id: string; /** Caller key used to return the same restore after retried creation. */ idempotencyKey: string; revision: number; sourceBackupId: string; sourceServiceId: string; sourceServiceName?: string; clusterId: string; /** Server-generated, non-runnable data-plane namespace. */ scratchNamespaceId: string; /** Server-generated archive namespace, distinct from sourceBackupId. */ stagingArchiveId: string; targetNodeName: string; purpose: string; requestedBy: IIsolatedRestoreActor; status: TIsolatedRestoreStatus; resourceMappings: TIsolatedRestoreResourceMapping[]; verification: IIsolatedRestoreVerification; sourceBackupHold: IIsolatedRestoreSourceBackupHold; createdAt: number; updatedAt: number; expiresAt: number; readyAt?: number; cleanup?: IIsolatedRestoreCleanup; /** Append-only; entries are never replaced when a later phase fails. */ errors: IIsolatedRestoreError[]; /** Append-only lifecycle audit trail. */ auditEvents: IIsolatedRestoreAuditEvent[]; }