feat(admin): web admin panel — user CRUD, role assignment, system health (#125)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
- Add BetterAuth admin plugin with admin/member role configuration - Add banned/banReason/banExpires fields to users schema - Gateway AdminModule: user list/create/role/ban/delete endpoints at /api/admin/users - Gateway AdminHealthController: system health at /api/admin/health (DB, Valkey, agent pool, providers) - AdminGuard: enforces admin role on all /api/admin/* routes - Web admin page: two-tab UI (User Management + System Health) - AdminRoleGuard: client-side redirect for non-admin users - Add adminClient to web auth-client for BetterAuth admin plugin integration - Add @mosaic/queue as gateway dep for Valkey health check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { betterAuth } from 'better-auth';
|
||||
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
||||
import { genericOAuth } from 'better-auth/plugins';
|
||||
import { admin, genericOAuth } from 'better-auth/plugins';
|
||||
import type { Db } from '@mosaic/db';
|
||||
|
||||
export interface AuthConfig {
|
||||
@@ -68,7 +68,7 @@ export function createAuth(config: AuthConfig) {
|
||||
expiresIn: 60 * 60 * 24 * 7, // 7 days
|
||||
updateAge: 60 * 60 * 24, // refresh daily
|
||||
},
|
||||
plugins,
|
||||
plugins: [...(plugins ?? []), admin({ defaultRole: 'member', adminRoles: ['admin'] })],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ export const users = pgTable('users', {
|
||||
emailVerified: boolean('email_verified').notNull().default(false),
|
||||
image: text('image'),
|
||||
role: text('role').notNull().default('member'),
|
||||
banned: boolean('banned').default(false),
|
||||
banReason: text('ban_reason'),
|
||||
banExpires: timestamp('ban_expires', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user