A lightweight team task-management web application built on AWS, supporting multiple teams with role-based access, event-driven notifications, and high-availability deployment.
CloudFront URL: https://d3k1jgfrlsvmw1.cloudfront.net/login
Click the link above to open the live application directly. No additional configuration required.
Demo Video URL: https://drive.google.com/drive/folders/1mja5fiqRuUdJjiUO2lypZN7IS1otZnZH?usp=sharing
Checkout the Demo video through this link.
Upnext AWS Architecture Diagram: https://drive.google.com/drive/folders/1M4CHejSCD-P-5m-jHls5dZYgElUUDVkK?usp=drive_link
The system is deployed in a high-availability setup across two Availability Zones in eu-central-1, fronted by an Application Load Balancer and CloudFront.
| Layer | Technology |
|---|---|
| Frontend | React + Tailwind CSS + shadcn/ui |
| Backend | Node.js + Express.js |
| Database | AWS DynamoDB |
| Authentication | AWS Cognito |
| Image Storage | AWS S3 |
| Hosting | AWS EC2 + ALB + CloudFront |
| Service | Role in the System |
|---|---|
| EC2 (Auto Scaling Group) | Hosts the Node.js backend across 2 Availability Zones |
| Application Load Balancer | Distributes traffic across EC2 instances and runs health checks |
| CloudFront | CDN in front of the ALB for low-latency delivery of the app and static assets |
| DynamoDB | Stores Users, Teams, Projects, Tasks, Comments, Activity Log, Audit Log. GSIs on teamId and assigneeId |
| S3 (originals bucket) | Stores task image attachments uploaded by users. Old versions retained on update |
| S3 (resized bucket) | Stores thumbnails generated by the image-resize Lambda |
| Lambda — Image Resize | Triggered by S3 PUT events on the originals bucket. Writes thumbnails to the resized bucket |
| Lambda — Assignment Worker | Drains the SQS queue, writes activity logs, publishes CloudWatch custom metrics |
| Lambda — Daily Digest | Triggered by EventBridge at 9:00 AM. Scans tasks due today and sends digest emails via SNS |
| SNS | Fan-out for task-assignment events: notifies the assignee by email and feeds the SQS queue |
| SQS | Buffers assignment events for the worker Lambda. Decouples the API from background processing |
| EventBridge | Scheduled rule that triggers the daily digest Lambda every day at 9:00 AM |
| Cognito | User pool for sign-up/sign-in. Stores role and teamId as user attributes |
| CloudWatch | Custom metrics, dashboard (4 widgets), and alarms |
| IAM | Least-privilege roles for EC2, each Lambda, and the application identity |
| VPC + Subnets | Public subnets for the ALB; private subnets for EC2; NAT Gateway for outbound traffic |
| Name | Password | Role | Team | |
|---|---|---|---|---|
| Farida | admin@upnext.com | Password123! | Admin | — |
| Ali | ali@upnext.com | Password123! | Manager | — |
| Sara | sara@upnext.com | Password123! | Employee | Frontend |
| Omar | omar@upnext.com | Password123! | Employee | Backend |
| Farida | farida@upnext.com | Password123! | Employee | Backend |
When a manager assigns a task:
Backend (EC2) → SNS Topic
├──→ Email notification to assignee
└──→ SQS Queue → Worker Lambda
├──→ Activity log saved to DynamoDB
└──→ CloudWatch metric published (TasksAssigned)
Every day at 9:00 AM:
EventBridge → Daily Digest Lambda → Scans DynamoDB for tasks due today → SNS → Email digest
Dashboard name: UpNext-Dashboard
| Widget | Metric |
|---|---|
| Tasks Assigned | Custom metric: TasksAssigned (UpNext namespace) |
| Lambda Invocations | AWS/Lambda Invocations |
| SQS Messages Sent | AWS/SQS NumberOfMessagesSent |
| Lambda Errors | AWS/Lambda Errors |
| Tasks created per day | tasks created per day |
| Average time to close | TimeToClose |
| Tasks closed per day per team | TasksClosed |
| CPUUtilization | CPUUtilization |
Alarm: UpNext-Lambda-Error-Alarm — triggers when Lambda errors > 0, publishes to SNS.
Alarm : upnext-overdue-tasks-alarm — triggers when OverdueTasks >= 1 for 1 datapoints within 5 minutes
- Node.js v18+
- AWS credentials configured
.envfile set up (see below)
cd backend
npm install
npm run devcd frontend
npm install
npm run devCreate a .env file in the backend/ directory:
PORT=
NODE_ENV=
AWS_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
COGNITO_USER_POOL_ID=
COGNITO_APP_CLIENT_ID=
COGNITO_CLIENT_ID =
USERS_TABLE=
TEAMS_TABLE=
PROJECTS_TABLE=
TASKS_TABLE=
COMMENTS_TABLE=
ACTIVITY_LOG_TABLE=
AUDIT_LOG_TABLE=
ORIGINAL_IMAGES_BUCKET=
RESIZED_IMAGES_BUCKET=
TASK_ASSIGNED_TOPIC_ARN=
TASK_ASSIGNMENT_QUEUE_URL=