from __future__ import annotations from fastapi import APIRouter, Depends from app.api.dependencies import get_export_service from app.core.exceptions import ValidationError from app.schemas.export import ( MetadataExportResponse, MetadataImportRequest, MetadataImportResponse, MetadataRestorePlanResponse, MetadataValidationResponse, ) from app.services.export_service import ExportService from app.services.job_service import JobService router = APIRouter() @router.get("/metadata", response_model=MetadataExportResponse) async def export_metadata(service: ExportService = Depends(get_export_service)) -> MetadataExportResponse: data = await service.export_metadata() exported_at = data.pop("exported_at") return MetadataExportResponse(exported_at=exported_at, data=data) @router.get("/metadata/integrity", response_model=MetadataValidationResponse) async def metadata_integrity(service: ExportService = Depends(get_export_service)) -> MetadataValidationResponse: result = await service.verify_runtime_integrity() return MetadataValidationResponse(ok=result["ok"], issues=result["issues"]) @router.post("/metadata/validate", response_model=MetadataValidationResponse) async def validate_metadata( payload: MetadataImportRequest, service: ExportService = Depends(get_export_service), ) -> MetadataValidationResponse: result = await service.validate_metadata_snapshot(payload.data) return MetadataValidationResponse(ok=result["ok"], issues=result["issues"]) @router.post("/metadata/restore-plan", response_model=MetadataRestorePlanResponse) async def restore_plan( payload: MetadataImportRequest, service: ExportService = Depends(get_export_service), ) -> MetadataRestorePlanResponse: result = await service.build_restore_plan(payload.data) return MetadataRestorePlanResponse( ok=result["ok"], issues=result["issues"], validation_token=result["validation_token"], summary=result["summary"], ) @router.post("/metadata/import", response_model=MetadataImportResponse) async def import_metadata( payload: MetadataImportRequest, service: ExportService = Depends(get_export_service), ) -> MetadataImportResponse: if not payload.confirm_replace: raise ValidationError("Metadata import requires confirm_replace=true.") restore_plan_result = await service.build_restore_plan(payload.data) if not restore_plan_result["ok"]: raise ValidationError("Metadata snapshot is invalid and cannot be imported.") if payload.validation_token != restore_plan_result["validation_token"]: raise ValidationError("Metadata import requires a current validation_token from restore-plan.") imported_tables = await service.import_metadata(payload.data) job_service = JobService(service.session) reconcile_job = await job_service.enqueue_full_reconcile() health_job_count = 0 for backend in await job_service.backend_repository.list_enabled(): await job_service.enqueue_backend_health_check(backend.id) health_job_count += 1 scheduled_jobs = [reconcile_job.kind] + ["check_backend_health"] * health_job_count return MetadataImportResponse(imported_tables=imported_tables, scheduled_jobs=scheduled_jobs)