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:
@@ -27,6 +27,17 @@ export const createBerthSchema = z.object({
|
||||
|
||||
export type CreateBerthInput = z.infer<typeof createBerthSchema>;
|
||||
|
||||
// ─── Bulk Add Berths ─────────────────────────────────────────────────────────
|
||||
|
||||
export const bulkAddBerthsSchema = z.object({
|
||||
/** Per-row create payloads. Each row must carry a unique mooringNumber;
|
||||
* the service rejects with ConflictError on first duplicate (either
|
||||
* within the input array OR against an existing port row). */
|
||||
berths: z.array(createBerthSchema).min(1).max(500),
|
||||
});
|
||||
|
||||
export type BulkAddBerthsInput = z.infer<typeof bulkAddBerthsSchema>;
|
||||
|
||||
// ─── Update Berth ─────────────────────────────────────────────────────────────
|
||||
|
||||
export const updateBerthSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user