feat: add invitations management and import wizard; enhance audit logging and member detail fetching
Some checks failed
Workflow / ʦ TypeScript (push) Failing after 4m53s
Workflow / ⚫️ Test (push) Has been skipped

This commit is contained in:
T. Zehetbauer
2026-04-01 19:02:55 +02:00
parent 080ec1cb47
commit db4e19c3af
10 changed files with 1847 additions and 104 deletions

View File

@@ -172,3 +172,102 @@ export const lockRecord = authActionClient
return { success: true, data: record };
});
export const bulkImportRecords = authActionClient
.inputSchema(
z.object({
moduleId: z.string().uuid(),
accountId: z.string().uuid(),
records: z.array(z.record(z.string(), z.unknown())).min(1).max(1000),
dryRun: z.boolean().default(false),
}),
)
.action(async ({ parsedInput: input, ctx }) => {
const client = getSupabaseServerClient();
const logger = await getLogger();
const api = createModuleBuilderApi(client);
const userId = ctx.user.id;
const moduleWithFields = await api.modules.getModuleWithFields(
input.moduleId,
);
if (!moduleWithFields) {
throw new Error('Module not found');
}
const { fields } = moduleWithFields;
const errors: Array<{ row: number; field: string; message: string }> = [];
const validRows: Array<Record<string, unknown>> = [];
for (let i = 0; i < input.records.length; i++) {
const row = input.records[i]!;
const validation = validateRecordData(
row,
fields as Parameters<typeof validateRecordData>[1],
);
if (!validation.success) {
for (const err of validation.errors) {
errors.push({ row: i + 1, field: err.field, message: err.message });
}
} else {
validRows.push(row);
}
}
if (input.dryRun) {
return {
success: true,
data: {
totalRows: input.records.length,
validRows: validRows.length,
errorCount: errors.length,
errors: errors.slice(0, 50),
},
};
}
if (errors.length > 0) {
return {
success: false,
error: `${errors.length} Validierungsfehler in ${new Set(errors.map((e) => e.row)).size} Zeilen`,
validationErrors: errors.slice(0, 50).map((e) => ({
field: `Zeile ${e.row}: ${e.field}`,
message: e.message,
})),
};
}
logger.info(
{
name: 'records.bulkImport',
moduleId: input.moduleId,
count: validRows.length,
},
'Bulk importing records...',
);
const insertData = validRows.map((row) => ({
module_id: input.moduleId,
account_id: input.accountId,
data: row as any,
status: 'active' as const,
created_by: userId,
updated_by: userId,
}));
const { error } = await client.from('module_records').insert(insertData);
if (error) throw error;
logger.info(
{ name: 'records.bulkImport', count: validRows.length },
'Bulk import complete',
);
return {
success: true,
data: { imported: validRows.length },
};
});