diff --git a/src/app/api/admin/import/furni/organize/route.ts b/src/app/api/admin/import/furni/organize/route.ts
new file mode 100644
index 0000000000..0e2889515d
--- /dev/null
+++ b/src/app/api/admin/import/furni/organize/route.ts
@@ -0,0 +1,42 @@
+import { withAdmin } from "@/lib/api-handler";
+import { apiError, apiOk } from "@/lib/api-response";
+import { PERMS } from "@/lib/permissions";
+import { logAudit } from "@/lib/services/audit";
+import { organizeCatalogAll } from "@/lib/services/catalog-repair";
+import { rcon } from "@/lib/services/rcon";
+
+// ── Fully automatic catalog organization of the whole database ──────
+export const POST = withAdmin(
+ { permission: PERMS.ASSETS_IMPORT },
+ async (_request, ctx) => {
+ try {
+ const result = await organizeCatalogAll();
+
+ // Refresh game server caches so the reorganized catalog shows up.
+ try {
+ await rcon.updateCatalog();
+ } catch (err) {
+ console.warn(
+ "[organize-furni] RCON catalog refresh failed:",
+ (err as Error).message,
+ );
+ }
+
+ logAudit({
+ userId: ctx.session.user.id,
+ action: "furni_organize",
+ target: "CatalogItems",
+ targetId: 0,
+ after: {
+ pagesCreated: result.pagesCreated,
+ catalogAdded: result.catalogAdded,
+ catalogRehomed: result.catalogRehomed,
+ },
+ });
+
+ return apiOk({ ...result });
+ } catch (err) {
+ return apiError((err as Error).message, 500);
+ }
+ },
+);
diff --git a/src/components/admin/studio/studio-client.tsx b/src/components/admin/studio/studio-client.tsx
index 7c2daaa666..dd5513aa80 100644
--- a/src/components/admin/studio/studio-client.tsx
+++ b/src/components/admin/studio/studio-client.tsx
@@ -514,6 +514,37 @@ export function StudioClient({
}
};
+ const [organizing, setOrganizing] = useState(false);
+
+ async function organizeAll() {
+ if (organizing) return;
+ setOrganizing(true);
+ try {
+ const res = await adminFetch("/api/admin/import/furni/organize", {
+ method: "POST",
+ });
+ const data = await res.json();
+ if (res.ok) {
+ const parts = [
+ `Catalogus georganiseerd`,
+ data.pagesCreated > 0
+ ? `${data.pagesCreated} pagina's aangemaakt`
+ : null,
+ data.catalogAdded > 0 ? `${data.catalogAdded} nieuw` : null,
+ data.catalogRehomed > 0 ? `${data.catalogRehomed} bijgewerkt` : null,
+ ].filter(Boolean);
+ toast.success(parts.join(" · "));
+ fetchStats();
+ } else {
+ toast.error(data.error || "Organiseren mislukt");
+ }
+ } catch {
+ toast.error("Netwerkfout");
+ } finally {
+ setOrganizing(false);
+ }
+ }
+
async function deleteItem() {
if (!deleting) return;
try {
@@ -844,6 +875,22 @@ export function StudioClient({
+
+
{selectedNonImported > 0 && (