This document explains the high-level architecture of NoteNest. It is intended to help contributors understand how different parts of the system work together without requiring deep technical knowledge.
NoteNest follows a standard three-layer architecture commonly used in modern web applications.
User (Browser)
↓
Frontend (Next.js)
↓
Backend (REST, GraphQL APIs)
↓
Database (MongoDB)
Each layer has a clear responsibility and can be worked on independently.
- Display the user interface
- Handle user interactions
- Send requests to backend APIs
- Render notes, dashboards, and editors
- Dashboard UI
- Notes list and editor
- Workspace navigation
- Role-based UI rendering (read-only vs editable)
- The frontend does NOT directly access the database
- All data comes through backend APIs
- Dummy or mocked data may be used during development
- Handle authentication and authorization
- Process API requests
- Apply business logic
- Enforce role-based access control (RBAC)
- Communicate with the database
- Receive request from frontend
- Authenticate user
- Check user permissions
- Perform requested operation
- Return response
“Can this user edit this note?”
This decision is made only in the backend.
- Store persistent data
- Maintain relationships between users, notes, and workspaces
- Users
- Notes
- Workspaces
- Roles / Permissions
- Database design is abstracted behind backend logic
- Contributors usually do not interact with the database directly
A workspace represents a team or group.
Each workspace contains:
- Multiple users
- Multiple notes
- Assigned roles per user
Example: Workspace: "OSQ Core Team"
-
Admin: Organizer
-
Editor: Contributor
-
Viewer: Observer
Workspaces allow NoteNest to support real-world collaboration.
NoteNest implements Optimistic Concurrency Control to prevent lost updates and ensure data integrity in collaborative editing scenarios.
- Each note has a
versionfield that increments on every successful update - Clients must submit their expected version when updating a note
- If the expected version doesn't match the current server version, a conflict is detected
- Conflicts return HTTP 409 with detailed resolution guidance
When updating a note:
- Client sends
expectedVersionin request body - Server compares
expectedVersionwith currentnote.version - If versions match: increment version and apply update
- If versions don't match: return 409 Conflict with merge guidance
{
"error": "Conflict",
"message": "Note has been updated by another user. Please refresh and try again.",
"currentVersion": 5,
"expectedVersion": 3,
"clientChanges": { "title": "New Title", "content": "New content" },
"serverData": {
"title": "Server Title",
"content": "Server content",
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"guidance": "Fetch the latest version, merge your changes manually, and retry the update."
}OCC is integrated across all update mechanisms:
- REST API: PUT
/api/notes/:idwithexpectedVersionin body - Socket Updates:
update-noteevent includesexpectedVersion - Version History: Each update creates a version snapshot
- Cache Invalidation: Occurs only after successful updates
- Event Emission: Domain events fired post-successful update
- Prevents silent data corruption
- Protects collaborative editing integrity
- Strengthens offline-first reliability
- Aligns with production-grade SaaS standards
NoteNest uses an internal event bus and domain events to decouple core business logic from side-effects, improving maintainability and scalability.
- Lightweight internal event emitter
- Supports synchronous and asynchronous event handlers
- Centralized event registration and emission
- Error handling ensures event failures don't crash core requests
Core actions emit structured domain events that other modules can subscribe to:
note.created- Emitted when a new note is creatednote.updated- Emitted when a note is modifiednote.deleted- Emitted when a note is deletedworkspace.created- Emitted when a new workspace is createdmember.added_to_workspace- Emitted when a user joins a workspacemember.removed_from_workspace- Emitted when a user leaves a workspacemember.role_updated- Emitted when a member's role changes
Dedicated listeners handle side-effects independently:
- Audit Logging: Records all user actions for compliance and debugging
- Cache Invalidation: Clears cached data when underlying data changes
- Activity Feed: Updates real-time activity streams (placeholder for future implementation)
- Reduces tight coupling between services
- Improves long-term scalability
- Enables future microservice extraction
- Aligns with modern backend patterns
- Verifies who the user is
- Example: login using email and password
- Verifies what the user can do
- Example: can edit or only view notes
Both are handled in the backend.
Search allows users to:
- Find notes by keyword
- Quickly access information
Basic search:
- Simple text matching
Advanced search (optional):
- Indexed search
- Full-text search
Each layer is independent:
| Layer | Can be worked on independently |
|---|---|
| Frontend | Yes |
| Backend | Yes |
| Documentation | Yes |
| UI/UX | Yes |
This allows contributors with different skill levels to collaborate efficiently.
This architecture:
- Is easy to understand
- Mirrors real-world industry systems
- Scales well with contributors
- Encourages clean code and collaboration
You do NOT need to understand the entire architecture to contribute. Pick one layer, focus on it, and collaborate with others.
That is how real software teams work 🚀