task-d.7.11

This commit is contained in:
phaichayon
2026-07-03 14:46:42 +07:00
parent 9c8d6a0d6d
commit 15c56efc8b
20 changed files with 1790 additions and 5983 deletions

View File

@@ -0,0 +1,60 @@
import { NextRequest, NextResponse } from 'next/server';
import { previewSetupCsvImport } from '@/features/setup/server/csv-preview.service';
import {
assertBootstrapRequiredFiles,
assertBootstrapSetupAvailable,
assertBootstrapToken,
BOOTSTRAP_ACTOR_ID,
BootstrapSetupError,
setupStepStatusFromPreview,
toSerializableRecord
} from '@/features/setup/server/setup-bootstrap.service';
import { saveSetupStep, startSetupRun } from '@/features/setup/server/setup-state.service';
function isFile(value: FormDataEntryValue): value is File {
return typeof value === 'object' && 'arrayBuffer' in value && 'name' in value;
}
export async function POST(request: NextRequest) {
try {
await assertBootstrapSetupAvailable();
const formData = await request.formData();
assertBootstrapToken(String(formData.get('bootstrapToken') ?? request.headers.get('x-bootstrap-setup-token') ?? ''));
const uploadedFiles = Array.from(formData.values()).filter(isFile);
if (uploadedFiles.length === 0) {
return NextResponse.json({ message: 'Upload at least one setup CSV file using multipart/form-data.' }, { status: 400 });
}
const files = await Promise.all(
uploadedFiles.map(async (file) => ({
fileName: file.name,
bytes: new Uint8Array(await file.arrayBuffer())
}))
);
assertBootstrapRequiredFiles(files);
await startSetupRun({ actorId: BOOTSTRAP_ACTOR_ID, mode: 'production', targetOrganizationId: null });
const preview = await previewSetupCsvImport(files);
await saveSetupStep({
stepKey: 'csv_preview',
status: setupStepStatusFromPreview(preview),
inputHash: preview.previewHash,
output: toSerializableRecord(preview),
errors: preview.files.flatMap((file) => file.errors),
warnings: preview.files.flatMap((file) => file.warnings)
});
return NextResponse.json(preview, { status: preview.summary.error > 0 ? 400 : 200 });
} catch (error) {
if (error instanceof BootstrapSetupError) {
return NextResponse.json({ message: error.message, details: error.details }, { status: error.status });
}
return NextResponse.json({ message: 'Unable preview bootstrap setup CSV import' }, { status: 500 });
}
}