A full-stack note-taking application with rich text editing, categories, and real-time syncing.
| Layer | Technology |
|---|---|
| Backend | Django 6.0, Django REST Framework, PostgreSQL 16 |
| Frontend | Next.js 14+, TypeScript, Tailwind CSS, Framer Motion |
| State | Zustand (client), JWT authentication |
| Editor | TipTap (ProseMirror-based rich text editor) |
| Container | Docker, Docker Compose |
| Mailcatcher (development) |
- Rich Text Editor: Bold, italic, headings, lists, links, images
- Categories: Organize notes with colored categories
- Real-time Sync: Differential patching for efficient updates
- Speech-to-Text: Voice input support for note creation
- Infinite Scroll: Lazy loading for large note collections
- Authentication: JWT with automatic token refresh
- Email Verification: Secure user registration flow
- Docker and Docker Compose
- Make (optional but recommended)
# Clone and start
git clone <repository-url>
cd NotesTakingApp
make setup| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:8000/api/v1 |
| API Documentation | http://localhost:8000/api/docs |
| Mailcatcher | http://localhost:1080 |
make createsuperuser# Services
make build # Build containers
make up # Start all services
make down # Stop all services
make restart # Restart all services
make logs # View all logs
make logs-backend # View backend logs
make logs-frontend # View frontend logs
# Database
make migrate # Run migrations
make makemigrations # Create new migrations
make reset-db # Reset database (destructive!)
# Shell Access
make shell-backend # Django shell
make shell-frontend # Frontend container shell
# Cleanup
make clean # Remove containers and volumesVisit http://localhost:8000/api/docs for Swagger UI documentation.
Success Response:
{
"success": true,
"data": { ... },
"meta": {
"pagination": {
"page": 1,
"page_size": 10,
"total_pages": 5,
"total_count": 50,
"has_next": true,
"has_previous": false
}
}
}Error Response:
{
"errors": [
{
"code": "validation_error",
"message": "This field is required.",
"field": "email"
}
]
}| Endpoint | Methods | Description |
|---|---|---|
/auth/login/ |
POST | Authenticate user |
/auth/register/ |
POST | Register new user |
/auth/refresh/ |
POST | Refresh access token |
/notes/ |
GET, POST | List/create notes |
/notes/{id}/ |
GET, PATCH, DELETE | Note operations |
/notes/{id}/patch_content/ |
POST | Differential update |
/categories/ |
GET, POST | List/create categories |
NotesTakingApp/
├── backend/ # Django REST API
│ ├── config/ # Settings, URLs
│ ├── core/ # Shared utilities
│ ├── users/ # Authentication
│ ├── notes/ # Notes & categories
│ └── README.md # Backend architecture
├── frontend/ # Next.js application
│ ├── src/
│ │ ├── app/ # Pages & layouts
│ │ ├── components/ # UI components
│ │ ├── hooks/ # Custom hooks
│ │ ├── store/ # Zustand stores
│ │ └── lib/ # Utilities
│ └── README.md # Frontend architecture
├── .cursor/rules/ # Cursor IDE rules
├── docker-compose.yml
├── Makefile
└── README.md
DEBUG=True
SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
POSTGRES_DB=notes_db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
# Email (Mailcatcher for development)
EMAIL_HOST=mailcatcher
EMAIL_PORT=1025
# CORS
FRONTEND_URL=http://localhost:3000
CORS_ALLOWED_ORIGINS=http://localhost:3000NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1- Backend: See
backend/README.mdfor Django architecture details - Frontend: See
frontend/README.mdfor Next.js architecture details - AI Guidelines: See
AGENTS.mdand.cursor/rules/for development patterns
This Notes Taking Application was built following a modern full-stack architecture with a clear separation of concerns between the Django REST API backend and the Next.js frontend. The development process followed an iterative approach, starting with core functionality and progressively adding features.
-
Project Setup & Infrastructure
- Docker Compose configuration for development environment
- PostgreSQL database with Django ORM
- Next.js with TypeScript and Tailwind CSS
- Makefile for common development tasks
-
Backend API Development
- RESTful API design with Django REST Framework
- JWT authentication with SimpleJWT
- Custom exception handling with standardized error responses
- Swagger/OpenAPI documentation with drf-spectacular
-
Frontend Development
- Component-based architecture with React/Next.js
- State management with Zustand stores
- Rich text editing with TipTap (ProseMirror)
- Responsive design with Tailwind CSS and Framer Motion animations
-
Testing & Quality Assurance
- Backend: pytest with pytest-django, factory-boy for test data
- Frontend: Jest with React Testing Library
- Coverage reporting for both backend and frontend
Decision: Use diff-match-patch algorithm for note content synchronization instead of sending full content on each save.
Rationale:
- Reduces bandwidth by only sending changes (deltas)
- Enables conflict resolution in collaborative scenarios
- More efficient for large notes with small edits
- Graceful degradation if patch fails
Decision: All API responses follow a consistent structure with success, data, meta, and errors fields.
Rationale:
- Predictable response handling in frontend
- Easy to implement generic error handling
- Supports pagination metadata uniformly
- Clear separation between success and error states
Decision: Store JWT tokens in HTTP-only cookies instead of localStorage.
Rationale:
- Protection against XSS attacks
- Automatic inclusion in requests
- Secure token refresh mechanism
- Standard web security practice
Decision: Use Zustand instead of Redux or Context API.
Rationale:
- Minimal boilerplate compared to Redux
- Better performance than Context for frequent updates
- Simple API with hooks
- Easy to test and mock
Decision: Use SQLite in-memory database for backend tests instead of PostgreSQL.
Rationale:
- Faster test execution (no Docker dependency)
- Isolated test runs
- No external database required for CI/CD
- Sufficient for unit and integration tests
Decision: Use TipTap (ProseMirror-based) instead of alternatives like Quill or Draft.js.
Rationale:
- Modern, extensible architecture
- TypeScript support
- Active community and maintenance
- Easy customization of toolbar and features
Decision: Implement optional category assignment with color coding.
Rationale:
- Visual organization without forced hierarchy
- Quick filtering by category
- "Unassigned" category for uncategorized notes
- User-defined colors for personalization
The primary AI tool used throughout development was Cursor IDE powered by Claude (Anthropic).
- Generated boilerplate code for Django models, serializers, and views
- Created React components with TypeScript typing
- Implemented complex features like the diff-match-patch integration
- Generated comprehensive test suites for both backend and frontend
- Discussed trade-offs for state management solutions
- Designed the standardized API response format
- Planned the testing strategy and coverage approach
- Structured the project folder hierarchy
- Diagnosed timezone issues in date formatting functions
- Fixed test failures related to serializer context handling
- Resolved Docker/Poetry dependency conflicts
- Identified and fixed IntegrityError handling in category creation
- Consolidated duplicate date parsing logic into helper functions
- Improved error handling in API endpoints
- Refactored validation logic to handle missing request context
- Optimized database queries with proper annotations
- Generated inline code comments and docstrings
- Created API documentation with OpenAPI examples
- Wrote test descriptions and assertions
- Updated configuration files (gitignore, jest.config, etc.)
- Faster Iteration: Quick generation of boilerplate and repetitive code
- Consistency: Maintained coding standards across the codebase
- Learning: Exposure to best practices and alternative approaches
- Debugging: Rapid identification of issues and solutions
- Documentation: Comprehensive docs generated alongside code
All AI-generated code was:
- Reviewed for correctness and security
- Tested against actual requirements
- Modified when necessary to fit specific needs
- Integrated with human-written architectural decisions
# Run all tests
make test
# Run with coverage
make test-cov
# Backend only
make test-backend
make test-backend-cov
# Frontend only
make test-frontend
make test-frontend-cov- Backend: HTML report in
backend/htmlcov/ - Frontend: HTML report in
frontend/coverage/
MIT