feat: add authentication, user management, and admin features
Added comprehensive authentication and authorization system: Authentication System: - Better Auth integration with session management - Login/logout pages and API routes - Middleware for route protection - Auth utilities and client libraries User Management: - User list, detail, and invite pages - User API endpoints (CRUD operations) - Session management for users - Profile settings page Role-Based Access Control: - Role management pages (list, create, edit) - Permission system with granular controls - Role assignment to users - Role API endpoints Admin Features: - Audit log page for tracking system events - Admin settings page - Audit service for logging user actions Additional Features: - Quotes management pages and components - SalesBldr API integration - Email service for notifications Configuration & Documentation: - Updated docker-compose.yml - MCP server configuration (mcp.json) - CVE-2025-55182 security review documentation - Standards guide and PRD documents - Re-enabling authentication documentation Database Migrations: - 012: Auth tables (users, sessions, accounts, verifications) - 013: Role tables (roles, permissions, role_permissions, user_roles) - 014: Admin settings table UI Updates: - Updated dashboard layout - Enhanced app layout with auth integration
This commit is contained in:
parent
d8e6931b85
commit
9f912aed24
68 changed files with 7651 additions and 3 deletions
103
lib/bootstrap.ts
Normal file
103
lib/bootstrap.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { Pool } from "pg";
|
||||
|
||||
const pool = new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if any users exist in the database
|
||||
*/
|
||||
export async function hasUsers(): Promise<boolean> {
|
||||
try {
|
||||
const result = await pool.query('SELECT COUNT(*) as count FROM "user"');
|
||||
return parseInt(result.rows[0].count) > 0;
|
||||
} catch (error) {
|
||||
// Table might not exist yet
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the default super-admin user from environment variables
|
||||
*/
|
||||
export async function createDefaultAdmin(): Promise<boolean> {
|
||||
const email = process.env.DEFAULT_ADMIN_EMAIL;
|
||||
const name = process.env.DEFAULT_ADMIN_NAME || "System Administrator";
|
||||
|
||||
if (!email) {
|
||||
console.warn("DEFAULT_ADMIN_EMAIL not set, skipping admin creation");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if user already exists
|
||||
const existing = await pool.query(
|
||||
'SELECT id FROM "user" WHERE email = $1',
|
||||
[email]
|
||||
);
|
||||
|
||||
if (existing.rows.length > 0) {
|
||||
console.log("Default admin already exists");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the admin user
|
||||
const id = crypto.randomUUID();
|
||||
await pool.query(
|
||||
`INSERT INTO "user" (id, name, email, role, email_verified, requires_setup, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, 'super-admin', false, true, NOW(), NOW())`,
|
||||
[id, name, email]
|
||||
);
|
||||
|
||||
console.log(`Created default admin: ${email}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Failed to create default admin:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run bootstrap checks and setup
|
||||
*/
|
||||
export async function bootstrap(): Promise<void> {
|
||||
try {
|
||||
const usersExist = await hasUsers();
|
||||
|
||||
if (!usersExist) {
|
||||
console.log("No users found, running initial setup...");
|
||||
await createDefaultAdmin();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Bootstrap failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user requires setup (has requires_setup flag)
|
||||
*/
|
||||
export async function userRequiresSetup(userId: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
'SELECT requires_setup FROM "user" WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
return result.rows[0]?.requires_setup === true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the requires_setup flag for a user
|
||||
*/
|
||||
export async function clearSetupFlag(userId: string): Promise<void> {
|
||||
try {
|
||||
await pool.query(
|
||||
'UPDATE "user" SET requires_setup = false, updated_at = NOW() WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to clear setup flag:", error);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue