fix: MEDIUM — Cache-Control headers on admin GETs, Open Day past date validation

- Add Cache-Control headers to admin GET endpoints (sections 60s, team 60s, bookings 30s, unread 15s, open-day 60s)
- Validate Open Day date is not in the past on both create (POST) and update (PUT)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 14:19:39 +03:00
parent b1adbbfe3d
commit 5cd23473c8
5 changed files with 26 additions and 5 deletions

View File

@@ -3,7 +3,9 @@ import { getGroupBookings, toggleGroupBookingNotification, deleteGroupBooking }
export async function GET() {
const bookings = getGroupBookings();
return NextResponse.json(bookings);
return NextResponse.json(bookings, {
headers: { "Cache-Control": "private, max-age=30" },
});
}
export async function PUT(request: NextRequest) {

View File

@@ -16,7 +16,9 @@ export async function GET(request: NextRequest) {
if (!event) return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json(event);
}
return NextResponse.json(getOpenDayEvents());
return NextResponse.json(getOpenDayEvents(), {
headers: { "Cache-Control": "private, max-age=60" },
});
}
export async function POST(request: NextRequest) {
@@ -25,6 +27,11 @@ export async function POST(request: NextRequest) {
if (!body.date || typeof body.date !== "string") {
return NextResponse.json({ error: "date is required" }, { status: 400 });
}
// Warn if date is in the past
const eventDate = new Date(body.date + "T23:59:59");
if (eventDate < new Date()) {
return NextResponse.json({ error: "Дата не может быть в прошлом" }, { status: 400 });
}
const id = createOpenDayEvent(body);
return NextResponse.json({ ok: true, id });
} catch (err) {
@@ -38,6 +45,12 @@ export async function PUT(request: NextRequest) {
const body = await request.json();
if (!body.id) return NextResponse.json({ error: "id is required" }, { status: 400 });
const { id, ...data } = body;
if (data.date) {
const eventDate = new Date(data.date + "T23:59:59");
if (eventDate < new Date()) {
return NextResponse.json({ error: "Дата не может быть в прошлом" }, { status: 400 });
}
}
updateOpenDayEvent(id, data);
return NextResponse.json({ ok: true });
} catch (err) {

View File

@@ -24,7 +24,9 @@ export async function GET(_request: NextRequest, { params }: Params) {
}
}
return NextResponse.json(data);
return NextResponse.json(data, {
headers: { "Cache-Control": "private, max-age=60" },
});
}
export async function PUT(request: NextRequest, { params }: Params) {

View File

@@ -5,7 +5,9 @@ import type { RichListItem, VictoryItem } from "@/types/content";
export async function GET() {
const members = getTeamMembers();
return NextResponse.json(members);
return NextResponse.json(members, {
headers: { "Cache-Control": "private, max-age=60" },
});
}
export async function POST(request: NextRequest) {

View File

@@ -2,5 +2,7 @@ import { NextResponse } from "next/server";
import { getUnreadBookingCounts } from "@/lib/db";
export async function GET() {
return NextResponse.json(getUnreadBookingCounts());
return NextResponse.json(getUnreadBookingCounts(), {
headers: { "Cache-Control": "private, max-age=15" },
});
}