Files
NextChair/src/app/api/manager/businesses/route.ts
T
Stefan Lazic b219fb4519
CI / ci (push) Canceled after 0s
initial NextChair Manager.
Key additions:
* Separate platform Manager stack: [stacks/manager/compose.yaml]
* Dedicated manager authentication with signed sessions.
* Business overview dashboard.
* Add Business workflow with slug suggestions and deployment progress.
* Business detail page with start, stop, restart, update, logs, Dockge, and conservative removal actions.
* Explicit management API endpoints under [src/app/api/manager]
* Shared provisioning service layer in [provisioning.service.ts]
* CLI and UI now use the same [create-business.sh] provisioning logic.
* Registry metadata, database status, container health, and media usage reporting.
* Manager-only entrypoint mode that does not require a business database.
* Updated deployment documentation with Manager setup and Caddy routing.
Validation passed:
* Infra, Caddy, Manager, and generated business Compose configurations.
* Shell syntax checks.
* Registry generation with registry image tags.
* git diff --check.
2026-09-04 20:54:58 +01:00

26 lines
1.5 KiB
TypeScript

import { NextResponse } from "next/server";
import { isManagerAuthenticated } from "@/services/management/management-auth";
import { createBusiness, listBusinesses } from "@/services/management/provisioning.service";
export async function GET() {
if (!(await isManagerAuthenticated())) return NextResponse.json({ error: "Unauthorized." }, { status: 401 });
return NextResponse.json(await listBusinesses());
}
export async function POST(request: Request) {
if (!(await isManagerAuthenticated())) return NextResponse.json({ error: "Unauthorized." }, { status: 401 });
const body = (await request.json().catch(() => null)) as Record<string, unknown> | null;
const name = typeof body?.name === "string" ? body.name.trim() : "";
const slug = typeof body?.slug === "string" ? body.slug.trim().toLowerCase() : "";
const domain = typeof body?.domain === "string" ? body.domain.trim().toLowerCase() : "";
const image = typeof body?.image === "string" ? body.image.trim() : "";
if (!name || name.length > 120 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) || slug.length > 22 || !/^[a-z0-9.-]+$/.test(domain) || !/^[A-Za-z0-9._/@:-]+$/.test(image)) {
return NextResponse.json({ error: "Enter a valid business name, slug, domain, and image version." }, { status: 400 });
}
try {
return NextResponse.json(await createBusiness({ name, slug, domain, image }), { status: 201 });
} catch (error) {
return NextResponse.json({ error: error instanceof Error ? error.message : "Business deployment failed." }, { status: 500 });
}
}