Codex 5.3 Refactor Note: Canonical refactor plan: docs/CODEX-5.3-REFACTOR-PLAN.md. This document is retained for historical and implementation context during the refactor.
W1 Implementation: Login
A. Summary
Implemented a complete login flow with email/password authentication, JWT token generation, role-based routing, and audit logging. Users can login and are redirected based on their role (HR/Manager/SMO → /dashboard, Admin → /admin/access-requests).
B. Routes Implemented
- GET /login – Login page with form
- POST /api/auth/login – Authentication endpoint
- GET /forgot-password – Stub page (coming soon)
- GET /request-access – Stub page (coming soon)
- GET /dashboard – User dashboard (stub)
- GET /admin/access-requests – Admin requests page (stub)
C. Data Model Changes
Prisma Schema Updates
Added to prisma/schema.prisma:
- enum Role – ADMIN, HR, MANAGER, SMO
- enum UserStatus – ACTIVE, INACTIVE, PENDING_APPROVAL
- enum AuditEventType – USER_LOGIN_SUCCESS, USER_LOGIN_FAILED (+ others for future wireframes)
- model User – id, email, passwordHash, role, status, createdAt, updatedAt
- model AuditLog – id, eventType, userId, details (JSON), createdAt
Migration Steps
cd /Users/rezafahmi/projectweb-nextjs
# Create .env.local with DATABASE_URL and JWT_SECRET
# Example:
# DATABASE_URL="postgresql://user:password@localhost:5432/offer_review"
# JWT_SECRET="your-secret-key"
# Initialize database
npx prisma migrate dev --name init
# Seed test data
npx prisma db seed
D. UI Components Created
Components
- src/components/LoginForm.tsx – Login form with email/password, client validation, error display, loading state
- src/app/login/page.tsx – Login page layout
- src/app/forgot-password/page.tsx – Stub (coming soon)
- src/app/request-access/page.tsx – Stub (coming soon)
- src/app/dashboard/page.tsx – User dashboard (stub)
- src/app/admin/access-requests/page.tsx – Admin dashboard (stub)
E. API Logic Created
Files
- src/app/api/auth/login/route.ts – POST /api/auth/login endpoint
- src/lib/auth.ts – JWT token generation, verification, cookie management
- src/lib/password.ts – Password hashing and verification
- src/lib/prisma.ts – Prisma client singleton
- src/lib/audit.ts – Audit logging helper
Endpoint Details
POST /api/auth/login
- Request:
{ email: string, password: string } - Response (Success):
Sets{ "success": true, "user": { "id": "...", "email": "...", "role": "ADMIN|HR|MANAGER|SMO" } }auth_tokenhttpOnly cookie (7 days expiry) - Response (Error):
- 400: Missing email/password
- 401: Invalid credentials or inactive user
- 403: Account pending approval or inactive
- 500: Server error
Flow
- Validate email/password format
- Query user by email
- Check user status (must be ACTIVE)
- Verify password hash
- Generate JWT token:
{ userId, email, role } - Set httpOnly secure cookie
- Log audit event (USER_LOGIN_SUCCESS or USER_LOGIN_FAILED)
- Return user data
F. RBAC Checks
Login Endpoint
- No authentication required
- Validates user exists in DB
- Validates user status = ACTIVE
- Invalid status returns 403 with appropriate message
Post-Login Routing
- HR/Manager/SMO roles →
/dashboard - ADMIN role →
/admin/access-requests
Audit Logging
- Successful login: USER_LOGIN_SUCCESS (logged with email)
- Failed login: USER_LOGIN_FAILED (logged with email + reason)
- Reasons: "User not found", "Invalid password", "User status is PENDING_APPROVAL", etc.
G. Audit Events
USER_LOGIN_SUCCESS
{
"eventType": "USER_LOGIN_SUCCESS",
"userId": "...",
"details": {
"email": "user@example.com"
}
}
USER_LOGIN_FAILED
{
"eventType": "USER_LOGIN_FAILED",
"userId": "... or unknown",
"details": {
"email": "user@example.com",
"reason": "Invalid password|User not found|User status is PENDING_APPROVAL|..."
}
}
H. Test Checklist
Setup
- Create
.env.localwith DATABASE_URL (PostgreSQL) and JWT_SECRET - Run
npx prisma migrate dev --name init - Run
npx prisma db seed(creates test users) - Run
npm run devto start development server
Test Users
- admin@example.com / admin123 (ADMIN role)
- hr@example.com / hr123 (HR role)
- manager@example.com / manager123 (MANAGER role)
- smo@example.com / smo123 (SMO role)
Manual Tests
- Navigate to
http://localhost:3000/login - Enter admin@example.com + admin123 → redirects to
/admin/access-requests - Enter hr@example.com + hr123 → redirects to
/dashboard - Enter invalid email → shows error "Invalid email or password"
- Enter wrong password → shows error "Invalid email or password"
- Enter non-existent email → shows error "Invalid email or password"
- Leave email/password empty → shows error "Email and password are required"
- Test loading state during login
- Verify browser cookies:
auth_tokenshould be httpOnly cookie - Click "Forgot password?" → navigates to
/forgot-password(stub page) - Click "Submit a registration request" → navigates to
/request-access(stub page) - Check database:
Usertable has all test users - Check database:
AuditLogtable logs USER_LOGIN_SUCCESS and USER_LOGIN_FAILED events
Database Verification
# Connect to Prisma Studio
npx prisma studio
# Or query directly
npx prisma db push # (if needed)
Next Steps (W2)
- Implement W2: Request Access form (allows public users to request account creation)
- Add email verification or approval workflow