Files
LiveServer-M1/src/app/api/rooms/route.ts
joylessorchid a42ec96965 perf: Redis pub/sub, PgBouncer, optimistic UI for high concurrency
- Add Redis 7 for pub/sub (lobby + chat real-time), rate limiting, caching
- Replace SSE DB polling with Redis pub/sub (lobby: instant approval, chat: instant delivery)
- Add PgBouncer (transaction mode, 500 client → 25 pool connections)
- Chat SSE stream via Redis pub/sub instead of 3s polling
- Optimistic UI in ChatPanel (messages appear before server confirms)
- Redis-based rate limiter (works across multiple app replicas)
- Prisma query optimization (select only needed fields)
- Chat message cache in Redis (10s TTL)
- Docker Compose: add redis, pgbouncer services with healthchecks
- Production: resource limits, 2 app replicas behind Traefik
- Update CLAUDE.md, README.md, .env.example, setup.sh

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 14:17:25 +03:00

78 lines
2.2 KiB
TypeScript

import { NextResponse } from "next/server";
import { z } from "zod";
import { prisma } from "@/lib/prisma";
import { getSessionFromRequest } from "@/lib/auth-helpers";
import { hash } from "bcryptjs";
const createRoomSchema = z.object({
name: z.string().min(1).max(255),
lobbyEnabled: z.boolean().optional().default(true),
webinarMode: z.boolean().optional().default(false),
pin: z.string().min(4).max(20).optional(),
});
export async function POST(req: Request) {
const session = await getSessionFromRequest(req);
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const user = await prisma.user.findUnique({ where: { id: session.user.id } });
if (!user || (user.role !== "HOST" && user.role !== "ADMIN")) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await req.json();
const parsed = createRoomSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({ error: parsed.error.message }, { status: 400 });
}
const { name, lobbyEnabled, webinarMode, pin } = parsed.data;
const pinHash = pin ? await hash(pin, 10) : null;
const room = await prisma.room.create({
data: {
name,
lobbyEnabled,
webinarMode,
pinHash,
hostId: user.id,
},
});
return NextResponse.json(room, { status: 201 });
}
export async function GET(req: Request) {
const session = await getSessionFromRequest(req);
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const user = await prisma.user.findUnique({ where: { id: session.user.id } });
if (!user || (user.role !== "HOST" && user.role !== "ADMIN")) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const where = user.role === "ADMIN" ? {} : { hostId: user.id };
const rooms = await prisma.room.findMany({
where,
orderBy: { createdAt: "desc" },
select: {
id: true,
name: true,
code: true,
status: true,
lobbyEnabled: true,
webinarMode: true,
isLocked: true,
createdAt: true,
startedAt: true,
endedAt: true,
},
});
return NextResponse.json(rooms);
}