Admin Dashboard
Managing users, analytics, and system settings
Admin Dashboard
Comprehensive admin dashboard for managing your SaaS application.
Features
- User management
- Analytics and metrics
- System settings
- Billing overview
- Support tickets
- Activity logs
Access Control
Admin Middleware
// server/middleware/admin.ts
export default defineEventHandler(async (event) => {
const user = event.context.user
if (!user || user.role !== 'admin') {
throw createError({
statusCode: 403,
message: 'Admin access required'
})
}
})
Route Protection
<script setup>
definePageMeta({
middleware: ['auth', 'admin']
})
</script>
User Management
List Users
// GET /api/admin/users
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const users = await db
.select()
.from(users)
.limit(query.limit || 50)
.offset(query.offset || 0)
return users
})
Update User
// PATCH /api/admin/users/:id
export default defineEventHandler(async (event) => {
const userId = getRouterParam(event, 'id')
const data = await readBody(event)
await db
.update(users)
.set(data)
.where(eq(users.id, userId))
return { success: true }
})
Ban/Suspend User
async function suspendUser(userId: string, reason: string) {
await db
.update(users)
.set({
status: 'suspended',
suspendedAt: new Date(),
suspendedReason: reason
})
.where(eq(users.id, userId))
}
Analytics
Dashboard Metrics
export default defineEventHandler(async (event) => {
const [
totalUsers,
activeUsers,
totalRevenue,
newSignups
] = await Promise.all([
db.select({ count: count() }).from(users),
db.select({ count: count() })
.from(users)
.where(gte(users.lastActiveAt, subDays(new Date(), 30))),
db.select({ sum: sum(subscriptions.amount) }).from(subscriptions),
db.select({ count: count() })
.from(users)
.where(gte(users.createdAt, subDays(new Date(), 7)))
])
return {
totalUsers: totalUsers[0].count,
activeUsers: activeUsers[0].count,
totalRevenue: totalRevenue[0].sum,
newSignups: newSignups[0].count
}
})
Activity Logs
Log Events
async function logActivity(event: {
userId: string
action: string
resource: string
metadata?: any
}) {
await db.insert(activityLogs).values({
userId: event.userId,
action: event.action,
resource: event.resource,
metadata: event.metadata,
createdAt: new Date()
})
}
View Logs
export default defineEventHandler(async (event) => {
const logs = await db
.select()
.from(activityLogs)
.orderBy(desc(activityLogs.createdAt))
.limit(100)
return logs
})
System Settings
// GET /api/admin/settings
export default defineEventHandler(async () => {
const settings = await db.select().from(systemSettings)
return Object.fromEntries(
settings.map(s => [s.key, s.value])
)
})
// PATCH /api/admin/settings
export default defineEventHandler(async (event) => {
const data = await readBody(event)
for (const [key, value] of Object.entries(data)) {
await db
.insert(systemSettings)
.values({ key, value })
.onConflictDoUpdate({
target: systemSettings.key,
set: { value, updatedAt: new Date() }
})
}
return { success: true }
})
Billing Overview
export default defineEventHandler(async () => {
const [
activeSubscriptions,
monthlyRecurringRevenue,
churnRate,
averageRevenuePerUser
] = await calculateBillingMetrics()
return {
activeSubscriptions,
mrr: monthlyRecurringRevenue,
churnRate,
arpu: averageRevenuePerUser
}
})
Export Data
// Export users as CSV
export default defineEventHandler(async (event) => {
const users = await db.select().from(users)
const csv = [
'ID,Email,Name,Created At,Status',
...users.map(u =>
`${u.id},${u.email},${u.name},${u.createdAt},${u.status}`
)
].join('\n')
setHeader(event, 'Content-Type', 'text/csv')
setHeader(event, 'Content-Disposition', 'attachment; filename=users.csv')
return csv
})
Best Practices
- Implement audit logging
- Use proper authorization
- Rate limit admin actions
- Add confirmation for destructive actions
- Monitor admin activity
- Implement 2FA for admins
- Regular security audits