Skip to content

PMafra/notes-taking

Repository files navigation

Notes-Taking App

CI

A modern, full-stack note-taking application built with Django REST Framework and Next.js. Features AWS Cognito authentication, category-based organization, and production deployment infrastructure using Terraform.

Live Demo: https://diic9tcw9xmrs.cloudfront.net/notes/


✅ Required Features Checklist

Authentication

  • Sign up screen with email and password inputs
  • Password visibility toggle on signup
  • Link to navigate to login if user already has an account
  • Login screen with email and password inputs
  • Sign out functionality

Initial Experience

  • Empty state when user has no notes (illustration + message)
  • Auto-created categories visible: Random Thoughts, School, Personal
  • Option to create a new note from the initial state

Notes Creation

  • Create new note by clicking "New note" icon/button
  • Automatic note creation (no manual save action required)

Note Structure and Editing

  • Note includes: Title, Content, Category, Last edited timestamp
  • Last edited timestamp updates automatically as user writes/edits
  • User can change a note's category
  • Note background color changes when category changes
  • User can close the note editor and return to notes list

Notes List and Filtering

  • Notes list screen with left sidebar showing categories
  • Each category displays: color, title, number of notes
  • Clicking a category filters the list to show only notes in that category
  • "All Categories" option shows all notes

Notes Preview Cards

  • Notes displayed as preview cards in the list
  • Each card includes: last edited date, category name, title, content preview
  • Content truncation when content doesn't fit in the card

Date Formatting

  • "Today" displayed if note was edited today
  • "Yesterday" displayed if edited yesterday
  • Month + day format (e.g., "Jan 26") for older notes

Editing Existing Notes

  • Clicking an existing note opens it for editing
  • Can edit title by clicking into text
  • Can edit content by clicking into text
  • Can change category via dropdown

⭐ Additional Features Implemented

Deployment & Infrastructure

  • Live Production Deployment on AWS (Free Tier)
  • AWS ECR + ECS + ALB for backend containerized deployment
  • AWS RDS PostgreSQL for managed database with Secrets Manager
  • AWS S3 + CloudFront for frontend static hosting with CDN
  • AWS Cognito + Lambda for authentication (auto-confirm without email verification)
  • Terraform Infrastructure as Code - All resources managed via Terraform

Authentication Enhancements

  • AWS Cognito integration with JWT validation
  • Auto sign-in after successful signup
  • Lambda trigger for instant user confirmation (no email verification delay)
  • Secure token refresh via AWS Amplify

Additional App Features

  • Pagination - 18 notes per page with navigation
  • Note Deletion - Delete notes from card hover or within editor
  • Confirmation Modal - Confirmation dialog before permanent deletion
  • Mobile-Responsive UI - Full responsive design with hamburger menu
  • Debounced Autosave - 600ms debounce for title/content, instant save on category change
  • Loading States - Spinners and skeleton states during data fetching

Code Quality

  • Backend Test Coverage: ~98% (81 comprehensive tests)
  • Frontend Test Coverage: ~85% (115 comprehensive tests)
  • Pre-commit Hooks - Automated linting on commit
  • CI/CD Pipeline - GitHub Actions for automated testing
  • Type Safety - TypeScript (frontend) + Mypy type checking (backend)
  • Code Formatting - Ruff + Prettier with ESLint

📋 Table of Contents


🏗️ Architecture

High-Level System Design

