427 lines
9.3 KiB
Markdown
427 lines
9.3 KiB
Markdown
# Notely - Secure Multi-Space Note-Taking Application
|
|
|
|
A production-ready, secure multi-tenant note-taking platform built with Go, Vue 3, and MongoDB.
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
- Docker & Docker Compose
|
|
- Go 1.21+ (for local development)
|
|
- Node.js 18+ (for frontend development)
|
|
- MongoDB 7.0+ (for local development)
|
|
|
|
### Development with Docker Compose
|
|
|
|
```bash
|
|
# Start all services
|
|
docker-compose up
|
|
|
|
# Backend: http://localhost:8080
|
|
# Frontend: http://localhost:5173
|
|
# MongoDB: localhost:27017
|
|
# Nginx: http://localhost:80
|
|
```
|
|
|
|
### Local Development Setup
|
|
|
|
#### Backend
|
|
|
|
```bash
|
|
cd backend
|
|
|
|
# Install dependencies
|
|
go mod download
|
|
|
|
# Set environment variables
|
|
export MONGODB_URI=mongodb://admin:password@localhost:27017/noteapp?authSource=admin
|
|
export JWT_SECRET=your-secret-key
|
|
export ENCRYPTION_KEY=00000000000000000000000000000000
|
|
|
|
# Run migrations and server
|
|
go run ./cmd/server/main.go
|
|
```
|
|
|
|
#### Frontend
|
|
|
|
```bash
|
|
cd frontend
|
|
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Start development server
|
|
npm run dev
|
|
```
|
|
|
|
## 📚 Architecture
|
|
|
|
### Backend (GoClean Architecture)
|
|
|
|
```
|
|
backend/
|
|
├── cmd/server/ # Entry point
|
|
├── internal/
|
|
│ ├── domain/ # Business logic (entities, interfaces)
|
|
│ ├── application/ # Use cases (services, DTOs)
|
|
│ ├── infrastructure/ # External dependencies (DB, auth)
|
|
│ └── interfaces/ # API handlers & middleware
|
|
├── pkg/ # Public packages
|
|
└── tests/ # Test suites
|
|
```
|
|
|
|
### Frontend (Vue 3 Composition API)
|
|
|
|
```
|
|
frontend/
|
|
├── src/
|
|
│ ├── components/ # Reusable Vue components
|
|
│ ├── pages/ # Page components
|
|
│ ├── stores/ # Pinia state management
|
|
│ ├── services/ # API client
|
|
│ ├── router/ # Vue Router config
|
|
│ ├── assets/ # Styles and assets
|
|
│ └── main.js # Entry point
|
|
├── index.html
|
|
└── vite.config.js
|
|
```
|
|
|
|
## 🔐 Security Features
|
|
|
|
### Authentication
|
|
|
|
- **Argon2id password hashing** - Industry-standard PBKDF2
|
|
- **JWT tokens** with short expiration (1 hour)
|
|
- **HTTP-only secure cookies** for refresh tokens
|
|
- **CSRF protection** via SameSite cookies
|
|
- **Brute-force protection** via login attempt tracking
|
|
|
|
### Authorization
|
|
|
|
- **Role-based access control (RBAC)** per space:
|
|
- Owner: Full control
|
|
- Editor: Edit notes and categories
|
|
- Viewer: Read-only access
|
|
- **Space-level data isolation** - all queries include space_id
|
|
- **IDOR prevention** - middleware enforces ownership verification
|
|
|
|
### Data Security
|
|
|
|
- **Encryption at rest** for sensitive fields (OAuth secrets)
|
|
- **HTTPS/TLS** in production (Nginx reverse proxy)
|
|
- **Content Security Policy (CSP)** headers
|
|
- **XSS protection** - DOMPurify for markdown sanitization
|
|
- **SQL injection prevention** - parameterized queries (MongoDB)
|
|
|
|
### API Security
|
|
|
|
- **Rate limiting** - IP-based and user-based
|
|
- **Security headers** - HSTS, X-Frame-Options, X-Content-Type-Options
|
|
- **CORS properly configured** - whitelist origin domains
|
|
- **Input validation** on all endpoints
|
|
|
|
## 📦 API Endpoints
|
|
|
|
### Authentication
|
|
|
|
```
|
|
POST /api/v1/auth/register - Register new user
|
|
POST /api/v1/auth/login - Login user
|
|
POST /api/v1/auth/refresh - Refresh access token
|
|
POST /api/v1/auth/logout - Logout user
|
|
GET /health - Health check
|
|
```
|
|
|
|
### Spaces
|
|
|
|
```
|
|
GET /api/v1/spaces - List user's spaces
|
|
POST /api/v1/spaces - Create space
|
|
GET /api/v1/spaces/{spaceId} - Get space details
|
|
PUT /api/v1/spaces/{spaceId} - Update space
|
|
DELETE /api/v1/spaces/{spaceId} - Delete space
|
|
```
|
|
|
|
### Notes
|
|
|
|
```
|
|
GET /api/v1/spaces/{spaceId}/notes - List notes
|
|
POST /api/v1/spaces/{spaceId}/notes - Create note
|
|
GET /api/v1/spaces/{spaceId}/notes/{noteId} - Get note
|
|
PUT /api/v1/spaces/{spaceId}/notes/{noteId} - Update note
|
|
DELETE /api/v1/spaces/{spaceId}/notes/{noteId} - Delete note
|
|
GET /api/v1/spaces/{spaceId}/notes/search?q= - Search notes
|
|
```
|
|
|
|
### Categories
|
|
|
|
```
|
|
GET /api/v1/spaces/{spaceId}/categories - List categories
|
|
POST /api/v1/spaces/{spaceId}/categories - Create category
|
|
PUT /api/v1/spaces/{spaceId}/categories/{id} - Update category
|
|
DELETE /api/v1/spaces/{spaceId}/categories/{id} - Delete category
|
|
```
|
|
|
|
## 🗄️ Database Design
|
|
|
|
### MongoDB Collections
|
|
|
|
#### users
|
|
|
|
```javascript
|
|
{
|
|
_id: ObjectId,
|
|
email: String (unique),
|
|
username: String (unique),
|
|
password_hash: String,
|
|
first_name: String,
|
|
last_name: String,
|
|
avatar: String,
|
|
is_active: Boolean,
|
|
email_verified: Boolean,
|
|
created_at: Date,
|
|
updated_at: Date,
|
|
last_login_at: Date
|
|
}
|
|
```
|
|
|
|
#### spaces
|
|
|
|
```javascript
|
|
{
|
|
_id: ObjectId,
|
|
name: String,
|
|
description: String,
|
|
icon: String,
|
|
owner_id: ObjectId,
|
|
is_public: Boolean,
|
|
created_at: Date,
|
|
updated_at: Date
|
|
}
|
|
```
|
|
|
|
#### memberships
|
|
|
|
```javascript
|
|
{
|
|
_id: ObjectId,
|
|
user_id: ObjectId,
|
|
space_id: ObjectId,
|
|
role: String (owner|editor|viewer),
|
|
joined_at: Date,
|
|
invited_by: ObjectId,
|
|
invited_at: Date
|
|
}
|
|
```
|
|
|
|
#### notes
|
|
|
|
```javascript
|
|
{
|
|
_id: ObjectId,
|
|
space_id: ObjectId,
|
|
category_id: ObjectId,
|
|
title: String,
|
|
content: String (Markdown),
|
|
tags: [String],
|
|
is_pinned: Boolean,
|
|
is_favorite: Boolean,
|
|
created_by: ObjectId,
|
|
updated_by: ObjectId,
|
|
created_at: Date,
|
|
updated_at: Date,
|
|
viewed_at: Date
|
|
}
|
|
```
|
|
|
|
#### categories
|
|
|
|
```javascript
|
|
{
|
|
_id: ObjectId,
|
|
space_id: ObjectId,
|
|
name: String,
|
|
description: String,
|
|
parent_id: ObjectId (for hierarchical structure),
|
|
icon: String,
|
|
order: Number,
|
|
created_by: ObjectId,
|
|
updated_by: ObjectId,
|
|
created_at: Date,
|
|
updated_at: Date
|
|
}
|
|
```
|
|
|
|
#### Indexes
|
|
|
|
```
|
|
users: { email: 1 (unique), username: 1 (unique) }
|
|
spaces: { owner_id: 1, created_at: -1 }
|
|
memberships: { user_id: 1, space_id: 1 (unique), space_id: 1 }
|
|
notes: { space_id: 1, category_id: 1, updated_at: -1, text: "text" }
|
|
categories: { space_id: 1, parent_id: 1, order: 1 }
|
|
```
|
|
|
|
## 🐳 Deployment
|
|
|
|
### Docker Compose (Development/Testing)
|
|
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
Services:
|
|
|
|
- **MongoDB** (port 27017)
|
|
- **Backend API** (port 8080)
|
|
- **Frontend** (port 5173)
|
|
- **Nginx Reverse Proxy** (port 80)
|
|
|
|
### Kubernetes (Production)
|
|
|
|
```bash
|
|
# Create namespace and secrets
|
|
kubectl apply -f devops/kubernetes/deployment.yaml
|
|
|
|
# Verify deployment
|
|
kubectl get pods -n noteapp
|
|
kubectl port-forward svc/frontend 5173:5173 -n noteapp
|
|
kubectl port-forward svc/backend 8080:8080 -n noteapp
|
|
```
|
|
|
|
Features:
|
|
|
|
- **StatefulSet** for MongoDB with persistent storage
|
|
- **Deployments** for backend and frontend with horizontal scaling
|
|
- **Ingress** for routing (requires ingress controller)
|
|
- **HPA** (Horizontal Pod Autoscaler) for automatic scaling
|
|
- **Liveness & readiness probes** for health checks
|
|
- **Resource limits** for fair resource allocation
|
|
|
|
## 🧪 Testing
|
|
|
|
### Backend Tests
|
|
|
|
```bash
|
|
cd backend
|
|
go test ./...
|
|
go test -v ./tests/unit/...
|
|
go test -v ./tests/integration/...
|
|
```
|
|
|
|
### Frontend Tests
|
|
|
|
```bash
|
|
cd frontend
|
|
npm run test
|
|
npm run test:watch
|
|
```
|
|
|
|
## 🔧 Configuration
|
|
|
|
### Environment Variables
|
|
|
|
#### Backend (.env)
|
|
|
|
```
|
|
MONGODB_URI=mongodb://admin:password@localhost:27017/noteapp
|
|
JWT_SECRET=your-secret-key-min-32-chars
|
|
ENCRYPTION_KEY=32-char-encryption-key-for-secrets
|
|
PORT=8080
|
|
LOG_LEVEL=info
|
|
ENV=development
|
|
```
|
|
|
|
#### Frontend (.env)
|
|
|
|
```
|
|
VITE_API_BASE_URL=http://localhost:8080
|
|
```
|
|
|
|
## 📝 Development Guidelines
|
|
|
|
### Code Structure
|
|
|
|
- Follow clean architecture principles
|
|
- Separate concerns: domain, application, infrastructure
|
|
- Use interfaces for dependency injection
|
|
- Keep services testable and focused
|
|
|
|
### Security Best Practices
|
|
|
|
1. **Never store secrets in code** - use environment variables
|
|
2. **Validate all inputs** on backend
|
|
3. **Sanitize outputs** before rendering
|
|
4. **Use HTTPS in production**
|
|
5. **Implement rate limiting** on APIs
|
|
6. **Log security events** (login attempts, permission denied)
|
|
7. **Audit trail** for sensitive operations
|
|
|
|
### Commit Message Format
|
|
|
|
```
|
|
[TYPE] Description
|
|
|
|
types: feat, fix, docs, style, refactor, test, chore
|
|
```
|
|
|
|
## 📖 API Documentation
|
|
|
|
### Request/Response Format
|
|
|
|
All API requests and responses use JSON.
|
|
|
|
```bash
|
|
# Example: Create Note
|
|
curl -X POST http://localhost:8080/api/v1/spaces/{spaceId}/notes \
|
|
-H "Authorization: Bearer {accessToken}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "My Note",
|
|
"content": "# Markdown content",
|
|
"tags": ["tag1", "tag2"],
|
|
"category_id": null,
|
|
"is_pinned": false,
|
|
"is_favorite": false
|
|
}'
|
|
```
|
|
|
|
## 🚨 Error Handling
|
|
|
|
All errors return appropriate HTTP status codes:
|
|
|
|
- `400` - Bad Request
|
|
- `401` - Unauthorized
|
|
- `403` - Forbidden (insufficient permissions)
|
|
- `404` - Not Found
|
|
- `409` - Conflict (e.g., duplicate email)
|
|
- `429` - Too Many Requests (rate limit exceeded)
|
|
- `500` - Internal Server Error
|
|
|
|
## 🎯 Future Enhancements
|
|
|
|
- [ ] OAuth2/OIDC integration
|
|
- [ ] Email notifications
|
|
- [ ] Real-time collaboration (WebSockets)
|
|
- [ ] Full-text search with Elasticsearch
|
|
- [ ] Export to PDF/Markdown
|
|
- [ ] Mobile applications
|
|
- [ ] Plugin system
|
|
- [ ] Advanced permissions management
|
|
|
|
## 📄 License
|
|
|
|
MIT License - See LICENSE file
|
|
|
|
## 👥 Contributing
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch
|
|
3. Commit your changes
|
|
4. Push to the branch
|
|
5. Create a Pull Request
|
|
|
|
---
|
|
|
|
**Built with ❤️ for secure, collaborative note-taking**
|