User Management Feature
This document describes the user management feature implemented for administrators to manage users, their roles, and demographic information.
Overview
The user management feature provides administrators with the ability to:
- View all registered users with search and filtering
- Edit user roles (ADMIN, PREMIUM, FREE)
- Manage user demographic information
- Track user learning preferences and objectives
Architecture
Backend Components
1. Database Migration
File: backend/migrations/005_add_user_demographics.sql
Adds demographic fields to the users table:
| Field | Type | Description |
|---|---|---|
| first_name | VARCHAR(255) | User’s first name |
| last_name | VARCHAR(255) | User’s last name |
| gender | VARCHAR(50) | Options: male, female, non-binary, prefer-not-to-say, other |
| age_group | VARCHAR(50) | Options: 18-24, 25-34, 35-44, 45-54, 55-64, 65+ |
| location_country | VARCHAR(100) | User’s country |
| location_city | VARCHAR(100) | User’s city |
| timezone | VARCHAR(100) | User’s timezone |
| interests | JSONB | Array of interest strings |
| learning_objectives | JSONB | Array of learning goal strings |
| preferred_learning_style | VARCHAR(50) | Options: visual, reading, interactive, video |
| weekly_learning_hours | INTEGER | Target hours per week (1-40) |
| profile_completed | BOOLEAN | Whether profile is complete |
| onboarding_completed_at | TIMESTAMP | When onboarding was completed |
Constraints:
- Check constraints ensure valid enum values for gender, age_group, learning_style
- Weekly learning hours limited to 1-40
- Indexes added for common query patterns
2. Type Definitions
File: backend/shared/types/database.ts
export type Gender = 'male' | 'female' | 'non-binary' | 'prefer-not-to-say' | 'other';
export type AgeGroup = '18-24' | '25-34' | '35-44' | '45-54' | '55-64' | '65+';
export type LearningStyle = 'visual' | 'reading' | 'interactive' | 'video';
export interface User {
id: string;
cognito_sub: string;
email: string;
name: string;
first_name?: string;
last_name?: string;
role: UserRole;
avatar_url?: string;
gender?: Gender;
age_group?: AgeGroup;
location_country?: string;
location_city?: string;
timezone?: string;
interests?: string[];
learning_objectives?: string[];
preferred_learning_style?: LearningStyle;
weekly_learning_hours?: number;
profile_completed: boolean;
onboarding_completed_at?: Date;
created_at: Date;
updated_at: Date;
}
export interface UpdateUserDTO {
role?: UserRole;
gender?: Gender;
age_group?: AgeGroup;
location_country?: string;
location_city?: string;
timezone?: string;
interests?: string[];
learning_objectives?: string[];
preferred_learning_style?: LearningStyle;
weekly_learning_hours?: number;
profile_completed?: boolean;
}
export interface UserFilters {
search?: string;
role?: UserRole;
profile_completed?: boolean;
}
3. UserRepository
File: backend/shared/repositories/UserRepository.ts
Repository methods:
| Method | Description |
|---|---|
findAllWithFilters(limit, offset, filters) |
Get users with pagination and filters |
findByCognitoSub(cognitoSub) |
Find user by Cognito sub ID |
findByEmail(email) |
Find user by email address |
search(searchTerm, limit, offset, filters) |
Search users by name or email |
createUser(data) |
Create a new user |
updateUser(id, data) |
Update user demographics and role |
countByRole() |
Get user count grouped by role |
getTotalCount(filters) |
Get total user count with filters |
findByInterest(interest, limit, offset) |
Find users by interest (JSONB query) |
4. Users Lambda Function
Files: backend/functions/users/
Endpoints:
| Method | Path | Description |
|---|---|---|
| GET | /users | List users with search, filter, and pagination |
| PUT | /users?id={userId} | Update user role and demographics |
Query Parameters (GET):
id- Get specific user by IDsearch- Search by name or emailrole- Filter by role (ADMIN, PREMIUM, FREE)profile_completed- Filter by profile statuslimit- Results per page (default: 20, max: 100)offset- Pagination offset
Request Body (PUT):
{
"role": "PREMIUM",
"gender": "male",
"age_group": "25-34",
"location_country": "United States",
"location_city": "New York",
"timezone": "America/New_York",
"interests": ["Technology", "Business"],
"learning_objectives": ["Learn programming"],
"preferred_learning_style": "video",
"weekly_learning_hours": 5,
"profile_completed": true
}
Authentication: Admin-only access via Cognito JWT validation
5. Input Validation
File: backend/shared/utils/validation.ts
The validateUpdateUserInput function validates:
- Role must be ADMIN, PREMIUM, or FREE
- Gender must be a valid option
- Age group must be a valid range
- Location country/city max 100 characters
- Timezone max 100 characters
- Interests array max 20 items, each max 100 characters
- Learning objectives array max 20 items, each max 200 characters
- Learning style must be a valid option
- Weekly hours between 1-40
- Profile completed must be boolean
6. Terraform Configuration
Files:
infrastructure/terraform/lambda.tf- Users Lambda functioninfrastructure/terraform/api-gateway.tf- API Gateway /users endpoint
Frontend Components
1. Type Definitions
File: frontend/lib/api/types.ts
Mirrors backend types for TypeScript type safety.
2. API Client
File: frontend/lib/api/users.ts
// Get users with filters and pagination
getUsers(options: GetUsersOptions): Promise<UsersListResponse>
// Get single user by ID
getUser(id: string): Promise<User>
// Update user
updateUser(id: string, data: UpdateUserDTO): Promise<User>
// Search users
searchUsers(searchTerm: string, options?): Promise<UsersListResponse>
3. Admin Users List Page
File: frontend/app/admin/users/page.tsx
Features:
- Search users by name or email
- Filter by role (ADMIN, PREMIUM, FREE)
- Pagination
- User table with:
- Avatar/initials
- Name and email
- Role badge
- Profile completion status
- Location
- Join date
- Edit action
4. Admin User Edit Page
File: frontend/app/admin/users/[id]/edit/page.tsx
Sections:
- User Information: Read-only display of email, name, Cognito sub, dates
- Role & Status: Role dropdown, profile completion checkbox
- Demographics: Gender, age group dropdowns
- Location: Country, city, timezone inputs
- Learning Preferences:
- Preferred learning style dropdown
- Weekly learning hours input
- Interests (comma-separated)
- Learning objectives (comma-separated)
5. Admin Dashboard
File: frontend/app/admin/page.tsx
Updated to display user count in the Users card.
Testing
Test Files
backend/__tests__/repositories/UserRepository.test.ts- 52 testsbackend/shared/utils/__tests__/user-validation.test.ts- 77 tests
Running Tests
cd backend
# Run all user management tests
npx jest __tests__/repositories/UserRepository.test.ts shared/utils/__tests__/user-validation.test.ts
# Run with coverage
npx jest __tests__/repositories/UserRepository.test.ts shared/utils/__tests__/user-validation.test.ts --coverage
Test Coverage
- UserRepository.ts: 100% statement coverage
- Total Tests: 129 passing
Deployment
Prerequisites
- AWS credentials configured
- Terraform installed
- Node.js 20.x
Steps
- Build the Lambda function:
cd backend/functions/users npm install npm run build - Run the database migration:
-- Execute against your PostgreSQL database \i backend/migrations/005_add_user_demographics.sql - Deploy infrastructure:
cd infrastructure/terraform terraform plan terraform apply - Deploy frontend: Push to main branch to trigger Amplify deployment.
API Usage Examples
List Users
curl -X GET "https://api.example.com/dev/users?limit=20&offset=0" \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Search Users
curl -X GET "https://api.example.com/dev/users?search=john&role=FREE" \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Get Single User
curl -X GET "https://api.example.com/dev/users?id=USER_ID" \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Update User
curl -X PUT "https://api.example.com/dev/users?id=USER_ID" \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "PREMIUM",
"gender": "male",
"age_group": "25-34"
}'
Security Considerations
- Admin-only access: All endpoints require admin role verification
- Input validation: All inputs validated and sanitized
- SQL injection prevention: Parameterized queries and field whitelisting
- XSS prevention: String sanitization removes HTML tags
- Audit logging: Admin actions logged for auditing
Future Enhancements
- Add bulk user operations (import/export)
- Add user activity history view
- Add user statistics and analytics
- Add email notifications for role changes
- Add user profile image upload
- Add user notes/comments for admins