┌─────────────────────────────────────────────────────────────────────────────┐
│                              PRODUCTION (AWS)                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────┐     ┌───────────────────────────────────────────┐    │
│   │   CloudFront    │     │              VPC (Default)                 │    │
│   │   (CDN + SSL)   │     │                                           │    │
│   │                 │     │   ┌─────────────┐    ┌─────────────────┐  │    │
│   │   Static Files  │     │   │     ALB     │    │   ECS Fargate   │  │    │
│   │   (Next.js)     │     │   │   (HTTP)    │───▶│   (Backend)     │  │    │
│   │                 │     │   └─────────────┘    └─────────────────┘  │    │
│   └────────┬────────┘     │                              │            │    │
│            │              │                              ▼            │    │
│            ▼              │                      ┌─────────────────┐  │    │
│   ┌─────────────────┐     │                      │   RDS Postgres  │  │    │
│   │    S3 Bucket    │     │                      │   (db.t3.micro) │  │    │
│   │   (Frontend)    │     │                      └─────────────────┘  │    │
│   └─────────────────┘     │                                           │    │
│                           └───────────────────────────────────────────┘    │
│                                                                             │
│   ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐      │
│   │    Cognito      │     │     Lambda      │     │ Secrets Manager │      │
│   │  (User Pool)    │────▶│ (Auto-Confirm)  │     │  (DB Creds)     │      │
│   └─────────────────┘     └─────────────────┘     └─────────────────┘      │
│                                                                             │
│   ┌─────────────────┐                                                       │
│   │      ECR        │                                                       │
│   │ (Docker Images) │                                                       │
│   └─────────────────┘                                                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Local Development Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                         LOCAL DEVELOPMENT (Docker)                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐      │
│   │    Frontend     │────▶│    Backend      │────▶│   PostgreSQL    │      │
│   │   (Next.js)     │     │  (Django DRF)   │     │    Database     │      │
│   │   Port 3000     │     │   Port 8000     │     │   Port 5432     │      │
│   └─────────────────┘     └─────────────────┘     └─────────────────┘      │
│                                                                             │
│                           ┌─────────────────┐                               │
│                           │  AWS Cognito    │                               │
│                           │   (DEV Pool)    │                               │
│                           └─────────────────┘                               │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Request Flow

  1. Authentication Flow:

    • User signs up/logs in via frontend (Next.js + AWS Amplify)
    • Cognito validates credentials and returns JWT tokens
    • Lambda trigger auto-confirms users (no email verification)
    • Frontend stores tokens and includes them in API requests
  2. API Request Flow:

    • Frontend makes authenticated request with JWT in Authorization header
    • Backend validates JWT against Cognito JWKS (cached 24h)
    • On first auth, backend creates local user and default categories
    • API returns data filtered by authenticated user
  3. Data Isolation:

    • All notes and categories belong to a specific user
    • Backend filters all queries by user_id
    • Users cannot access other users' data

🛠️ Tech Stack

Backend

Technology Version Purpose
Python 3.13 Runtime
Django 5.1.5 Web framework
Django REST Framework 3.15.2 API framework
PostgreSQL 16 Database
Gunicorn 23.0.0 WSGI server
PyJWT 2.10.1 JWT validation
uv Latest Package manager
Ruff Latest Linter & formatter
Mypy Latest Type checking
Pytest 8.3.5 Testing

Frontend

Technology Version Purpose
Next.js 15.1.6 React framework
React 19.0.0 UI library
TypeScript 5 Type safety
Tailwind CSS 3.4.17 Styling
AWS Amplify 6.13.2 Cognito integration
Jest 29.7.0 Testing
React Testing Library 16.2.0 Component testing
ESLint 9.18.0 Linting
Prettier 3.4.2 Formatting

Infrastructure

Technology Version Purpose
Docker 20.10+ Containerization
Docker Compose 2.0+ Local orchestration
Terraform 1.0+ Infrastructure as Code
AWS ECS Fargate - Container orchestration
AWS RDS PostgreSQL 16 Managed database
AWS S3 - Static file hosting
AWS CloudFront - CDN
AWS Cognito - Authentication
AWS Lambda Python 3.13 Serverless functions
AWS Secrets Manager - Secrets storage
AWS ECR - Container registry

🚀 Quick Start

Get the application running locally with one command:

make up

The application will be available at:

Service URL
Frontend http://localhost:3000
Backend API http://localhost:8000/api/
Health Check http://localhost:8000/api/health/
Admin Panel http://localhost:8000/admin/

To verify everything is working:

./verify-setup.sh

To stop the application:

make down

💻 Development Setup

Prerequisites

  • Docker (v20.10+)
  • Docker Compose (v2.0+)
  • Make (optional but recommended)

Verify installations:

docker --version
docker compose --version
make --version  # optional

