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.
This commit is contained in:
24 files changed
+596
-11
No files matched your search
@@ -0,0 +1,25 @@
|
||||
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 });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user