feat(plugins): foundation système Plugin Karbé
- Modèle Prisma Plugin (key, name, description, category, version, enabled, config JSONB, migrationsApplied, timestamps) + migration SQL - PluginRegistry (src/lib/plugins/registry.ts) avec 12 plugins déclarés : visuels (theme-guyane, landing-hero, landing-sections, image-gallery-seed, demo-carbets-seed), métier (access-type, seasonality, pirogue-providers, min-stay), contenus (content-pages, legal-pages), i18n (i18n-fr-en) - Server helpers (server.ts) : sync, isEnabled, getEnabledKeys, toggle avec hooks onEnable/onDisable, updateConfig, cache 5s - Client bridge (client.tsx) : PluginProvider + useIsPluginEnabled - Composant <IfPluginEnabled plugin=... fallback=...> - Guard requirePluginOr404 pour pages et routes - Page admin /admin/plugins avec table toggle par catégorie + édition config - Route PATCH /api/admin/plugins/[key] + GET - Layout async qui sync registry + passe enabledKeys au PluginProvider Tous plugins en enabled=false par défaut, activation pilotée depuis l'admin.
This commit is contained in:
parent
d7de43a70e
commit
62cc464738
12 changed files with 577 additions and 2 deletions
39
src/app/api/admin/plugins/[key]/route.ts
Normal file
39
src/app/api/admin/plugins/[key]/route.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { requireRole } from "@/lib/authorization";
|
||||
import { UserRole } from "@/generated/prisma/enums";
|
||||
import { findDescriptor } from "@/lib/plugins/registry";
|
||||
import { togglePlugin, updatePluginConfig, getPluginState } from "@/lib/plugins/server";
|
||||
|
||||
const patchSchema = z.object({
|
||||
enabled: z.boolean().optional(),
|
||||
config: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
export async function PATCH(req: Request, ctx: { params: Promise<{ key: string }> }) {
|
||||
await requireRole([UserRole.ADMIN]);
|
||||
const { key } = await ctx.params;
|
||||
if (!findDescriptor(key)) {
|
||||
return NextResponse.json({ error: "Unknown plugin" }, { status: 404 });
|
||||
}
|
||||
const parsed = patchSchema.safeParse(await req.json().catch(() => ({})));
|
||||
if (!parsed.success) {
|
||||
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
|
||||
}
|
||||
let state = await getPluginState(key);
|
||||
if (parsed.data.enabled !== undefined) {
|
||||
state = await togglePlugin(key, parsed.data.enabled);
|
||||
}
|
||||
if (parsed.data.config !== undefined) {
|
||||
state = await updatePluginConfig(key, parsed.data.config);
|
||||
}
|
||||
return NextResponse.json(state);
|
||||
}
|
||||
|
||||
export async function GET(_req: Request, ctx: { params: Promise<{ key: string }> }) {
|
||||
await requireRole([UserRole.ADMIN]);
|
||||
const { key } = await ctx.params;
|
||||
const state = await getPluginState(key);
|
||||
if (!state) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
return NextResponse.json(state);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue