X Enterprises

nuxt-x-app-admin

Nuxt layer for admin portals — user management, Stripe billing, content, support ticketing, AI assistants, roles, tenants, audit logs, and impersonation. Extends nuxt-x-app.

nuxt-x-app-admin

Admin portal layer for Nuxt 4 apps. Extends nuxt-x-app with 46 XAdmin-prefixed components and 12 composables organized by domain: Dashboard, Users (Better Auth), Stripe, Content, Support, AI, Roles & Permissions, Tenants, Feature Flags, Settings, Audit Logs, and Impersonation. The layer provides UI and composables only — your backend provides the API endpoints.

This layer ships as an SPA: ssr: false is set at the layer level, so consumers inherit client-only rendering. All admin data is client-fetched against your backend API anyway. See Migration Notes.

Installation

npm install @xenterprises/nuxt-x-app-admin

If npm install fails with an ERESOLVE peer-dependency error, re-run with npm install --legacy-peer-deps — this is a known vitest peer conflict in the dependency tree and does not affect runtime behaviour.

// nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    "@xenterprises/nuxt-x-app-admin", // automatically includes @xenterprises/nuxt-x-app
    "@xenterprises/nuxt-x-auth",      // Better Auth for admin sessions
  ],
});

What the consumer writes

The batteries-included setup — a consuming app writes only:

1. Install the layer. The base layer @xenterprises/nuxt-x-app is a real dependency, so extending admin automatically includes the app shell (use --legacy-peer-deps if npm reports the known vitest peer conflict):

npm install @xenterprises/nuxt-x-app-admin

2. Extend it in nuxt.config.ts:

export default defineNuxtConfig({
  extends: [
    "@xenterprises/nuxt-x-app-admin",
    "@xenterprises/nuxt-x-auth", // Better Auth for admin sessions
  ],
});

3. No app/app.config.ts is required. This layer exposes no x.* config namespace — behaviour is controlled by component endpoint props and composable options (baseEndpoint, showToast), which carry working defaults (/api/admin/*).

4. Implement the backend /api/admin/* routes the components call (see API Endpoints Expected), with STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and BETTER_AUTH_SECRET configured server-side. The layer defaults x.app.apiUrl to /api so useXCrud list fetches match the contract; set NUXT_PUBLIC_X_APP_API_URL only if your API lives outside /api.

5. Drop components into your admin pages:

<template>
  <XAdminDashboard />
</template>

Migration Notes

2026-07-23 — Composables migrated to the useXCrud v2 factory API

All useXAdmin* composables now consume the useXCrud v2 factory API shipped by @xenterprises/nuxt-x-app@0.6.0. The crud objects they return (e.g. useXAdminUsers().users) are v2 list instancesuseXCrud(endpoint).all(){ data, total, filters, search, sort, loading, error, refresh, invalidateCache, create, update, remove, save }.

  • The legacy crud.fetch(params) is gone. Assign crud.filters.value = { ... } (refetches automatically via an internal watcher) and/or call await crud.refresh().
  • Single-record consumers use useXCrud(endpoint).read(id) — a detail instance with { data, id, form, formDirty, resetForm, ... }.
  • Any consumer code touching crud return shapes directly must be updated.

2026-07-23 — The layer now ships as an SPA

ssr: false is set at the layer level, so consumers inherit client-only rendering. Admin data is client-fetched against the backend API regardless, so no prerendered markup is lost. To opt back into SSR, set ssr: true in your own nuxt.config.ts.

Components

All components use the XAdmin prefix and are auto-imported.

Dashboard

ComponentDescription
XAdminDashboardComplete dashboard layout with all widgets.
XAdminDashboardMetricsConfigurable metrics grid.
XAdminDashboardRevenueChartRevenue trends with area chart.
XAdminDashboardActivityChartUser activity line chart.
XAdminDashboardUsageChartResource usage donut chart.
XAdminDashboardSystemChartCPU/Memory/Disk metrics.
XAdminDashboardSystemHealthSystem health status monitor.
XAdminDashboardActiveUsersReal-time active users count.
XAdminDashboardErrorLogRecent error log viewer.

User Management

ComponentDescription
XAdminUsersDirectorySearchable user directory with filters.
XAdminUsersProfileUser profile management.
XAdminUsersDetailFull user detail with tabs.
XAdminUsersSessionsActive session management.
XAdminUsersAccountsLinked OAuth accounts.

Stripe Management

ComponentDescription
XAdminStripeCustomersCustomer list with search and filters.
XAdminStripeCustomersDetailCustomer detail view with subscriptions.
XAdminStripeChargesCharge/payment history table.
XAdminStripeChargesDetailCharge detail with refund actions.
XAdminStripeInvoicesInvoice management list.
XAdminStripeInvoicesDetailInvoice detail with refund/void actions.
XAdminStripeSubscriptionsSubscription management.
XAdminStripeSubscriptionsDetailSubscription detail with cancel options.
XAdminStripePaymentMethodsPayment method list.
XAdminStripeWebhookLogsWebhook event audit trail.

Content Management

ComponentDescription
XAdminContentPostsBlog/content post list with filters.
XAdminContentPostsEditorRich post editor with SEO settings.
XAdminContentMediaMedia library with grid/list views.

Support Queue

ComponentDescription
XAdminSupportTicketsSupport ticket queue with stats.
XAdminSupportTicketsDetailTicket conversation view with reply.

AI / Agents

ComponentDescription
XAdminAIChatAI chat interface.
XAdminAIAgentsAgent management list.
XAdminAIAgentEditorAgent configuration editor.

Roles & Permissions

ComponentDescription
XAdminRolesListRole list with user counts.
XAdminRolesEditorRole creation/edit with permissions.
XAdminRolesPermissionMatrixVisual permission grid.
XAdminRolesAssignModalAssign roles to users.

Tenant Management

ComponentDescription
XAdminTenantsDirectoryTenant list with search and filters.
XAdminTenantsDetailTenant detail view with tabs.
XAdminTenantsSettingsTenant settings and feature flags.
XAdminTenantsBillingTenant billing and usage metrics.

Feature Flags

ComponentDescription
XAdminFeatureFlagsFeature flag list with search, enable toggle, and row actions.
XAdminFeatureFlagsEditorCreate/edit form for a feature flag, including per-plan overrides.

Settings

ComponentDescription
XAdminSettingsGrouped system settings editor with inline value editing.

Audit & Security

ComponentDescription
XAdminAuditLogSystem-wide activity log viewer.
XAdminImpersonationBannerWarning banner when impersonating a user.
XAdminImpersonationSwitcherModal to select a user to impersonate.

Composables

useXAdminDashboard(options?)

const dashboard = useXAdminDashboard({ refreshInterval: 30000 });

dashboard.health.value
dashboard.metrics.value
dashboard.activeUsers.value
dashboard.revenueHistory.value

await dashboard.refreshAll();

useXAdminUsers()

const admin = useXAdminUsers();

await admin.updateRole(userId, "editor");
await admin.suspendUser(userId, "Violation of TOS");
await admin.unsuspendUser(userId);
await admin.resetPassword(userId);
await admin.deleteUser(userId, { hardDelete: false });

useXAdminStripe()

const stripe = useXAdminStripe();

stripe.customers.data
stripe.subscriptions.data

await stripe.syncCustomer(customerId);
await stripe.cancelSubscription(subscriptionId, { immediately: false });
await stripe.refundInvoice(invoiceId, { amount: 1000 });
await stripe.voidInvoice(invoiceId);

useXAdminContent()

const content = useXAdminContent();

await content.publishPost(postId);
await content.unpublishPost(postId);
await content.duplicatePost(postId);
await content.uploadMedia(files, { folder: "images" });

useXAdminSupport()

const support = useXAdminSupport();

await support.assignTicket(ticketId, agentId);
await support.closeTicket(ticketId, "Resolved");
await support.replyToTicket(ticketId, "Hello!", { close: true });

useXAdminAI()

const ai = useXAdminAI();

await ai.selectAgent(agentId);
await ai.sendMessage("Hello!");
await ai.streamMessage("Generate a report", (chunk) => console.log(chunk));
await ai.createAgent({ name: "Support Bot", systemPrompt: "..." });

useXAdminRoles()

const roles = useXAdminRoles();

await roles.updatePermissions(roleId, ["perm1", "perm2"]);
await roles.assignRole(userId, roleId);
await roles.revokeRole(userId, roleId);
roles.hasPermission(roleId, "users:delete");

useXAdminTenants()

const tenants = useXAdminTenants();

await tenants.suspend(tenantId, "Violation reason");
await tenants.activate(tenantId);
await tenants.updatePlan(tenantId, "enterprise");
await tenants.updateSettings(tenantId, { maxUsers: 100 });

useXAdminAuditLog()

const auditLog = useXAdminAuditLog();

await auditLog.getLogsByUser(userId);
await auditLog.getLogsByResource("users", userId);
await auditLog.exportLogs("csv");

useXAdminImpersonation()

const impersonation = useXAdminImpersonation();

impersonation.isImpersonating.value
impersonation.impersonatedUser.value

await impersonation.startImpersonation(userId);
await impersonation.stopImpersonation();

useXAdminFeatureFlags()

const featureFlags = useXAdminFeatureFlags();

featureFlags.flags.data.value // v2 list instance: useXCrud("admin/feature-flags").all()

await featureFlags.createFlag({ key: "new-checkout", name: "New Checkout", enabled: true });
await featureFlags.updateFlag(flagId, { enabled: false });
await featureFlags.toggleFlag(flag);
await featureFlags.deleteFlag(flagId);

featureFlags.getFlag("new-checkout");
featureFlags.isEnabled("new-checkout", { plan: "pro" }); // master switch → plan override → defaultValue

useXAdminSystemSettings()

const systemSettings = useXAdminSystemSettings();

systemSettings.settings.data.value        // v2 list instance: useXCrud("admin/settings").all()
systemSettings.groupedSettings.value      // settings grouped by `group`
systemSettings.getSetting("general", "siteName");

await systemSettings.updateSetting({ group: "general", key: "siteName", value: "Acme" });
await systemSettings.updateSettings([{ group: "general", key: "siteName", value: "Acme" }]);

API Endpoints Expected

The layer calls these backend routes — your backend must implement them:

DomainRoutes
DashboardGET /api/admin/dashboard/health, /metrics, /active-users, /errors, /charts/*
UsersGET/POST /api/admin/users, GET/PUT/DELETE /api/admin/users/:id, ban/unban/reset-password
StripeCustomers, charges, subscriptions, invoices, webhook-logs under /api/admin/stripe/*
ContentPosts (publish/unpublish/duplicate), media upload under /api/admin/content/*
SupportTickets (assign/close/reopen/reply), agents, stats under /api/admin/support/*
AIAgents, conversations, chat, stream under /api/admin/ai/*
RolesCRUD, permissions, assign/revoke under /api/admin/roles/*
TenantsCRUD, suspend/activate/plan/settings under /api/admin/tenants/*
Feature FlagsCRUD under /api/admin/feature-flags/*
SettingsGET /api/admin/settings, PUT /api/admin/settings (single or bulk)
AuditGET /api/admin/audit-log, POST /api/admin/audit-log/export
ImpersonationPOST /api/admin/impersonation/start, /stop, GET .../status

Environment Variables

This layer does not read env vars directly. The backend API it calls typically needs:

VariableRequiredDescription
STRIPE_SECRET_KEYYes (backend)Stripe API key for billing management.
STRIPE_WEBHOOK_SECRETYes (backend)Stripe webhook signing secret.
BETTER_AUTH_SECRETYes (backend)Better Auth session secret.
NUXT_PUBLIC_API_BASENoOverride API base URL (default: /api).

Error Handling

All composables follow a consistent pattern:

Error SourceBehavior
$fetch failureToast shown (if showToast: true), error re-thrown.
Invalid inputCaught by backend, returned as typed error.
Network timeoutToast with "Failed to..." message, error re-thrown.

Pass showToast: false to suppress toasts and handle errors manually.

How It Works

nuxt-x-app-admin is a Nuxt layer that extends nuxt-x-app. Extending it automatically includes all base-layer components, composables, and utilities.

Components live under app/components/XAdmin/ and are auto-registered with the XAdmin prefix. Each component is self-contained: pass an endpoint prop and it handles fetching, loading states, pagination, and actions using useXCrud from the base layer.

Composables live under app/composables/ and wrap $fetch with toast notifications, error handling, and reactive state. They use the useXCrud v2 factory API from the base layer — useXCrud(endpoint).all() for list CRUD and useXCrud(endpoint).read(id) for single records — plus raw $fetch for domain-specific actions (suspend, impersonate, refund, stream, etc.). See Migration Notes for the v1 → v2 changes.

Types are exported from app/types/index.ts and define shapes for AdminUser, AuditLogEntry, Tenant, Role, Permission, Stripe objects, and more.

The layer's nuxt.config.ts configures extends: ['@xenterprises/nuxt-x-app'] (dependency @xenterprises/nuxt-x-app@^0.6.0), sets ssr: false (SPA — consumers inherit client-only rendering), sets up component auto-import from ./app/components, and adds composable auto-import from ./app/composables.

The layer does not include server routes — your backend implements all /api/admin/* endpoints.

Copyright © 2026