Step-by-Step Setup

  1. Clone the repository

    git clone https://github.com/YOUR_USERNAME/notes-taking.git
    cd notes-taking
  2. Configure environment (optional for local dev)

    # Copy example env file
    cp backend/env.example backend/.env
    
    # Edit with your Cognito credentials if available
    # Default values work for local development
  3. Build and start services

    make build
    make up
  4. Run migrations (automatic on container start)

    make migrate
  5. Create admin user (optional)

    make createsuperuser

Available Make Commands

Command Description
make help Show all available commands
make build Build all Docker containers
make up Start all services
make down Stop all services
make restart Restart all services
make logs View logs from all services
make clean Stop services and remove volumes
make test Run all tests
make test-backend Run backend tests only
make test-frontend Run frontend tests only
make test-backend-coverage Backend tests with coverage report
make test-frontend-coverage Frontend tests with coverage report
make lint Run all linters
make lint-backend Run backend linters (Ruff + Mypy)
make lint-frontend Run frontend linters (ESLint + Prettier)
make lint-backend-fix Auto-fix backend lint issues
make lint-frontend-fix Auto-fix frontend lint issues
make migrate Run database migrations
make createsuperuser Create Django admin user
make shell Open Django shell
make shell-db Open PostgreSQL shell
make status Show status of all services
make pre-commit-install Install pre-commit hooks
make pre-commit-run Run pre-commit on all files

Code Quality & Linting

The project uses industry-standard linters:

Backend:

  • Ruff: Fast Python linter and formatter
  • Mypy: Static type checking with Django stubs

Frontend:

  • ESLint: Next.js configuration
  • Prettier: Code formatting with Tailwind plugin
# Run all linters
make lint

# Auto-fix issues
make lint-backend-fix
make lint-frontend-fix

Pre-commit Hooks

# Install hooks (one time)
make pre-commit-install

# Hooks run automatically on git commit
git commit -m "feat: your changes"

# Run manually on all files
make pre-commit-run

🧪 Testing

Test Coverage Summary

Component Tests Coverage
Backend 81 ~98%
Frontend 115 ~85%

Run Tests

# All tests
make test

# Backend only
make test-backend

# Frontend only
make test-frontend

# With coverage reports
make test-backend-coverage
make test-frontend-coverage

Backend Test Structure

backend/api/tests/
├── test_api_categories.py    # Category CRUD tests
├── test_api_notes.py         # Note CRUD tests
├── test_auth.py              # Authentication tests
├── test_category_filtering.py # Category filtering tests
├── test_delete_note.py       # Note deletion tests
├── test_health.py            # Health endpoint tests
├── test_models.py            # Model tests
├── test_pagination.py        # Pagination tests
└── test_serializers.py       # Serializer validation tests

Frontend Test Structure

frontend/src/
├── __tests__/                # Integration tests
├── app/__tests__/            # Page tests
├── components/__tests__/     # Component tests
├── hooks/__tests__/          # Hook tests
├── lib/__tests__/            # Utility tests
└── utils/__tests__/          # Helper function tests

View Coverage Reports

# Backend (after running test-backend-coverage)
xdg-open backend/htmlcov/index.html    # Linux
open backend/htmlcov/index.html        # macOS

# Frontend (after running test-frontend-coverage)
xdg-open frontend/coverage/lcov-report/index.html    # Linux
open frontend/coverage/lcov-report/index.html        # macOS

For detailed testing documentation, see:


🚢 Deployment

Production Infrastructure (AWS Free Tier)

The application is deployed to AWS using Terraform. All resources are configured to stay within AWS Free Tier limits.

Deployed Services:

  • ECS Fargate: Containerized backend (256 CPU, 512 MB memory)
  • RDS PostgreSQL: db.t3.micro with 20GB storage
  • S3 + CloudFront: Static frontend with CDN
  • Cognito: User authentication
  • Secrets Manager: Database credentials
  • ECR: Container registry

Deployment Scripts

# Deploy backend to ECS
./scripts/deploy.sh

# Deploy frontend to S3/CloudFront
./scripts/deploy-frontend.sh

# Run database migrations
./scripts/run-migrations.sh

# Update task definition
./scripts/update-task-definition.sh

Quick Deployment Steps

