feat: implement comprehensive admin functionality

- Add admin role system with role and isAdmin fields to users table
- Create admin_actions audit log table for tracking all admin operations
- Implement admin CLI tool for user management (create, promote, demote, list, check)
- Add admin authentication with role-based access control
- Create admin service layer with system statistics and user management
- Implement user impersonation system with proper security checks
- Add admin API endpoints for user management and system statistics
- Create admin dashboard UI with overview, users, and action logs
- Fix admin stats endpoint and user deletion with proper foreign key handling
- Add admin link to navigation bar for admin users

Database:
- Add role and isAdmin columns to users table
- Create admin_actions table for audit trail
- Migration script: add-admin-functionality.js

CLI:
- src/backend/scripts/admin-cli.js - Admin user management tool

Backend:
- src/backend/services/admin.service.js - Admin business logic
- Updated auth.service.js with admin helper functions
- Enhanced index.js with admin routes and middleware
- Export sqlite connection from config for raw SQL operations

Frontend:
- src/frontend/src/routes/admin/+page.svelte - Admin dashboard
- Updated api.js with adminAPI functions
- Added Admin link to navigation bar

Security:
- Admin-only endpoints with role verification
- Audit logging for all admin actions
- Impersonation with 1-hour token expiration
- Foreign key constraint handling for user deletion
- Cannot delete self or other admins
- Last admin protection
This commit is contained in:
2026-01-21 09:43:56 +01:00
parent fe305310b9
commit e88537754f
10 changed files with 2314 additions and 1 deletions

View File

@@ -0,0 +1,103 @@
/**
* Migration: Add admin functionality to users table and create admin_actions table
*
* This script adds role-based access control (RBAC) for admin functionality:
* - Adds 'role' and 'isAdmin' columns to users table
* - Creates admin_actions table for audit logging
* - Adds indexes for performance
*/
import Database from 'bun:sqlite';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
// ES module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const dbPath = join(__dirname, '../award.db');
const sqlite = new Database(dbPath);
async function migrate() {
console.log('Starting migration: Add admin functionality...');
try {
// Check if role column already exists in users table
const columnExists = sqlite.query(`
SELECT COUNT(*) as count
FROM pragma_table_info('users')
WHERE name = 'role'
`).get();
if (columnExists.count > 0) {
console.log('Admin columns already exist in users table. Skipping...');
} else {
// Add role column to users table
sqlite.exec(`
ALTER TABLE users
ADD COLUMN role TEXT NOT NULL DEFAULT 'user'
`);
// Add isAdmin column to users table
sqlite.exec(`
ALTER TABLE users
ADD COLUMN is_admin INTEGER NOT NULL DEFAULT 0
`);
console.log('Added role and isAdmin columns to users table');
}
// Check if admin_actions table already exists
const tableExists = sqlite.query(`
SELECT name FROM sqlite_master
WHERE type='table' AND name='admin_actions'
`).get();
if (tableExists) {
console.log('Table admin_actions already exists. Skipping...');
} else {
// Create admin_actions table
sqlite.exec(`
CREATE TABLE admin_actions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER NOT NULL,
action_type TEXT NOT NULL,
target_user_id INTEGER,
details TEXT,
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),
FOREIGN KEY (admin_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (target_user_id) REFERENCES users(id) ON DELETE SET NULL
)
`);
// Create indexes for admin_actions
sqlite.exec(`
CREATE INDEX idx_admin_actions_admin_id ON admin_actions(admin_id)
`);
sqlite.exec(`
CREATE INDEX idx_admin_actions_action_type ON admin_actions(action_type)
`);
sqlite.exec(`
CREATE INDEX idx_admin_actions_created_at ON admin_actions(created_at)
`);
console.log('Created admin_actions table with indexes');
}
console.log('Migration complete! Admin functionality added to database.');
} catch (error) {
console.error('Migration failed:', error);
sqlite.close();
process.exit(1);
}
sqlite.close();
}
// Run migration
migrate().then(() => {
console.log('Migration script completed successfully');
process.exit(0);
});