A full-stack serverless note-taking application built with Serverless Framework, AWS, React, and Node.js. This application allows users to create, update, delete, and manage notes with authentication, file attachments, and a modern, scalable architecture.
Application Name: WingNote Tech Stack: React, Node.js, AWS Lambda, DynamoDB, Cognito, S3
- Project Overview
- Architecture
- Real Folder Structure
- Key Files & Their Purpose
- Prerequisites & System Requirements
- Complete AWS Setup Guide
- Step-by-Step Installation
- Configuration in Detail
- How to Start the Application
- Deployment to AWS
- Application Features & Routes
- Troubleshooting Guide
- Development Commands
WingNote is a serverless note-taking application with the following features:
✅ User Authentication - Sign up, login, password reset, change email & password ✅ Create & Manage Notes - Create, edit, delete, and organize notes ✅ File Attachments - Upload and download files with notes ✅ User Settings - Update profile information and credentials ✅ Dark Mode - Toggle between light and dark themes ✅ Responsive Design - Works on desktop, tablet, and mobile
✅ Serverless Architecture - No servers to manage ✅ Auto-Scaling - Automatic scaling based on demand ✅ Cost-Efficient - Pay only for what you use ✅ Secure Authentication - AWS Cognito with JWT tokens ✅ Cloud Storage - Files stored in AWS S3 ✅ Reliable Database - AWS DynamoDB with built-in redundancy
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React) │
│ serverless-stack-client/src/ │
│ - Home, Login, Signup, Notes, Settings, Profile Management │
└────────────────────────────┬────────────────────────────────────┘
│
┌────────▼────────┐
│ AWS Amplify │
│ (Authentication)
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌───▼────┐ ┌──────▼──────┐ ┌─────▼─────┐
│ Cognito│ │ API Gateway│ │ CloudFront│
│(Auth) │ │ (REST API) │ │ (CDN) │
└────────┘ └──────┬──────┘ └───────────┘
│
┌───────────────┼───────────────┐
│ │ │
┌────▼────┐ ┌──────▼──────┐ ┌────▼─────┐
│ Lambda │ │ DynamoDB │ │ S3 │
│(Compute)│ │ (Database) │ │(Storage) │
└─────────┘ └─────────────┘ └──────────┘
wingnote/
├── README.md ← You are here
│
├── serverless-stack-api/ # BACKEND FOLDER
│ ├── README.md # Backend documentation
│ ├── notes-api/ # API implementation
│ │ ├── handler.js # Lambda function handlers
│ │ ├── serverless.yml # AWS resource configuration
│ │ ├── package.json # Backend dependencies
│ │ ├── package-lock.json # Locked versions
│ │ ├── env.example # Example environment variables
│ │ ├── LICENSE # MIT License
│ │ ├── .gitignore # Git ignore rules
│ │ └── tests/
│ │ └── handler.test.js # Unit tests for Lambda
│ └── node_modules/ # Installed dependencies
│
└── serverless-stack-client/ # FRONTEND FOLDER
├── README.md # Frontend documentation
├── package.json # React dependencies
├── package-lock.json # Locked versions
│
├── public/ # Static files
│ ├── index.html # HTML entry point
│ ├── favicon.ico # Website icon
│ ├── manifest.json # PWA manifest
│ ├── style.css # Global styles
│ ├── _redirects # URL routing for deployment
│ ├── robots.txt # SEO configuration
│ ├── browserconfig.xml # Windows tile config
│ ├── site.webmanifest # Web app manifest
│ └── [favicon images] # Various app icons
│
├── src/ # React source code
│ ├── index.js # React entry point
│ ├── App.js # Main App component
│ ├── Routes.js # Route definitions
│ ├── config.js # AWS configuration
│ ├── App.css # App styles
│ ├── index.css # Global styles
│ ├── setupTests.js # Jest test setup
│ ├── reportWebVitals.js # Performance metrics
│ ├── App.test.js # App component tests
│ │
│ ├── components/ # Reusable UI components
│ │ ├── AuthenticatedRoute.js # Protected route wrapper
│ │ ├── UnauthenticatedRoute.js # Public route wrapper
│ │ ├── LoaderButton.js # Loading button component
│ │ └── LoaderButton.css # Button styles
│ │
│ ├── containers/ # Page-level components
│ │ ├── Home.js # Landing page
│ │ ├── Login.js # User login page
│ │ ├── Signup.js # User registration page
│ │ ├── Notes.js # View/edit single note
│ │ ├── NewNote.js # Create new note
│ │ ├── Settings.js # User settings page
│ │ ├── ChangePassword.js # Change password page
│ │ ├── ChangeEmail.js # Change email page
│ │ ├── ResetPassword.js # Password reset page
│ │ ├── NotFound.js # 404 error page
│ │ ├── [container-specific CSS files] # Component styling
│ │ └── image/ # Background & UI images
│ │
│ └── libs/ # Helper functions
│ ├── awsLib.js # AWS Amplify utilities (S3 upload)
│ ├── contextLib.js # React context helpers
│ ├── errorLib.js # Error handling utilities
│ └── hooksLib.js # Custom React hooks
│
└── node_modules/ # Installed dependencies
| File | Purpose |
|---|---|
handler.js |
Defines Lambda function handlers for API endpoints |
serverless.yml |
Infrastructure as Code - defines AWS resources (Lambda, DynamoDB, S3, etc.) |
package.json |
Lists backend dependencies (serverless plugins, aws-sdk, etc.) |
env.example |
Template for environment variables (copy to .env) |
tests/handler.test.js |
Unit tests for Lambda functions |
| File | Purpose |
|---|---|
App.js |
Main React component, handles authentication & navigation |
Routes.js |
Defines all application routes/pages |
config.js |
CRITICAL - AWS credentials and API endpoint configuration |
index.js |
React app entry point |
components/ |
Reusable UI components (buttons, route wrappers, etc.) |
containers/ |
Full page components (Login, Notes, Settings, etc.) |
libs/ |
Helper functions (AWS operations, error handling, hooks) |
public/index.html |
HTML page template |
config.js- Contains AWS credentials, API URL, S3 bucket, Cognito IDs⚠️ SECURITY: Never commit this with real credentials.env- Backend environment variables (should be in.gitignore)serverless.yml- AWS resource definitions
-
Node.js & npm
- Download: https://nodejs.org/
- Version: Node.js 18.x or higher
- npm: 8.x or higher (comes with Node.js)
-
Git
- Download: https://git-scm.com/
- Used for cloning repository and version control
-
AWS Account
- Sign up: https://aws.amazon.com/
- Required for all AWS services
-
AWS CLI (Recommended)
- Install:
pip install awscli --upgrade --user - Used for managing AWS resources from terminal
- Install:
-
Serverless Framework
- Will install with:
npm install -g serverless - Required for deploying to AWS
- Will install with:
# Check Node.js version (should be v18 or higher)
node --version
# Output: v18.x.x or higher
# Check npm version
npm --version
# Output: 8.x.x or higher
# Check Git
git --version
# Output: git version 2.x or higherThis section walks you through setting up all AWS services needed for WingNote.
- Go to https://aws.amazon.com/
- Click "Create an AWS Account"
- Enter your email and password
- Add payment information
- Complete verification
- Log in to AWS Console: https://console.aws.amazon.com/
Why? You need special credentials for Serverless Framework to deploy your app.
Steps:
- Go to AWS Console → Search "IAM" → Click "Users"
- Click "Create user" button
- User name:
serverless-deployer - ✅ Check "Provide user console access"
- Click "Next"
- Click "Attach policies directly"
- Search and select these policies:
- ✅
AdministratorAccess(easiest) - OR manually select:
AWSLambdaFullAccessAmazonAPIGatewayAdministratorAmazonDynamoDBFullAccessAmazonS3FullAccessAWSCloudFormationFullAccessIAMFullAccessAmazonCognitoPowerUser
- ✅
- Click "Create user"
- Click on your new user
- Go to "Security credentials" tab
- Click "Create access key"
- Choose "Command Line Interface (CLI)"
- ✅ Accept the warning
- Click "Create access key"
- SAVE THESE SECURELY:
- Access Key ID:
AKIAXXXXXXXXXX - Secret Access Key:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- Access Key ID:
Option A: Using AWS CLI (Recommended)
# Install AWS CLI
pip install awscli --upgrade --user
# Configure credentials
aws configure
# When prompted, enter:
# AWS Access Key ID: [paste your Access Key ID]
# AWS Secret Access Key: [paste your Secret Access Key]
# Default region name: us-east-1
# Default output format: jsonOption B: Using Environment Variables
# Linux/Mac
export AWS_ACCESS_KEY_ID=your_access_key_id
export AWS_SECRET_ACCESS_KEY=your_secret_access_key
export AWS_DEFAULT_REGION=us-east-1
# Windows (PowerShell)
$env:AWS_ACCESS_KEY_ID="your_access_key_id"
$env:AWS_SECRET_ACCESS_KEY="your_secret_access_key"
$env:AWS_DEFAULT_REGION="us-east-1"Users will upload note attachments to S3.
# Create bucket with unique name
aws s3 mb s3://wingnote-bucket-$(date +%s) --region us-east-1
# Remember the bucket name for later!Or through AWS Console:
- Go to S3 service
- Click "Create bucket"
- Bucket name:
wingnote-mybucket(must be globally unique) - Region:
us-east-1 - ✅ Block all public access
- Create bucket
Cognito handles user sign-up, login, password reset, etc.
- Go to AWS Console → Search "Cognito"
- Click "Create user pool"
- Configure sign-in:
- ✅ Username
- Click "Next step"
- Password policy: Default is fine
- MFA: "No MFA" for testing
- Click through remaining steps
- Pool name:
wingnote-users - Click "Create pool"
- Click on your new pool
- Look for "User pool ID" at the top
- Copy it (format:
us-east-1_xxxxx)
- Still in User Pool → "App integration" → "App clients and analytics"
- Click "Create app client"
- App client name:
wingnote-web - ✅ Don't generate client secret (for web apps)
- Scroll down and click "Create app client"
- Click on your app client
- Copy "Client ID" (format:
xxxxxxxxxxxxx)
- Go back to Cognito main page
- Click "Create identity pool"
- Pool name:
wingnote-identity - ✅ Enable access to unauthenticated identities
- Create pool
- Skip "Configure IAM roles" for now
- Copy "Identity pool ID" (format:
us-east-1:xxxxxxxxxxxxx)
Note: Serverless.yml might create this automatically, but you can pre-create it.
Through AWS Console:
- Go to AWS Console → Search "DynamoDB"
- Click "Create table"
- Table name:
notes - Partition key:
userId(String) - Sort key:
noteId(String) - Billing mode: "On-demand"
- Create table
# If you need to clone (skip if you already have it)
git clone <your-repo-url>
cd wingnote
# Or navigate to existing folder
cd /path/to/wingnote# Install Serverless Framework globally
npm install -g serverless
# Verify installation
serverless --version
# Configure Serverless with AWS credentials
serverless config credentials --provider aws \
--key YOUR_ACCESS_KEY_ID \
--secret YOUR_SECRET_ACCESS_KEY \
--region us-east-1# Navigate to backend
cd serverless-stack-api
# Install backend root dependencies
npm install
# Navigate to notes-api
cd notes-api
# Install API dependencies
npm install
# Go back to root
cd ../..# Navigate to frontend
cd serverless-stack-client
# Install React dependencies
npm install
# Go back to root
cd ..# Check if all dependencies are installed
ls -la serverless-stack-api/node_modules | head -10
ls -la serverless-stack-client/node_modules | head -10
# Verify Serverless
serverless --version# Navigate to backend API folder
cd serverless-stack-api/notes-api
# Create .env file based on example
cat > .env << 'EOF'
# AWS Region (keep this same everywhere)
AWS_REGION=us-east-1
# Your AWS Credentials (from IAM user)
AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY
# DynamoDB Configuration
DYNAMODB_TABLE=notes
DYNAMODB_REGION=us-east-1
# S3 Configuration (bucket you created)
S3_BUCKET=wingnote-bucket-xxxxx
S3_REGION=us-east-1
# Cognito Configuration (from User Pool)
COGNITO_USER_POOL_ID=us-east-1_xxxxxx
# Stage (dev, staging, or prod)
STAGE=dev
EOF
# Keep this file private - never commit it!
cat >> .gitignore << EOF
.env
EOFOpen serverless-stack-api/notes-api/serverless.yml and verify:
service: notes-api
provider:
name: aws
runtime: nodejs18.x
stage: ${opt:stage, 'dev'}
region: ${opt:region, 'us-east-1'}
# Environment variables for Lambda
environment:
STAGE: ${self:provider.stage}
DYNAMODB_TABLE: notes
S3_BUCKET: ${env:S3_BUCKET}
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
resources:
Resources:
# DynamoDB Table will be defined here
# S3 Bucket references will be hereOpen serverless-stack-client/src/config.js and update with YOUR AWS details:
// Get these values from AWS Cognito and your created S3 bucket
const config = {
// Maximum file size allowed (5MB)
MAX_ATTACHMENT_SIZE: 5000000,
// S3 Configuration - For storing files
s3: {
REGION: "us-east-1",
BUCKET: "wingnote-bucket-xxxxx", // ← YOUR S3 BUCKET NAME
},
// API Gateway - Your backend API endpoint
apiGateway: {
REGION: "us-east-1",
URL: "http://localhost:3000", // ← Change after deployment
},
// Cognito - For user authentication
cognito: {
REGION: "us-east-1",
USER_POOL_ID: "us-east-1_xxxxxx", // ← Your User Pool ID
APP_CLIENT_ID: "xxxxxxxxxxxxx", // ← Your App Client ID
IDENTITY_POOL_ID: "us-east-1:xxxxxxxx", // ← Your Identity Pool ID
},
};
export default config;Where to Find These Values:
| Config Value | Where to Find | How to Find |
|---|---|---|
BUCKET |
S3 Console | Services → S3 → Your bucket name |
USER_POOL_ID |
Cognito Console | Services → Cognito → User pools → Your pool → Pool ID (top) |
APP_CLIENT_ID |
Cognito Console | Cognito → App integration → App clients and analytics → Select your client |
IDENTITY_POOL_ID |
Cognito Console | Cognito → Identity pools → Your pool → Edit identity pool |
apiGateway.URL |
API Gateway | Services → API Gateway → Your API → Stages → Copy "Invoke URL" |
You need 2-3 terminal windows open!
# From project root
cd serverless-stack-api/notes-api
# Start Serverless offline
npm install -g serverless-offline # If not installed
serverless offline start
# You should see:
# [output] offline listening on http://localhost:3000# From project root
cd serverless-stack-client
# Start React development server
npm start
# Browser will open at http://localhost:3000
# Click "Signup" to create an account# Monitor backend logs
cd serverless-stack-api/notes-api
serverless logs -f hello- Visit Homepage: http://localhost:3000
- Signup: Create new account with email/password
- Login: Log in with your credentials
- Create Note: Click "New Note" button
- Edit Note: Click on a note to edit
- Upload File: Attach a file to a note
- Settings: Change password or email
- Logout: Click logout
# Navigate to backend
cd serverless-stack-api/notes-api
# Deploy to AWS
serverless deploy
# You'll see output like:
# endpoints:
# GET - https://xxxxx.execute-api.us-east-1.amazonaws.com/dev/helloCopy the API URL! You'll need it in the next step.
# Edit config.js
nano serverless-stack-client/src/config.js
# Update this line:
apiGateway: {
REGION: "us-east-1",
URL: "https://xxxxx.execute-api.us-east-1.amazonaws.com/dev", // ← Paste your API URL
},cd serverless-stack-client
# Create production build
npm run build
# Output: build/ folder with optimized files# Deploy to S3
aws s3 sync ./build s3://wingnote-bucket-xxxxx --delete
# Access via: http://wingnote-bucket-xxxxx.s3.amazonaws.comFor production, use CloudFront for faster access:
- AWS Console → CloudFront
- Create distribution
- Origin: Your S3 bucket
- Default root object:
index.html - Create
| Route | Component | What It Does |
|---|---|---|
/ |
Home | Landing page / Dashboard |
/Signup |
Signup | Create new account |
/Login |
Login | Log in to account |
/ResetPassword |
ResetPassword | Reset forgotten password |
/Notes/New |
NewNote | Create new note |
/Notes/:id |
Notes | View and edit single note |
/Settings |
Settings | View settings |
/settings/password |
ChangePassword | Change account password |
/settings/email |
ChangeEmail | Change email address |
App.js (Main Component)
├── Navbar (Navigation with Login/Logout)
├── Routes.js (Route definitions)
│ ├── AuthenticatedRoute (Protected routes)
│ │ ├── NewNote
│ │ ├── Notes
│ │ ├── Settings
│ │ ├── ChangePassword
│ │ └── ChangeEmail
│ └── UnauthenticatedRoute (Public routes)
│ ├── Home
│ ├── Login
│ ├── Signup
│ └── ResetPassword
└── AppContext (Authentication state)
└── Used by all components
# Node.js not installed
# Solution: Download from https://nodejs.org/
# After installing, restart terminal and try again
node --version # Should show v18.x# Solution: Install globally
npm install -g serverless
# Restart terminal
serverless --versioncd serverless-stack-api/notes-api
npm install aws-sdk
npm install# Solution A: Kill the process
lsof -i :3000
kill -9 <PID>
# Solution B: Use different port
PORT=3001 npm start- Check
config.jshas correct User Pool ID - Check
config.jshas correct App Client ID - Verify credentials in AWS Cognito console
- Ensure you created Cognito User Pool
# Create bucket
aws s3 mb s3://wingnote-mybucket --region us-east-1
# Update bucket name in config.js- Verify API URL in
config.js - Check if backend is running
- Check CORS settings in
serverless.yml - Verify API Gateway is deployed
- Check S3 bucket exists
- Verify bucket name in
config.js - Check IAM permissions for S3
- Ensure file size < 5MB
- Check internet connection
- Verify Cognito credentials
- Check if user pool exists
- Check app client settings
# Verify DynamoDB table exists
aws dynamodb list-tables --region us-east-1
# Create table if missing
aws dynamodb create-table \
--table-name notes \
--attribute-definitions AttributeName=userId,AttributeType=S AttributeName=noteId,AttributeType=S \
--key-schema AttributeName=userId,KeyType=HASH AttributeName=noteId,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST# Check AWS credentials
aws sts get-caller-identity
# View backend logs
cd serverless-stack-api/notes-api
serverless logs -f hello
# Test API endpoint
curl -X GET http://localhost:3000/hello
# Check what's running on port 3000
lsof -i :3000
# Clear npm cache
npm cache clean --force
npm install
# Reinstall all dependencies
rm -rf node_modules package-lock.json
npm installcd serverless-stack-api/notes-api
# Install dependencies
npm install
# Start local development server
serverless offline start
# or
npm start
# Run tests
npm test
# Deploy to AWS
serverless deploy
# Deploy function only (faster)
serverless deploy function -f hello
# Remove from AWS
serverless remove
# View logs
serverless logs -f hello -tcd serverless-stack-client
# Install dependencies
npm install
# Start development server
npm start
# Run tests
npm test
# Create production build
npm run build
# Eject configuration (NOT recommended)
npm run eject# Configure credentials
aws configure
# List S3 buckets
aws s3 ls
# Upload to S3
aws s3 sync ./build s3://your-bucket --delete
# List DynamoDB tables
aws dynamodb list-tables --region us-east-1
# View CloudFormation stacks
aws cloudformation list-stacks --region us-east-1- Serverless Framework: https://www.serverless.com/
- AWS Documentation: https://docs.aws.amazon.com/
- React Documentation: https://react.dev/
- AWS Amplify: https://docs.amplify.aws/
- Cognito Guide: https://docs.aws.amazon.com/cognito/
- DynamoDB: https://docs.aws.amazon.com/dynamodb/
- Lambda: https://docs.aws.amazon.com/lambda/
Frontend config: serverless-stack-client/src/config.js
Backend config: serverless-stack-api/notes-api/serverless.yml
Environment vars: serverless-stack-api/notes-api/.env
Frontend code: serverless-stack-client/src/
Backend code: serverless-stack-api/notes-api/handler.js
Frontend dependencies: serverless-stack-client/package.json
Backend dependencies: serverless-stack-api/notes-api/package.json
✅ Save these securely (never share or commit):
- AWS Access Key ID
- AWS Secret Access Key
- Cognito User Pool ID
- Cognito App Client ID
- Cognito Identity Pool ID
- S3 Bucket Name
❌ Never commit these files:
.envfileconfig.jswith real credentials- AWS credentials in code
Created: February 2024 Last Updated: February 2024 Version: 1.0.0 - Complete Setup Guide
For detailed backend documentation, see serverless-stack-api/README.md For detailed frontend documentation, see serverless-stack-client/README.md