feat(bulk-berths): 2-step wizard for new-port setup
Step 5 per PRE-DEPLOY-PLAN § 1.4.13.
Service: bulkAddBerths(portId, inputs, meta) — input-level dedup
catches in-batch duplicates, then a single SELECT against existing
port rows rejects with ConflictError on first collision. All inserts
in one round-trip; audit log + realtime alert.
Validator: bulkAddBerthsSchema with min(1) max(500) per call.
Route: POST /api/v1/berths/bulk-add gated on berths.create.
Wizard UI (/[portSlug]/admin/berths/bulk-add):
Step 1 — dock letter A-E, range start+end mooring numbers, tenure
default. Generates N empty rows.
Step 2 — editable table with per-row dimensions / pontoon / pricing.
"Apply to all" inputs in the header row copy a value down every
row at once (covers the "every row is 40ft × 15ft at €125k" case
in two clicks). Per-row remove button.
Drag-fill deferred. Server-side mooring uniqueness check is canonical;
client-side dedup is a pre-flight courtesy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
32
src/app/api/v1/berths/bulk-add/route.ts
Normal file
32
src/app/api/v1/berths/bulk-add/route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
import { withAuth, withPermission } from '@/lib/api/helpers';
|
||||
import { parseBody } from '@/lib/api/route-helpers';
|
||||
import { errorResponse } from '@/lib/errors';
|
||||
import { bulkAddBerths } from '@/lib/services/berths.service';
|
||||
import { bulkAddBerthsSchema } from '@/lib/validators/berths';
|
||||
|
||||
/**
|
||||
* POST /api/v1/berths/bulk-add
|
||||
*
|
||||
* Bulk-insert berths for new-port setup. Cap of 500 rows per call;
|
||||
* the service rejects with ConflictError on first duplicate (within
|
||||
* the input array or against existing port rows). Wizard UI lives at
|
||||
* /[portSlug]/admin/berths/bulk-add.
|
||||
*/
|
||||
export const POST = withAuth(
|
||||
withPermission('berths', 'create', async (req, ctx) => {
|
||||
try {
|
||||
const input = await parseBody(req, bulkAddBerthsSchema);
|
||||
const result = await bulkAddBerths(ctx.portId, input.berths, {
|
||||
userId: ctx.userId,
|
||||
portId: ctx.portId,
|
||||
ipAddress: ctx.ipAddress,
|
||||
userAgent: ctx.userAgent,
|
||||
});
|
||||
return NextResponse.json({ data: result });
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
}
|
||||
}),
|
||||
);
|
||||
Reference in New Issue
Block a user