feat(api): GET/POST /api/v1/yachts

Add yacht list + create routes, export RouteHandler type and inner
handlers so tests can invoke them directly with a mock AuthContext.
New tests/helpers/route-tester.ts provides makeMockCtx/makeMockRequest
reusable by subsequent Task 3.x routes.
This commit is contained in:
Matt Ciaccio
2026-04-24 12:35:25 +02:00
parent f743169354
commit a5036c6358
4 changed files with 192 additions and 16 deletions

View File

@@ -3,12 +3,7 @@ import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
import {
portRoleOverrides,
ports,
userPortRoles,
userProfiles,
} from '@/lib/db/schema';
import { portRoleOverrides, ports, userPortRoles, userProfiles } from '@/lib/db/schema';
import { type RolePermissions } from '@/lib/db/schema/users';
import { createAuditLog } from '@/lib/audit';
import { errorResponse } from '@/lib/errors';
@@ -40,7 +35,7 @@ export interface AuthContext {
userAgent: string;
}
type RouteHandler<T = unknown> = (
export type RouteHandler<T = unknown> = (
req: NextRequest,
ctx: AuthContext,
params: Record<string, string>,
@@ -133,10 +128,7 @@ export function withAuth(
if (!profile.isSuperAdmin && portId) {
const portRole = await db.query.userPortRoles.findFirst({
where: and(
eq(userPortRoles.userId, profile.userId),
eq(userPortRoles.portId, portId),
),
where: and(eq(userPortRoles.userId, profile.userId), eq(userPortRoles.portId, portId)),
with: {
role: true,
port: true,
@@ -182,8 +174,7 @@ export function withAuth(
email: session.user.email,
name: session.user.name,
},
ipAddress:
req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown',
ipAddress: req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown',
userAgent: req.headers.get('user-agent') ?? 'unknown',
};
@@ -213,9 +204,7 @@ export function withPermission(
): RouteHandler {
return async (req, ctx, params) => {
if (!ctx.isSuperAdmin) {
const resourcePerms = ctx.permissions?.[resource] as
| Record<string, boolean>
| undefined;
const resourcePerms = ctx.permissions?.[resource] as Record<string, boolean> | undefined;
if (!resourcePerms || !resourcePerms[action]) {
logger.warn({ userId: ctx.userId, resource, action }, 'Permission denied');