diff --git a/DOCKER_GIT_DEPLOYMENT.md b/DOCKER_GIT_DEPLOYMENT.md
index 175db9b..30f5fe2 100644
--- a/DOCKER_GIT_DEPLOYMENT.md
+++ b/DOCKER_GIT_DEPLOYMENT.md
@@ -22,7 +22,10 @@ docker-compose up
docker-compose -f docker-compose.prod.yml up --build
```
-**Note**: Both development and production Docker builds automatically create the default admin account.
+**Note**: Both development and production Docker builds automatically:
+- Create the default admin account
+- Run any pending database migrations
+- Initialize/update the database schema
### 2. Deploy from Git Repository
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index 4670af0..217da9a 100644
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -20,6 +20,10 @@ chmod -R 755 /app/public/uploads
echo "🔧 Setting up admin account..."
node scripts/create-admin.js
+# Run any pending database migrations
+echo "🔄 Running database migrations..."
+./run-migrations.sh
+
# Start the application
echo "✅ Starting production server..."
exec npm start
diff --git a/migrate-add-team-lead-role.mjs b/migrate-add-team-lead-role.mjs
new file mode 100644
index 0000000..215a8e5
--- /dev/null
+++ b/migrate-add-team-lead-role.mjs
@@ -0,0 +1,75 @@
+import db from './src/lib/db.js';
+
+console.log('Starting migration to add team_lead role to users table constraint...');
+
+try {
+ // Disable foreign key constraints temporarily
+ db.pragma('foreign_keys = OFF');
+ console.log('Disabled foreign key constraints');
+
+ // Since SQLite doesn't support modifying CHECK constraints directly,
+ // we need to recreate the table with the new constraint
+
+ // First, create a backup table with current data
+ db.exec('CREATE TABLE users_backup AS SELECT * FROM users');
+ console.log('Created backup table');
+
+ // Drop the original table
+ db.exec('DROP TABLE users');
+ console.log('Dropped original table');
+
+ // Recreate the table with the updated constraint
+ db.exec(`
+ CREATE TABLE users (
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
+ name TEXT NOT NULL,
+ username TEXT UNIQUE NOT NULL,
+ password_hash TEXT NOT NULL,
+ role TEXT CHECK(role IN ('admin', 'team_lead', 'project_manager', 'user', 'read_only')) DEFAULT 'user',
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
+ is_active INTEGER DEFAULT 1,
+ last_login TEXT,
+ failed_login_attempts INTEGER DEFAULT 0,
+ locked_until TEXT,
+ can_be_assigned INTEGER DEFAULT 1,
+ initial TEXT
+ )
+ `);
+ console.log('Created new table with updated constraint');
+
+ // Copy data back from backup
+ db.exec(`
+ INSERT INTO users (
+ id, name, username, password_hash, role, created_at, updated_at,
+ is_active, last_login, failed_login_attempts, locked_until,
+ can_be_assigned, initial
+ )
+ SELECT
+ id, name, username, password_hash, role, created_at, updated_at,
+ is_active, last_login, failed_login_attempts, locked_until,
+ can_be_assigned, initial
+ FROM users_backup
+ `);
+ console.log('Copied data back from backup');
+
+ // Drop the backup table
+ db.exec('DROP TABLE users_backup');
+ console.log('Dropped backup table');
+
+ // Re-enable foreign key constraints
+ db.pragma('foreign_keys = ON');
+ console.log('Re-enabled foreign key constraints');
+
+ // Verify the migration
+ const userCount = db.prepare('SELECT COUNT(*) as count FROM users').get();
+ console.log(`✅ Migration completed successfully! Users table now has ${userCount.count} records`);
+
+ // Verify the constraint allows the new role
+ console.log('✅ CHECK constraint now includes: admin, team_lead, project_manager, user, read_only');
+
+} catch (error) {
+ console.error('❌ Migration failed:', error.message);
+ console.error('You may need to restore from backup manually');
+ process.exit(1);
+}
\ No newline at end of file
diff --git a/run-migrations.sh b/run-migrations.sh
new file mode 100644
index 0000000..4c05ad5
--- /dev/null
+++ b/run-migrations.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Database migration runner for deployment
+# This script runs all pending migrations in order
+
+echo "🔄 Running database migrations..."
+
+# List of migration scripts to run (in order)
+MIGRATIONS=(
+ "migrate-add-team-lead-role.mjs"
+)
+
+for migration in "${MIGRATIONS[@]}"; do
+ if [ -f "$migration" ]; then
+ echo "Running migration: $migration"
+ if node "$migration"; then
+ echo "✅ Migration $migration completed successfully"
+ # Optionally move completed migration to a completed folder
+ # mkdir -p migrations/completed
+ # mv "$migration" "migrations/completed/"
+ else
+ echo "❌ Migration $migration failed"
+ exit 1
+ fi
+ else
+ echo "Migration file $migration not found, skipping..."
+ fi
+done
+
+echo "✅ All migrations completed"
\ No newline at end of file
diff --git a/src/app/admin/users/page.js b/src/app/admin/users/page.js
index 9c9f15c..364dbbb 100644
--- a/src/app/admin/users/page.js
+++ b/src/app/admin/users/page.js
@@ -125,6 +125,8 @@ export default function UserManagementPage() {
switch (role) {
case "admin":
return "red";
+ case "team_lead":
+ return "purple";
case "project_manager":
return "blue";
case "user":
@@ -140,6 +142,8 @@ export default function UserManagementPage() {
switch (role) {
case "project_manager":
return "Project Manager";
+ case "team_lead":
+ return "Team Lead";
case "read_only":
return "Read Only";
default:
@@ -433,6 +437,7 @@ function CreateUserModal({ onClose, onUserCreated }) {
+
diff --git a/src/lib/init-db.js b/src/lib/init-db.js
index 1ba1c79..47c9e3e 100644
--- a/src/lib/init-db.js
+++ b/src/lib/init-db.js
@@ -312,7 +312,7 @@ export default function initializeDatabase() {
name TEXT NOT NULL,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
- role TEXT CHECK(role IN ('admin', 'project_manager', 'user', 'read_only')) DEFAULT 'user',
+ role TEXT CHECK(role IN ('admin', 'team_lead', 'project_manager', 'user', 'read_only')) DEFAULT 'user',
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
is_active INTEGER DEFAULT 1,
diff --git a/src/lib/middleware/auth.js b/src/lib/middleware/auth.js
index 1d01a78..5efd9a2 100644
--- a/src/lib/middleware/auth.js
+++ b/src/lib/middleware/auth.js
@@ -3,7 +3,8 @@ import { NextResponse } from "next/server"
// Role hierarchy for permission checking
const ROLE_HIERARCHY = {
- 'admin': 4,
+ 'admin': 5,
+ 'team_lead': 4,
'project_manager': 3,
'user': 2,
'read_only': 1
diff --git a/src/lib/userManagement.js b/src/lib/userManagement.js
index 5adff8a..8cf9d82 100644
--- a/src/lib/userManagement.js
+++ b/src/lib/userManagement.js
@@ -53,7 +53,7 @@ export function getAllUsers() {
// Update user role
export function updateUserRole(userId, role) {
- const validRoles = ['admin', 'project_manager', 'user', 'read_only']
+ const validRoles = ['admin', 'team_lead', 'project_manager', 'user', 'read_only']
if (!validRoles.includes(role)) {
throw new Error("Invalid role")
}
@@ -159,7 +159,7 @@ export async function updateUser(userId, updates) {
}
if (updates.role !== undefined) {
- const validRoles = ['admin', 'project_manager', 'user', 'read_only'];
+ const validRoles = ['admin', 'team_lead', 'project_manager', 'user', 'read_only'];
if (!validRoles.includes(updates.role)) {
throw new Error("Invalid role");
}