Add user settings, audit log, berth CRUD, and missing endpoints

- PATCH /api/v1/me: self-service profile update (name, phone, timezone)
- User settings page with profile editor + notification preferences
- Audit log API with filtering (entity, action, user, date range)
- Audit log page with search, entity type, and action filters
- Berth create/delete: POST /api/v1/berths + DELETE /api/v1/berths/[id]
- Client duplicates endpoint: GET /api/v1/clients/duplicates?name=
- Replace settings and audit stub pages with real implementations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-08 19:45:56 -04:00
parent 4fdd9e3207
commit 8df8ded46c
12 changed files with 779 additions and 53 deletions

View File

@@ -3,7 +3,7 @@ import { NextResponse } from 'next/server';
import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseBody } from '@/lib/api/route-helpers';
import { updateBerthSchema } from '@/lib/validators/berths';
import { getBerthById, updateBerth } from '@/lib/services/berths.service';
import { getBerthById, updateBerth, deleteBerth } from '@/lib/services/berths.service';
import { errorResponse } from '@/lib/errors';
// GET /api/v1/berths/[id]
@@ -18,7 +18,7 @@ export const GET = withAuth(
}),
);
// PATCH /api/v1/berths/[id] — update berth fields (no DELETE — import-only)
// PATCH /api/v1/berths/[id]
export const PATCH = withAuth(
withPermission('berths', 'edit', async (req, ctx, params) => {
try {
@@ -35,3 +35,20 @@ export const PATCH = withAuth(
}
}),
);
// DELETE /api/v1/berths/[id]
export const DELETE = withAuth(
withPermission('berths', 'edit', async (_req, ctx, params) => {
try {
await deleteBerth(params.id!, ctx.portId, {
userId: ctx.userId,
portId: ctx.portId,
ipAddress: ctx.ipAddress,
userAgent: ctx.userAgent,
});
return NextResponse.json({ success: true });
} catch (error) {
return errorResponse(error);
}
}),
);

View File

@@ -1,12 +1,11 @@
import { NextResponse } from 'next/server';
import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseQuery } from '@/lib/api/route-helpers';
import { listBerthsSchema } from '@/lib/validators/berths';
import { listBerths } from '@/lib/services/berths.service';
import { parseBody, parseQuery } from '@/lib/api/route-helpers';
import { listBerthsSchema, createBerthSchema } from '@/lib/validators/berths';
import { listBerths, createBerth } from '@/lib/services/berths.service';
import { errorResponse } from '@/lib/errors';
// GET /api/v1/berths — list berths for the current port (no POST — import-only)
export const GET = withAuth(
withPermission('berths', 'view', async (req, ctx) => {
try {
@@ -34,3 +33,20 @@ export const GET = withAuth(
}
}),
);
export const POST = withAuth(
withPermission('berths', 'edit', async (req, ctx) => {
try {
const body = await parseBody(req, createBerthSchema);
const data = await createBerth(ctx.portId, body, {
userId: ctx.userId,
portId: ctx.portId,
ipAddress: ctx.ipAddress,
userAgent: ctx.userAgent,
});
return NextResponse.json({ data }, { status: 201 });
} catch (error) {
return errorResponse(error);
}
}),
);