# 1. Initialize and apply Terraform
cd terraform/aws
terraform init
terraform apply -var-file="vars/prod.tfvars"

# 2. Build and push backend image
./scripts/deploy.sh

# 3. Build and deploy frontend
./scripts/deploy-frontend.sh

# 4. Run migrations
./scripts/run-migrations.sh

Access Deployed Application

# Get outputs from Terraform
cd terraform/aws
terraform output frontend_url      # CloudFront URL
terraform output alb_dns_name      # Backend API URL
terraform output deployment_summary # Full deployment info

Cost Estimate

With low traffic (~5 users), monthly cost is approximately $0.40-1.00 (mostly Secrets Manager). All other services stay within Free Tier limits.

For complete deployment documentation, see terraform/README.md.


🗃️ Database Design

Entity Relationship Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                              DATABASE SCHEMA                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────────────┐                                           │
│   │           users             │                                           │
│   ├─────────────────────────────┤                                           │
│   │ id (PK)         SERIAL      │                                           │
│   │ cognito_sub     VARCHAR(255)│ ◄── Unique identifier from Cognito       │
│   │ email           VARCHAR(255)│                                           │
│   │ is_active       BOOLEAN     │                                           │
│   │ created_at      TIMESTAMP   │                                           │
│   │ updated_at      TIMESTAMP   │                                           │
│   └──────────────┬──────────────┘                                           │
│                  │                                                          │
│                  │ 1:N                                                      │
│                  ▼                                                          │
│   ┌─────────────────────────────┐        ┌─────────────────────────────┐   │
│   │        categories           │        │           notes             │   │
│   ├─────────────────────────────┤        ├─────────────────────────────┤   │
│   │ id (PK)         SERIAL      │        │ id (PK)         SERIAL      │   │
│   │ user_id (FK)    INTEGER     │◄───────│ user_id (FK)    INTEGER     │   │
│   │ name            VARCHAR(100)│   1:N  │ category_id(FK) INTEGER     │──┐│
│   │ color           VARCHAR(7)  │◄───────│ title           VARCHAR(255)│  ││
│   │ created_at      TIMESTAMP   │        │ content         TEXT        │  ││
│   │ updated_at      TIMESTAMP   │        │ created_at      TIMESTAMP   │  ││
│   └─────────────────────────────┘        │ updated_at      TIMESTAMP   │  ││
│                                          └─────────────────────────────┘  ││
│                                                           │               ││
│                                                           └───────────────┘│
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Tables

users

Column Type Constraints Description
id SERIAL PRIMARY KEY Auto-increment ID
cognito_sub VARCHAR(255) UNIQUE, NOT NULL Cognito user identifier
email VARCHAR(255) UNIQUE, NOT NULL User email address
is_active BOOLEAN DEFAULT TRUE Account active status
created_at TIMESTAMP AUTO Creation timestamp
updated_at TIMESTAMP AUTO Last update timestamp

categories

Column Type Constraints Description
id SERIAL PRIMARY KEY Auto-increment ID
user_id INTEGER FOREIGN KEY → users.id Owner user
name VARCHAR(100) NOT NULL Category name
color VARCHAR(7) NOT NULL Hex color code (#RRGGBB)
created_at TIMESTAMP AUTO Creation timestamp
updated_at TIMESTAMP AUTO Last update timestamp

Unique constraint: (user_id, name)

Default categories (created on first login):

  • Random Thoughts (#EF9C66)
  • School (#FCDC94)
  • Personal (#78ABA8)

notes

Column Type Constraints Description
id SERIAL PRIMARY KEY Auto-increment ID
user_id INTEGER FOREIGN KEY → users.id Owner user
category_id INTEGER FOREIGN KEY → categories.id Note category
title VARCHAR(255) BLANK OK Note title
content TEXT BLANK OK, MAX 50000 Note content
created_at TIMESTAMP AUTO Creation timestamp
updated_at TIMESTAMP AUTO Last update timestamp

Business Rules:

  • Every note MUST have a category (required)
  • Category must belong to the same user as the note
  • Notes ordered by updated_at DESC (newest first)

Indexes

Table Index Columns Purpose
users idx_cognito_sub cognito_sub Fast lookup by Cognito ID
users idx_email email Fast lookup by email
categories idx_user_name user_id, name User's categories lookup
notes idx_user_updated user_id, -updated_at User's notes ordered by date
notes idx_category category_id Filter notes by category

🔒 Security Considerations

OWASP Top 10 Alignment

Risk Mitigation
A01: Broken Access Control User-based data isolation; all queries filtered by user_id
A02: Cryptographic Failures Passwords handled by Cognito; JWT tokens for auth
A03: Injection Django ORM prevents SQL injection; input validation via serializers
A04: Insecure Design Least privilege principle; defense in depth
A05: Security Misconfiguration Environment-specific settings; secrets in AWS Secrets Manager
A06: Vulnerable Components Actively maintained dependencies; regular updates
A07: Auth Failures AWS Cognito handles authentication; JWT validation
A08: Data Integrity Failures Category ownership validation; CSRF protection
A09: Security Logging CloudWatch logging enabled
A10: SSRF No user-controlled URL fetching

Authentication Security

  • JWT Validation: Tokens validated against Cognito JWKS
  • JWKS Caching: Keys cached for 24 hours to reduce API calls
  • Token Claims Validated: Issuer, audience, expiry, token_use
  • Secure Password Policy: Min 8 chars, requires uppercase, lowercase, numbers, symbols

API Security

  • CORS Configuration: Restricted to allowed origins
  • Input Validation: All inputs validated via DRF serializers
  • Rate Limiting: Recommended for production (Django Ratelimit)
  • Security Headers: X-Frame-Options, X-Content-Type-Options, HSTS

Production Security Checklist

  • HTTPS via CloudFront
  • Database credentials in Secrets Manager
  • Environment-specific configurations
  • User data isolation
  • WAF (Web Application Firewall) - Recommended
  • Rate limiting - Recommended
  • Security scanning (SAST/DAST) - Recommended

⚠️ Security Risks & Mitigations

Risk Mitigation
Default credentials in development Use environment variables; never use defaults in production
Debug mode exposure DEBUG=False in production
CORS misconfiguration Restrict ALLOWED_HOSTS and CORS_ALLOWED_ORIGINS
Missing rate limiting Implement Django Ratelimit or AWS WAF

Security Contact

For security issues or vulnerabilities:

  • Create a private security advisory on GitHub
  • Do not disclose security issues publicly until addressed

📚 API Documentation

Authentication

All endpoints except /health/ require a valid JWT token in the Authorization header:

Authorization: Bearer <token>

Endpoints

Health Check

GET /api/health/

Response (200):

{
  "status": "healthy",
  "service": "notes-taking-api",
  "database": "connected"
}

Categories

Method Endpoint Description
GET /api/categories/ List user's categories
POST /api/categories/ Create category
GET /api/categories/{id}/ Get category details
PATCH /api/categories/{id}/ Update category
DELETE /api/categories/{id}/ Delete category

Category Object:

{
  "id": 1,
  "name": "Personal",
  "color": "#78ABA8",
  "note_count": 5,
  "created_at": "2026-01-26T10:00:00Z",
  "updated_at": "2026-01-26T10:00:00Z"
}

Notes

Method Endpoint Description
GET /api/notes/ List user's notes (paginated)
GET /api/notes/?category=1 Filter notes by category
GET /api/notes/?page=2 Get specific page
POST /api/notes/ Create note
GET /api/notes/{id}/ Get note details
PATCH /api/notes/{id}/ Update note
DELETE /api/notes/{id}/ Delete note
GET /api/notes/summary/ Get notes summary

Note Object:

{
  "id": 1,
  "title": "My Note",
  "content": "Note content here...",
  "category": 1,
  "category_name": "Personal",
  "category_color": "#78ABA8",
  "created_at": "2026-01-26T10:00:00Z",
  "updated_at": "2026-01-26T10:30:00Z"
}

Paginated Response:

{
  "count": 42,
  "next": "http://api/notes/?page=3",
  "previous": "http://api/notes/?page=1",
  "results": [ /* Note objects */ ]
}

For detailed API documentation, see backend/README.md.


📁 Project Structure

notes-taking/
├── backend/                      # Django REST Framework API
│   ├── api/                      # Main API app
│   │   ├── tests/                # Test files
│   │   ├── authentication.py     # Cognito JWT auth
│   │   ├── models.py             # User, Category, Note models
│   │   ├── serializers.py        # DRF serializers
│   │   ├── viewsets.py           # API viewsets
│   │   ├── views.py              # Health check view
│   │   └── urls.py               # API routes
│   ├── config/                   # Django project config
│   │   └── settings.py           # Django settings
│   ├── Dockerfile                # Production container
│   ├── pyproject.toml            # Python dependencies
│   └── README.md                 # Backend documentation
│
├── frontend/                     # Next.js application
│   ├── src/
│   │   ├── app/                  # Next.js pages
│   │   │   ├── login/            # Login page
│   │   │   ├── signup/           # Signup page
│   │   │   └── notes/            # Notes page (protected)
│   │   ├── components/           # React components
│   │   │   ├── NoteEditor.tsx    # Note editor modal
│   │   │   ├── Pagination.tsx    # Pagination controls
│   │   │   └── ...
│   │   ├── hooks/                # Custom hooks
│   │   │   ├── useAuth.ts        # Authentication hook
│   │   │   └── useDebounce.ts    # Debounce hook
│   │   ├── lib/                  # Utilities
│   │   │   ├── api-client.ts     # API client with auth
│   │   │   └── amplify-config.ts # AWS Amplify config
│   │   └── utils/                # Helper functions
│   ├── Dockerfile                # Production container
│   ├── Dockerfile.dev            # Development container
│   └── README.md                 # Frontend documentation
│
├── terraform/                    # Infrastructure as Code
│   └── aws/                      # AWS resources
│       ├── main.tf               # Provider configuration
│       ├── cognito.tf            # Cognito user pools
│       ├── lambda.tf             # Lambda functions
│       ├── ecs.tf                # ECS cluster & service
│       ├── rds.tf                # RDS database
│       ├── s3.tf                 # S3 bucket
│       ├── cloudfront.tf         # CloudFront distribution
│       ├── alb.tf                # Application Load Balancer
│       └── README.md             # Infrastructure docs
│
├── scripts/                      # Deployment scripts
│   ├── deploy.sh                 # Backend deployment
│   ├── deploy-frontend.sh        # Frontend deployment
│   ├── run-migrations.sh         # Database migrations
│   └── update-task-definition.sh # ECS task definition
│
├── infra/                        # Infrastructure configs
│   └── task-definition-prod.json # ECS task definition
│
├── docs/                         # Documentation
│   └── workflow-process.md       # AI workflow & planning
│
├── docker-compose.yml            # Local development
├── Makefile                      # Development commands
├── CODEOWNERS                    # Code ownership
└── README.md                     # This file

🔄 Process Summary & AI Usage Workflow

For a detailed explanation of the development process, planning methodology, and AI tools used throughout this project, see:

docs/workflow-process.md

This document covers:

  • How the project roadmap was created
  • Tools used to manage tasks and deliverables
  • AI tools and integrations used (Cursor IDE, Claude Sonnet 4.5, Figma MCP)
  • The iterative development approach
  • Infrastructure planning and deployment strategy

🤝 Contributing

Code Review Process

  • All changes require review from code owners (see CODEOWNERS)
  • PRs must pass all CI checks (lint, test, smoke test)
  • Follow existing code style and patterns

Development Workflow

# Create feature branch
git checkout -b feature/your-feature-name

# Make changes and test
make lint
make test

# Commit (pre-commit hooks run automatically)
git commit -m "feat: your feature description"

# Push and create PR
git push origin feature/your-feature-name

Commit Message Convention

Use conventional commits:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • style: Formatting
  • refactor: Code restructuring
  • test: Tests
  • chore: Maintenance

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


📞 Support

For questions or issues:

  1. Check documentation (this README, backend/frontend/terraform READMEs)
  2. Review API Documentation
  3. Open an issue on GitHub
  4. Contact the development team

Built with ❤️ using Django REST Framework, Next.js, and AWS

About

Notes Taking App

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors