nuxt-x-app-admin
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.
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 instances — useXCrud(endpoint).all() → { data, total, filters, search, sort, loading, error, refresh, invalidateCache, create, update, remove, save }.
- The legacy
crud.fetch(params)is gone. Assigncrud.filters.value = { ... }(refetches automatically via an internal watcher) and/or callawait 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
| Component | Description |
|---|---|
XAdminDashboard | Complete dashboard layout with all widgets. |
XAdminDashboardMetrics | Configurable metrics grid. |
XAdminDashboardRevenueChart | Revenue trends with area chart. |
XAdminDashboardActivityChart | User activity line chart. |
XAdminDashboardUsageChart | Resource usage donut chart. |
XAdminDashboardSystemChart | CPU/Memory/Disk metrics. |
XAdminDashboardSystemHealth | System health status monitor. |
XAdminDashboardActiveUsers | Real-time active users count. |
XAdminDashboardErrorLog | Recent error log viewer. |
User Management
| Component | Description |
|---|---|
XAdminUsersDirectory | Searchable user directory with filters. |
XAdminUsersProfile | User profile management. |
XAdminUsersDetail | Full user detail with tabs. |
XAdminUsersSessions | Active session management. |
XAdminUsersAccounts | Linked OAuth accounts. |
Stripe Management
| Component | Description |
|---|---|
XAdminStripeCustomers | Customer list with search and filters. |
XAdminStripeCustomersDetail | Customer detail view with subscriptions. |
XAdminStripeCharges | Charge/payment history table. |
XAdminStripeChargesDetail | Charge detail with refund actions. |
XAdminStripeInvoices | Invoice management list. |
XAdminStripeInvoicesDetail | Invoice detail with refund/void actions. |
XAdminStripeSubscriptions | Subscription management. |
XAdminStripeSubscriptionsDetail | Subscription detail with cancel options. |
XAdminStripePaymentMethods | Payment method list. |
XAdminStripeWebhookLogs | Webhook event audit trail. |
Content Management
| Component | Description |
|---|---|
XAdminContentPosts | Blog/content post list with filters. |
XAdminContentPostsEditor | Rich post editor with SEO settings. |
XAdminContentMedia | Media library with grid/list views. |
Support Queue
| Component | Description |
|---|---|
XAdminSupportTickets | Support ticket queue with stats. |
XAdminSupportTicketsDetail | Ticket conversation view with reply. |
AI / Agents
| Component | Description |
|---|---|
XAdminAIChat | AI chat interface. |
XAdminAIAgents | Agent management list. |
XAdminAIAgentEditor | Agent configuration editor. |
Roles & Permissions
| Component | Description |
|---|---|
XAdminRolesList | Role list with user counts. |
XAdminRolesEditor | Role creation/edit with permissions. |
XAdminRolesPermissionMatrix | Visual permission grid. |
XAdminRolesAssignModal | Assign roles to users. |
Tenant Management
| Component | Description |
|---|---|
XAdminTenantsDirectory | Tenant list with search and filters. |
XAdminTenantsDetail | Tenant detail view with tabs. |
XAdminTenantsSettings | Tenant settings and feature flags. |
XAdminTenantsBilling | Tenant billing and usage metrics. |
Feature Flags
| Component | Description |
|---|---|
XAdminFeatureFlags | Feature flag list with search, enable toggle, and row actions. |
XAdminFeatureFlagsEditor | Create/edit form for a feature flag, including per-plan overrides. |
Settings
| Component | Description |
|---|---|
XAdminSettings | Grouped system settings editor with inline value editing. |
Audit & Security
| Component | Description |
|---|---|
XAdminAuditLog | System-wide activity log viewer. |
XAdminImpersonationBanner | Warning banner when impersonating a user. |
XAdminImpersonationSwitcher | Modal 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:
| Domain | Routes |
|---|---|
| Dashboard | GET /api/admin/dashboard/health, /metrics, /active-users, /errors, /charts/* |
| Users | GET/POST /api/admin/users, GET/PUT/DELETE /api/admin/users/:id, ban/unban/reset-password |
| Stripe | Customers, charges, subscriptions, invoices, webhook-logs under /api/admin/stripe/* |
| Content | Posts (publish/unpublish/duplicate), media upload under /api/admin/content/* |
| Support | Tickets (assign/close/reopen/reply), agents, stats under /api/admin/support/* |
| AI | Agents, conversations, chat, stream under /api/admin/ai/* |
| Roles | CRUD, permissions, assign/revoke under /api/admin/roles/* |
| Tenants | CRUD, suspend/activate/plan/settings under /api/admin/tenants/* |
| Feature Flags | CRUD under /api/admin/feature-flags/* |
| Settings | GET /api/admin/settings, PUT /api/admin/settings (single or bulk) |
| Audit | GET /api/admin/audit-log, POST /api/admin/audit-log/export |
| Impersonation | POST /api/admin/impersonation/start, /stop, GET .../status |
Environment Variables
This layer does not read env vars directly. The backend API it calls typically needs:
| Variable | Required | Description |
|---|---|---|
STRIPE_SECRET_KEY | Yes (backend) | Stripe API key for billing management. |
STRIPE_WEBHOOK_SECRET | Yes (backend) | Stripe webhook signing secret. |
BETTER_AUTH_SECRET | Yes (backend) | Better Auth session secret. |
NUXT_PUBLIC_API_BASE | No | Override API base URL (default: /api). |
Error Handling
All composables follow a consistent pattern:
| Error Source | Behavior |
|---|---|
$fetch failure | Toast shown (if showToast: true), error re-thrown. |
| Invalid input | Caught by backend, returned as typed error. |
| Network timeout | Toast 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.
