- Implemented user tracking columns in project_tasks and notes tables. - Added created_by and assigned_to fields to project_tasks. - Introduced created_by field and is_system flag in notes. - Updated API endpoints to handle user tracking during task and note creation. - Enhanced database initialization to include new columns and indexes. - Created utility functions to fetch users for task assignment. - Updated front-end components to display user information for tasks and notes. - Added tests for project-tasks API endpoints to verify functionality.
27 KiB
Authorization Implementation Guide
Project Overview
This document outlines the implementation strategy for adding authentication and authorization to the Project Management Panel - a Next.js 15 application with SQLite database.
Current State Analysis (Updated: June 25, 2025)
✅ What We Have Implemented
- Framework: Next.js 15 with App Router
- Database: SQLite with better-sqlite3
- Authentication: NextAuth.js v5 with credentials provider
- User Management: Complete user CRUD operations with bcrypt password hashing
- Database Schema: Users table with roles, audit logs, sessions
- API Protection: Middleware system with role-based access control
- Session Management: JWT-based sessions with 30-day expiration
- Security Features: Account lockout, failed login tracking, password validation
- UI Components: Authentication provider, navigation with user context
- Auth Pages: Sign-in page implemented
✅ What's Protected
- API Routes: All major endpoints (projects, contracts, tasks, notes) are protected
- Role Hierarchy: admin > project_manager > user > read_only
- Navigation: Role-based menu items (admin sees user management)
- Session Security: Automatic session management and validation
🔄 Partially Implemented
- Auth Pages: Sign-in exists, missing sign-out and error pages
- User Interface: Basic auth integration, could use more polish
- Admin Features: User management backend exists, UI needs completion
- Audit Logging: Database schema exists, not fully integrated
❌ Still Missing
- Complete user management UI for admins
- Password reset functionality
- Rate limiting implementation
- Enhanced input validation schemas
- CSRF protection
- Security headers middleware
- Comprehensive error handling
- Email notifications
Recommended Implementation Strategy
1. Authentication Solution: NextAuth.js
Why NextAuth.js?
- ✅ Native Next.js 15 App Router support
- ✅ Database session management
- ✅ Built-in security features (CSRF, JWT handling)
- ✅ Flexible provider system
- ✅ SQLite adapter available
2. Role-Based Access Control (RBAC)
Proposed User Roles:
| Role | Permissions | Use Case |
|---|---|---|
| Admin | Full system access, user management | System administrators |
| Project Manager | Manage all projects/tasks, view reports | Team leads, supervisors |
| User | View/edit assigned projects/tasks | Regular employees |
| Read-only | View-only access to data | Clients, stakeholders |
Implementation Status
✅ Phase 1: Foundation Setup - COMPLETED
1.1 Dependencies - ✅ INSTALLED
- NextAuth.js v5 (beta)
- bcryptjs for password hashing
- Zod for validation
- Better-sqlite3 adapter compatibility
1.2 Environment Configuration - ✅ COMPLETED
.env.localconfigured with NEXTAUTH_SECRET and NEXTAUTH_URL- Database URL configuration
- Development environment setup
1.3 Database Schema - ✅ IMPLEMENTED
- Users table with roles and security features
- Sessions table for NextAuth.js
- Audit logs table for security tracking
- Proper indexes for performance
1.4 Initial Admin User - ✅ COMPLETED
scripts/create-admin.jsscript available- Default admin user: admin@localhost.com / admin123456
✅ Phase 2: Authentication Core - COMPLETED
2.1 NextAuth.js Configuration - ✅ IMPLEMENTED
- File:
src/lib/auth.js - Credentials provider with email/password
- JWT session strategy with 30-day expiration
- Account lockout after 5 failed attempts (15-minute lockout)
- Password verification with bcrypt
- Failed login attempt tracking
- Session callbacks for role management
2.2 API Route Handlers - ✅ IMPLEMENTED
- File:
src/app/api/auth/[...nextauth]/route.js - NextAuth.js handlers properly configured
2.3 User Management System - ✅ IMPLEMENTED
- File:
src/lib/userManagement.js - Complete CRUD operations for users
- Password hashing and validation
- Role management functions
- User lookup by ID and email
✅ Phase 3: Authorization Middleware - COMPLETED
3.1 API Protection Middleware - ✅ IMPLEMENTED
- File:
src/lib/middleware/auth.js withAuth()function for protecting routes- Role hierarchy enforcement (admin=4, project_manager=3, user=2, read_only=1)
- Helper functions:
withReadAuth,withUserAuth,withAdminAuth,withManagerAuth - Proper error handling and status codes
3.2 Protected API Routes - ✅ IMPLEMENTED
Example in src/app/api/projects/route.js:
- GET requests require read_only access
- POST requests require user access
- All major API endpoints are protected
3.3 Session Provider - ✅ IMPLEMENTED
- File:
src/components/auth/AuthProvider.js - NextAuth SessionProvider wrapper
- Integrated into root layout
🔄 Phase 4: User Interface - PARTIALLY COMPLETED
4.1 Authentication Pages - 🔄 PARTIAL
- ✅ Sign-in page:
src/app/auth/signin/page.js- Complete with form validation - ❌ Sign-out page: Missing
- 🔄 Error page:
src/app/auth/error/page.js- Basic implementation - ❌ Unauthorized page: Missing
4.2 Navigation Updates - ✅ COMPLETED
- File:
src/components/ui/Navigation.js - User session integration with useSession
- Role-based menu items (admin sees user management)
- Sign-out functionality
- Conditional rendering based on auth status
4.3 User Management Interface - ❌ MISSING
- Backend exists in userManagement.js
- Admin UI for user CRUD operations needed
- Role assignment interface needed
❌ Phase 5: Security Enhancements - NOT STARTED
5.1 Input Validation Schemas - ❌ MISSING
- Zod schemas for API endpoints
- Request validation middleware
5.2 Rate Limiting - ❌ MISSING
- Rate limiting middleware
- IP-based request tracking
5.3 Security Headers - ❌ MISSING
- CSRF protection
- Security headers middleware
- Content Security Policy
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { BetterSQLite3Adapter } from "@auth/better-sqlite3-adapter";
import db from "./db.js";
import bcrypt from "bcryptjs";
import { z } from "zod";
const loginSchema = z.object({
email: z.string().email("Invalid email format"),
password: z.string().min(6, "Password must be at least 6 characters"),
});
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: BetterSQLite3Adapter(db),
session: {
strategy: "database",
maxAge: 30 * 24 * 60 * 60, // 30 days
updateAge: 24 * 60 * 60, // 24 hours
},
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
try {
// Validate input
const validatedFields = loginSchema.parse(credentials);
// Check if user exists and is active
const user = db
.prepare(
`
SELECT id, email, name, password_hash, role, is_active,
failed_login_attempts, locked_until
FROM users
WHERE email = ? AND is_active = 1
`
)
.get(validatedFields.email);
if (!user) {
throw new Error("Invalid credentials");
}
// Check if account is locked
if (user.locked_until && new Date(user.locked_until) > new Date()) {
throw new Error("Account temporarily locked");
}
// Verify password
const isValidPassword = await bcrypt.compare(
validatedFields.password,
user.password_hash
);
if (!isValidPassword) {
// Increment failed attempts
db.prepare(
`
UPDATE users
SET failed_login_attempts = failed_login_attempts + 1,
locked_until = CASE
WHEN failed_login_attempts >= 4
THEN datetime('now', '+15 minutes')
ELSE locked_until
END
WHERE id = ?
`
).run(user.id);
throw new Error("Invalid credentials");
}
// Reset failed attempts and update last login
db.prepare(
`
UPDATE users
SET failed_login_attempts = 0,
locked_until = NULL,
last_login = CURRENT_TIMESTAMP
WHERE id = ?
`
).run(user.id);
// Log successful login
logAuditEvent(user.id, "LOGIN_SUCCESS", "user", user.id, req);
return {
id: user.id,
email: user.email,
name: user.name,
role: user.role,
};
} catch (error) {
console.error("Login error:", error);
return null;
}
},
}),
],
callbacks: {
async jwt({ token, user, account }) {
if (user) {
token.role = user.role;
token.userId = user.id;
}
return token;
},
async session({ session, token, user }) {
if (token) {
session.user.id = token.userId || token.sub;
session.user.role = token.role || user?.role;
}
return session;
},
async signIn({ user, account, profile, email, credentials }) {
// Additional sign-in logic if needed
return true;
},
},
pages: {
signIn: "/auth/signin",
signOut: "/auth/signout",
error: "/auth/error",
},
events: {
async signOut({ session, token }) {
if (session?.user?.id) {
logAuditEvent(session.user.id, "LOGOUT", "user", session.user.id);
}
},
},
});
// Audit logging helper
function logAuditEvent(userId, action, resourceType, resourceId, req = null) {
try {
db.prepare(
`
INSERT INTO audit_logs (user_id, action, resource_type, resource_id, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?, ?)
`
).run(
userId,
action,
resourceType,
resourceId,
req?.ip || "unknown",
req?.headers?.["user-agent"] || "unknown"
);
} catch (error) {
console.error("Audit log error:", error);
}
}
2.2 API Route Handlers
Create src/app/api/auth/[...nextauth]/route.js:
import { handlers } from "@/lib/auth";
export const { GET, POST } = handlers;
Phase 3: Authorization Middleware
3.1 API Protection Middleware
Create src/lib/middleware/auth.js:
import { auth } from "@/lib/auth";
import { NextResponse } from "next/server";
import { z } from "zod";
// Role hierarchy for permission checking
const ROLE_HIERARCHY = {
admin: 4,
project_manager: 3,
user: 2,
read_only: 1,
};
export function withAuth(handler, options = {}) {
return async (req, context) => {
try {
const session = await auth();
// Check if user is authenticated
if (!session?.user) {
return NextResponse.json(
{ error: "Authentication required" },
{ status: 401 }
);
}
// Check if user account is active
const user = db
.prepare("SELECT is_active FROM users WHERE id = ?")
.get(session.user.id);
if (!user?.is_active) {
return NextResponse.json(
{ error: "Account deactivated" },
{ status: 403 }
);
}
// Check role-based permissions
if (
options.requiredRole &&
!hasPermission(session.user.role, options.requiredRole)
) {
logAuditEvent(
session.user.id,
"ACCESS_DENIED",
options.resource || "api",
req.url
);
return NextResponse.json(
{ error: "Insufficient permissions" },
{ status: 403 }
);
}
// Check resource-specific permissions
if (options.checkResourceAccess) {
const hasAccess = await options.checkResourceAccess(
session.user,
context.params
);
if (!hasAccess) {
return NextResponse.json(
{ error: "Access denied to this resource" },
{ status: 403 }
);
}
}
// Validate request body if schema provided
if (
options.bodySchema &&
(req.method === "POST" ||
req.method === "PUT" ||
req.method === "PATCH")
) {
try {
const body = await req.json();
options.bodySchema.parse(body);
} catch (error) {
return NextResponse.json(
{ error: "Invalid request data", details: error.errors },
{ status: 400 }
);
}
}
// Add user info to request
req.user = session.user;
req.session = session;
// Call the original handler
return await handler(req, context);
} catch (error) {
console.error("Auth middleware error:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
};
}
export function hasPermission(userRole, requiredRole) {
return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];
}
// Helper for read-only operations
export function withReadAuth(handler) {
return withAuth(handler, { requiredRole: "read_only" });
}
// Helper for user-level operations
export function withUserAuth(handler) {
return withAuth(handler, { requiredRole: "user" });
}
// Helper for project manager operations
export function withManagerAuth(handler) {
return withAuth(handler, { requiredRole: "project_manager" });
}
// Helper for admin operations
export function withAdminAuth(handler) {
return withAuth(handler, { requiredRole: "admin" });
}
3.2 Client-Side Route Protection
Create src/components/auth/ProtectedRoute.js:
"use client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
export function ProtectedRoute({
children,
requiredRole = null,
fallback = null,
}) {
const { data: session, status } = useSession();
const router = useRouter();
useEffect(() => {
if (status === "loading") return; // Still loading
if (!session) {
router.push("/auth/signin");
return;
}
if (requiredRole && !hasPermission(session.user.role, requiredRole)) {
router.push("/unauthorized");
return;
}
}, [session, status, router, requiredRole]);
if (status === "loading") {
return (
<div className="flex justify-center items-center h-64">Loading...</div>
);
}
if (!session) {
return fallback || <div>Redirecting to login...</div>;
}
if (requiredRole && !hasPermission(session.user.role, requiredRole)) {
return fallback || <div>Access denied</div>;
}
return children;
}
function hasPermission(userRole, requiredRole) {
const roleHierarchy = {
admin: 4,
project_manager: 3,
user: 2,
read_only: 1,
};
return roleHierarchy[userRole] >= roleHierarchy[requiredRole];
}
Phase 4: User Interface Components
4.1 Authentication Pages
Pages to create:
src/app/auth/signin/page.js- Login formsrc/app/auth/signout/page.js- Logout confirmationsrc/app/auth/error/page.js- Error handlingsrc/app/unauthorized/page.js- Access denied page
4.2 Navigation Updates
Update src/components/ui/Navigation.js to include:
- Login/logout buttons
- User info display
- Role-based menu items
4.3 User Management Interface
For admin users:
- User listing and management
- Role assignment
- Account activation/deactivation
Phase 5: Security Enhancements
5.1 Input Validation Schemas
Create src/lib/schemas/ with Zod schemas for all API endpoints:
// src/lib/schemas/project.js
import { z } from "zod";
export const createProjectSchema = z.object({
contract_id: z.number().int().positive(),
project_name: z.string().min(1).max(255),
project_number: z.string().min(1).max(50),
address: z.string().optional(),
// ... other fields
});
export const updateProjectSchema = createProjectSchema.partial();
5.2 Rate Limiting
Implement rate limiting for sensitive endpoints:
// src/lib/middleware/rateLimit.js
const attempts = new Map();
export function withRateLimit(
handler,
options = { maxAttempts: 5, windowMs: 15 * 60 * 1000 }
) {
return async (req, context) => {
const key = req.ip || "unknown";
const now = Date.now();
const window = attempts.get(key) || {
count: 0,
resetTime: now + options.windowMs,
};
if (now > window.resetTime) {
window.count = 1;
window.resetTime = now + options.windowMs;
} else {
window.count++;
}
attempts.set(key, window);
if (window.count > options.maxAttempts) {
return NextResponse.json({ error: "Too many requests" }, { status: 429 });
}
return handler(req, context);
};
}
Implementation Checklist (Updated Status)
✅ Phase 1: Foundation - COMPLETED
- Install dependencies (NextAuth.js v5, bcryptjs, zod)
- Create environment configuration (.env.local)
- Extend database schema (users, sessions, audit_logs)
- Create initial admin user script
✅ Phase 2: Authentication - COMPLETED
- Configure NextAuth.js with credentials provider
- Create API route handlers (/api/auth/[...nextauth])
- Implement user management system
- Test login/logout functionality
✅ Phase 3: Authorization - COMPLETED
- Implement API middleware (withAuth, role hierarchy)
- Protect existing API routes (projects, contracts, tasks, notes)
- Create role-based helper functions
- Integrate session provider in app layout
🔄 Phase 4: User Interface - IN PROGRESS
- Create sign-in page with form validation
- Update navigation component with auth integration
- Add role-based menu items
- Create sign-out confirmation page
- Create error handling page
- Create unauthorized access page
- Build admin user management interface
❌ Phase 5: Security Enhancements - NOT STARTED
- Add input validation schemas to all endpoints
- Implement rate limiting for sensitive operations
- Add comprehensive audit logging
- Create security headers middleware
- Implement CSRF protection
- Add password reset functionality
Current Working Features
🔐 Authentication System
- Login/Logout: Fully functional with NextAuth.js
- Session Management: JWT-based with 30-day expiration
- Password Security: bcrypt hashing with salt rounds
- Account Lockout: 5 failed attempts = 15-minute lockout
- Role System: 4-tier hierarchy (admin, project_manager, user, read_only)
🛡️ Authorization System
- API Protection: All major endpoints require authentication
- Role-Based Access: Different permission levels per endpoint
- Middleware: Clean abstraction with helper functions
- Session Validation: Automatic session verification
📱 User Interface
- Navigation: Context-aware with user info and sign-out
- Auth Pages: Professional sign-in form with error handling
- Role Integration: Admin users see additional menu items
- Responsive: Works across device sizes
🗄️ Database Security
- User Management: Complete CRUD with proper validation
- Audit Schema: Ready for comprehensive logging
- Indexes: Optimized for performance
- Constraints: Role validation and data integrity
Next Priority Tasks
-
Complete Auth UI (High Priority)
- Sign-out confirmation page
- Unauthorized access page
- Enhanced error handling
-
Admin User Management (High Priority)
- User listing interface
- Create/edit user forms
- Role assignment controls
-
Security Enhancements (Medium Priority)
- Input validation schemas
- Rate limiting middleware
- Comprehensive audit logging
-
Password Management (Medium Priority)
- Password reset functionality
- Password strength requirements
- Password change interface
User Tracking in Projects - NEW FEATURE ✅
📊 Project User Management Implementation
We've successfully implemented comprehensive user tracking for projects:
Database Schema Updates ✅
- created_by: Tracks who created the project (user ID)
- assigned_to: Tracks who is assigned to work on the project (user ID)
- created_at: Timestamp when project was created
- updated_at: Timestamp when project was last modified
- Indexes: Performance optimized with proper foreign key indexes
API Enhancements ✅
- Enhanced Queries: Projects now include user names and emails via JOIN operations
- User Assignment: New
/api/projects/usersendpoint for user management - Query Filters: Support for filtering projects by assigned user or creator
- User Context: Create/update operations automatically capture authenticated user ID
UI Components ✅
- Project Form: User assignment dropdown in create/edit forms
- Project Listing: "Created By" and "Assigned To" columns in project table
- User Selection: Dropdown populated with active users for assignment
New Query Functions ✅
getAllUsersForAssignment(): Get active users for assignment dropdowngetProjectsByAssignedUser(userId): Filter projects by assigneegetProjectsByCreator(userId): Filter projects by creatorupdateProjectAssignment(projectId, userId): Update project assignment
Security Integration ✅
- Authentication Required: All user operations require valid session
- Role-Based Access: User assignment respects role hierarchy
- Audit Ready: Infrastructure prepared for comprehensive user action logging
Usage Examples
Creating Projects with User Tracking
// Projects are automatically assigned to the authenticated user as creator
POST /api/projects
{
"project_name": "New Project",
"assigned_to": "user-id-here", // Optional assignment
// ... other project data
}
Filtering Projects by User
// Get projects assigned to specific user
GET /api/projects?assigned_to=user-id
// Get projects created by specific user
GET /api/projects?created_by=user-id
Updating Project Assignment
POST /api/projects/users
{
"projectId": 123,
"assignedToUserId": "new-user-id"
}
Project Tasks User Tracking - NEW FEATURE ✅
📋 Task User Management Implementation
We've also implemented comprehensive user tracking for project tasks:
Database Schema Updates ✅
- created_by: Tracks who created the task (user ID)
- assigned_to: Tracks who is assigned to work on the task (user ID)
- created_at: Timestamp when task was created
- updated_at: Timestamp when task was last modified
- Indexes: Performance optimized with proper foreign key indexes
API Enhancements ✅
- Enhanced Queries: Tasks now include user names and emails via JOIN operations
- User Assignment: New
/api/project-tasks/usersendpoint for user management - Query Filters: Support for filtering tasks by assigned user or creator
- User Context: Create/update operations automatically capture authenticated user ID
UI Components ✅
- Task Form: User assignment dropdown in create task forms
- Task Listing: "Created By" and "Assigned To" columns in task table
- User Selection: Dropdown populated with active users for assignment
New Task Query Functions ✅
getAllUsersForTaskAssignment(): Get active users for assignment dropdowngetProjectTasksByAssignedUser(userId): Filter tasks by assigneegetProjectTasksByCreator(userId): Filter tasks by creatorupdateProjectTaskAssignment(taskId, userId): Update task assignment
Task Creation Behavior ✅
- Auto-assignment: Tasks are automatically assigned to the authenticated user as creator
- Optional Assignment: Users can assign tasks to other team members during creation
- Creator Tracking: All tasks track who created them for accountability
Task Usage Examples
Creating Tasks with User Tracking
// Tasks are automatically assigned to the authenticated user as creator
POST /api/project-tasks
{
"project_id": 123,
"task_template_id": 1, // or custom_task_name for custom tasks
"assigned_to": "user-id-here", // Optional, defaults to creator
"priority": "high"
}
Filtering Tasks by User
// Get tasks assigned to specific user
GET /api/project-tasks?assigned_to=user-id
// Get tasks created by specific user
GET /api/project-tasks?created_by=user-id
Updating Task Assignment
POST /api/project-tasks/users
{
"taskId": 456,
"assignedToUserId": "new-user-id"
}
Next Enhancements
-
Dashboard Views (Recommended)
- "My Projects" dashboard showing assigned projects
- Project creation history per user
- Workload distribution reports
-
Advanced Filtering (Future)
- Multi-user assignment support
- Team-based project assignments
- Role-based project visibility
-
Notifications (Future)
- Email alerts on project assignment
- Deadline reminders for assigned users
- Status change notifications
Notes User Tracking - NEW FEATURE ✅
📝 Notes User Management Implementation
We've also implemented comprehensive user tracking for all notes (both project notes and task notes):
Database Schema Updates ✅
- created_by: Tracks who created the note (user ID)
- is_system: Distinguishes between user notes and system-generated notes
- Enhanced queries: Notes now include user names and emails via JOIN operations
- Indexes: Performance optimized with proper indexes for user lookups
API Enhancements ✅
- User Context: All note creation operations automatically capture authenticated user ID
- System Notes: Automatic system notes (task status changes) track who made the change
- User Information: Note retrieval includes creator name and email for display
UI Components ✅
- Project Notes: Display creator name and email in project note listings
- Task Notes: Show who added each note with user badges and timestamps
- System Notes: Distinguished from user notes with special styling and "System" badge
- User Attribution: Clear indication of who created each note and when
New Note Query Functions ✅
getAllNotesWithUsers(): Get all notes with user and project/task contextgetNotesByCreator(userId): Filter notes by creator for user activity tracking- Enhanced
getNotesByProjectId()andgetNotesByTaskId()with user information
Automatic User Tracking ✅
- Note Creation: All new notes automatically record who created them
- System Notes: Task status changes generate system notes attributed to the user who made the change
- Audit Trail: Complete history of who added what notes and when
Notes Usage Examples
Project Notes with User Tracking
- Notes display creator name in a blue badge next to the timestamp
- Form automatically associates notes with the authenticated user
- Clear visual distinction between different note authors
Task Notes with User Tracking
- User notes show creator name in a gray badge
- System notes show "System" badge but also track the user who triggered the action
- Full audit trail of task status changes and who made them
System Note Generation
// When a user changes a task status, a system note is automatically created:
// "Status changed from 'pending' to 'in_progress'" - attributed to the user who made the change
Benefits
- Accountability: Full audit trail of who added what notes
- Context: Know who to contact for clarification on specific notes
- History: Track communication and decisions made by team members
- System Integration: Automatic notes for system actions still maintain user attribution
- User Experience: Clear visual indicators of note authors improve team collaboration