feat: Updated admin panel providers list & modal
This commit is contained in:
543
README.md
543
README.md
@@ -1,306 +1,174 @@
|
||||
# Notely - Secure Multi-Space Note-Taking Application
|
||||
# Notely
|
||||
|
||||
A production-ready, secure multi-tenant note-taking platform built with Go, Vue 3, and MongoDB.
|
||||
Notely is a multi-space note application built with Go, Vue 3, MongoDB, and Redis.
|
||||
|
||||
## 🚀 Quick Start
|
||||
The repository contains a Go backend, a Vue frontend, Docker Compose assets for local deployment, and Kubernetes manifests for cluster deployment. In containerized environments, the frontend is built into the backend image and served by the Go server. Docker Compose also places Nginx in front of the app for HTTP and HTTPS entry points.
|
||||
|
||||
### Prerequisites
|
||||
## What Is In This Repo
|
||||
|
||||
- Docker & Docker Compose
|
||||
- Go 1.21+ (for local development)
|
||||
- Node.js 18+ (for frontend development)
|
||||
- MongoDB 7.0+ (for local development)
|
||||
- Backend API in `backend/`
|
||||
- Frontend SPA in `frontend/`
|
||||
- Docker and Nginx assets in `devops/docker/`
|
||||
- Kubernetes manifests in `devops/kubernetes/`
|
||||
- Root documentation in `README.md`, `QUICKSTART.md`, `ENV_SETUP.md`, and `PERMISSIONS.md`
|
||||
|
||||
### Development with Docker Compose
|
||||
## Core Features
|
||||
|
||||
- Email/password authentication
|
||||
- Session cookies backed by Redis, with bearer-token fallback for API clients
|
||||
- Admin bootstrap from environment variables
|
||||
- Permission-based authorization with wildcard support
|
||||
- Spaces, categories, and notes
|
||||
- Full-text note search
|
||||
- Public spaces and public notes
|
||||
- Password-protected notes
|
||||
- OAuth/OIDC provider support
|
||||
- Feature flags for registration, provider login, public sharing, and file explorer support
|
||||
- Optional S3-compatible file explorer when enabled through feature flags
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Backend
|
||||
|
||||
- Language: Go
|
||||
- Module: `gitea.hostxtra.co.uk/mrhid6/notely/backend`
|
||||
- Entry point: `backend/cmd/server/main.go`
|
||||
- Architecture style: domain/application/infrastructure/interfaces split
|
||||
- Storage: MongoDB
|
||||
- Session store: Redis
|
||||
|
||||
### Frontend
|
||||
|
||||
- Framework: Vue 3
|
||||
- Router: Vue Router
|
||||
- State: Pinia
|
||||
- Build tool: Vite
|
||||
|
||||
### Container Layout
|
||||
|
||||
- `devops/docker/Dockerfile` builds the frontend and backend into a single app image
|
||||
- `docker-compose.yml` starts:
|
||||
- `mongodb`
|
||||
- `redis`
|
||||
- `notely` (combined app image)
|
||||
- `nginx`
|
||||
|
||||
## Documentation Map
|
||||
|
||||
- `README.md`: project overview and current architecture
|
||||
- `QUICKSTART.md`: fast setup and day-to-day development commands
|
||||
- `ENV_SETUP.md`: environment-variable reference and configuration layout
|
||||
- `PERMISSIONS.md`: enforced permission model and naming
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Docker Compose
|
||||
|
||||
1. Copy the root environment file:
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up
|
||||
|
||||
# Backend: http://localhost:8080
|
||||
# Frontend: http://localhost:5173
|
||||
# MongoDB: localhost:27017
|
||||
# Nginx: http://localhost:80
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Local Development Setup
|
||||
2. Start the stack:
|
||||
|
||||
#### Backend
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
3. Open the app:
|
||||
|
||||
- UI through Nginx: `http://localhost`
|
||||
- Backend health check: `http://localhost:8080/health`
|
||||
- MongoDB: `localhost:27017`
|
||||
- Redis: `localhost:6379`
|
||||
|
||||
### Local Development
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Go 1.25+
|
||||
- Node.js 18+
|
||||
- MongoDB
|
||||
- Redis
|
||||
|
||||
Backend:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# Install dependencies
|
||||
cp .env.example .env
|
||||
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
|
||||
Frontend:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
|
||||
# Install dependencies
|
||||
cp .env.example .env
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 📚 Architecture
|
||||
Local frontend development runs at `http://localhost:5173` and proxies `/api` requests to `http://localhost:8080`.
|
||||
|
||||
### Backend (GoClean Architecture)
|
||||
## API Surface
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
The router in `backend/cmd/server/main.go` currently exposes these endpoint groups.
|
||||
|
||||
### Frontend (Vue 3 Composition API)
|
||||
### Public Endpoints
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
- `GET /health`
|
||||
- `POST /api/v1/auth/register`
|
||||
- `POST /api/v1/auth/login`
|
||||
- `POST /api/v1/auth/refresh`
|
||||
- `POST /api/v1/auth/logout`
|
||||
- `GET /api/v1/auth/providers`
|
||||
- `GET /api/v1/auth/providers/{providerId}/start`
|
||||
- `GET /api/v1/auth/providers/{providerId}/callback`
|
||||
- `GET /api/v1/settings/feature-flags`
|
||||
- `GET /api/v1/public/spaces`
|
||||
- `GET /api/v1/public/spaces/{spaceId}`
|
||||
- `GET /api/v1/public/spaces/{spaceId}/notes`
|
||||
- `GET /api/v1/public/spaces/{spaceId}/notes/{noteId}`
|
||||
- `POST /api/v1/public/spaces/{spaceId}/notes/{noteId}/unlock`
|
||||
|
||||
## 🔐 Security Features
|
||||
### Authenticated User Endpoints
|
||||
|
||||
### Authentication
|
||||
- `GET /api/v1/auth/me`
|
||||
- Space CRUD under `/api/v1/spaces`
|
||||
- Space member management under `/api/v1/spaces/{spaceId}/members`
|
||||
- Note CRUD, search, and unlock under `/api/v1/spaces/{spaceId}/notes`
|
||||
- Category CRUD and move under `/api/v1/spaces/{spaceId}/categories`
|
||||
- File explorer operations under `/api/v1/spaces/{spaceId}/files`
|
||||
|
||||
- **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
|
||||
### Admin Endpoints
|
||||
|
||||
### Authorization
|
||||
Admin routes live under `/api/v1/admin` and cover:
|
||||
|
||||
- **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
|
||||
- users
|
||||
- groups
|
||||
- spaces
|
||||
- feature flags
|
||||
- auth providers
|
||||
|
||||
### Data Security
|
||||
## Permissions
|
||||
|
||||
- **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)
|
||||
Notely uses permission-based authorization, not fixed owner/editor/viewer roles.
|
||||
|
||||
### API Security
|
||||
- Global permissions include `space.create`, `space.edit`, and `space.delete`
|
||||
- Space-scoped permissions follow `space.<space_key>.<action>`
|
||||
- Example: `space.product_docs.note.create`
|
||||
- Example: `space.product_docs.settings.delete`
|
||||
- Space deletion requires either:
|
||||
- global `space.delete`, or
|
||||
- space-scoped `space.<space_key>.settings.delete`
|
||||
|
||||
- **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
|
||||
See `PERMISSIONS.md` for the current enforced permission set.
|
||||
|
||||
## 📦 API Endpoints
|
||||
## Testing And Quality Checks
|
||||
|
||||
### 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
|
||||
Backend:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
@@ -309,118 +177,73 @@ go test -v ./tests/unit/...
|
||||
go test -v ./tests/integration/...
|
||||
```
|
||||
|
||||
### Frontend Tests
|
||||
Frontend:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run build
|
||||
npm run lint
|
||||
npm run test
|
||||
npm run test:watch
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
## Deployment Notes
|
||||
|
||||
### Environment Variables
|
||||
### Docker Compose
|
||||
|
||||
#### Backend (.env)
|
||||
Docker Compose uses the combined application image plus Nginx, MongoDB, and Redis. Configuration is driven by the root `.env` file.
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
### Kubernetes
|
||||
|
||||
#### Frontend (.env)
|
||||
The manifest at `devops/kubernetes/deployment.yaml` currently provisions:
|
||||
|
||||
```
|
||||
VITE_API_BASE_URL=http://localhost:8080
|
||||
```
|
||||
- `noteapp` namespace
|
||||
- MongoDB StatefulSet and PVC
|
||||
- single `noteapp` Deployment for the combined app image
|
||||
- ClusterIP services
|
||||
- Ingress
|
||||
- HorizontalPodAutoscaler
|
||||
|
||||
## 📝 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.
|
||||
Apply it with:
|
||||
|
||||
```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
|
||||
}'
|
||||
kubectl apply -f devops/kubernetes/deployment.yaml
|
||||
```
|
||||
|
||||
## 🚨 Error Handling
|
||||
## Current Repo Layout
|
||||
|
||||
All errors return appropriate HTTP status codes:
|
||||
```text
|
||||
noteapp/
|
||||
├── backend/
|
||||
│ ├── cmd/server/
|
||||
│ ├── internal/
|
||||
│ ├── pkg/
|
||||
│ ├── tests/
|
||||
│ └── .env.example
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ ├── tests/
|
||||
│ ├── package.json
|
||||
│ ├── vite.config.js
|
||||
│ ├── vitest.config.js
|
||||
│ └── .env.example
|
||||
├── devops/
|
||||
│ ├── docker/
|
||||
│ │ ├── Dockerfile
|
||||
│ │ ├── nginx.conf
|
||||
│ │ └── ssl/
|
||||
│ └── kubernetes/
|
||||
│ └── deployment.yaml
|
||||
├── docker-compose.yml
|
||||
├── .env.example
|
||||
├── ENV_SETUP.md
|
||||
├── PERMISSIONS.md
|
||||
├── QUICKSTART.md
|
||||
└── README.md
|
||||
```
|
||||
|
||||
- `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
|
||||
## Notes For Contributors
|
||||
|
||||
## 🎯 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**
|
||||
- Check `PERMISSIONS.md` when changing authorization behavior
|
||||
- Check `ENV_SETUP.md` when adding or changing configuration
|
||||
- Check `backend/cmd/server/main.go` before documenting routes
|
||||
- Keep docs aligned with actual package scripts and checked-in files
|
||||
|
||||
Reference in New Issue
Block a user