The backend service for NoteNexus is a RESTful API built with Go and the Chi router framework. It handles user authentication, workspace management, note storage, and task tracking with a PostgreSQL database backend.
This backend service provides the core functionality for the NoteNexus application. It manages user accounts, authentication tokens, workspace collaboration features, and all associated data operations for notes and tasks.
Live Application: https://note-nexusgh.onrender.com
API Base URL (Production): https://note-nexus-anxm.onrender.com
API Base URL (Local): http://localhost:8080
- Language: Go 1.25.1
- HTTP Framework: Chi v5.2.3 - lightweight and composable HTTP router
- Database: PostgreSQL
- Authentication: JWT tokens with golang-jwt/jwt
- Password Hashing: golang.org/x/crypto
- Environment Management: godotenv for configuration
- CORS Support: go-chi/cors middleware
cmd/api/
├── main.go - Server initialization and configuration
├── auth.go - Authentication handlers (signup, login)
├── middleware.go - Authentication and authorization middleware
├── notes.go - Note management endpoints
├── tasks.go - Task/todo management endpoints
└── workspaces.go - Workspace management endpoints
internal/data/
├── models.go - Data model registry and initialization
├── users.go - User database operations
├── workspaces.go - Workspace database operations
├── notes.go - Note database operations
└── tasks.go - Task database operations
migrations/
└── 001_create_tables.sql - Initial database schema
go.mod - Go module dependencies
Dockerfile - Container image definition
LICENSE - License information
- Go 1.25.1 or later
- PostgreSQL 15 or later
- Make (optional, for running build commands)
-
Clone the repository:
git clone https://github.com/Fenlot/Note-Nexus.git cd note-nexus-backend -
Install Go dependencies:
go mod download
-
Create a
.envfile with the following configuration:DATABASE_URL=postgres://username:password@localhost:5432/notenexus PORT=8080 JWT_SECRET=your-secret-key-here
-
Set up the PostgreSQL database:
createdb notenexus psql notenexus < migrations/001_create_tables.sql -
Run the server:
go run cmd/api/main.go
-
Verify the server is running:
curl http://localhost:8080/health
-
Build the Docker image:
docker build -t note-nexus-backend . -
Run the container with environment variables:
docker run \ -p 8080:8080 \ -e DATABASE_URL=postgres://user:password@host:5432/notenexus \ -e JWT_SECRET=your-secret-key \ note-nexus-backend
-
For complete stack setup, use Docker Compose from the root directory:
docker-compose up --build
All requests and responses use JSON format.
- Method: POST
- Path:
/v1/signup - Request Body:
{ "email": "user@example.com", "password": "securepassword" } - Response: 201 Created
{ "id": 1, "email": "user@example.com", "token": "eyJhbGciOiJIUzI1NiIs..." }
- Method: POST
- Path:
/v1/login - Request Body:
{ "email": "user@example.com", "password": "securepassword" } - Response: 200 OK
{ "id": 1, "email": "user@example.com", "token": "eyJhbGciOiJIUzI1NiIs..." }
All protected endpoints require the Authorization header with a valid JWT token:
Authorization: Bearer <token>
- Method: GET
- Path:
/v1/workspaces - Authentication: Required
- Response: 200 OK
[ { "id": 1, "name": "My Workspace", "owner_id": 1, "subscription_tier": "free", "created_at": "2026-05-06T10:30:00Z" } ]
All note endpoints are scoped to a workspace.
- Method: POST
- Path:
/v1/workspaces/{workspaceId}/notes - Authentication: Required
- Authorization: User must be workspace member
- Request Body:
{ "title": "Meeting Notes", "content": "Discussed project timeline and deliverables" } - Response: 201 Created
- Method: GET
- Path:
/v1/workspaces/{workspaceId}/notes - Authentication: Required
- Authorization: User must be workspace member
- Response: 200 OK
[ { "id": 1, "workspace_id": 1, "user_id": 1, "title": "Meeting Notes", "content": "Discussed project timeline and deliverables", "updated_at": "2026-05-06T10:30:00Z" } ]
- Method: PUT
- Path:
/v1/workspaces/{workspaceId}/notes/{id} - Authentication: Required
- Request Body:
{ "title": "Updated Title", "content": "Updated content" } - Response: 200 OK
- Method: DELETE
- Path:
/v1/workspaces/{workspaceId}/notes/{id} - Authentication: Required
- Response: 204 No Content
All task endpoints are scoped to a workspace.
- Method: POST
- Path:
/v1/workspaces/{workspaceId}/todos - Authentication: Required
- Request Body:
{ "title": "Complete project documentation" } - Response: 201 Created
- Method: GET
- Path:
/v1/workspaces/{workspaceId}/todos - Authentication: Required
- Response: 200 OK
[ { "id": 1, "workspace_id": 1, "user_id": 1, "title": "Complete project documentation", "is_completed": false, "created_at": "2026-05-06T10:30:00Z" } ]
- Method: PATCH
- Path:
/v1/workspaces/{workspaceId}/todos/{id} - Authentication: Required
- Request Body:
{ "is_completed": true } - Response: 200 OK
- Method: PUT
- Path:
/v1/workspaces/{workspaceId}/todos/{id} - Authentication: Required
- Request Body:
{ "title": "Updated task title" } - Response: 200 OK
- Method: DELETE
- Path:
/v1/workspaces/{workspaceId}/todos/{id} - Authentication: Required
- Response: 204 No Content
- id: Integer, primary key
- email: String, unique, required
- password_hash: String, hashed password
- created_at: Timestamp, auto-set
- id: Integer, primary key
- name: String, required
- owner_id: Integer, foreign key to users
- subscription_tier: String, defaults to 'free'
- created_at: Timestamp, auto-set
- workspace_id: Integer, foreign key to workspaces
- user_id: Integer, foreign key to users
- role: String, defaults to 'member' (owner, admin, member)
- joined_at: Timestamp, auto-set
- Primary key: (workspace_id, user_id)
- id: Integer, primary key
- workspace_id: Integer, foreign key to workspaces
- user_id: Integer, foreign key to users (creator)
- title: String, required
- content: String, optional
- updated_at: Timestamp, auto-set
- id: Integer, primary key
- workspace_id: Integer, foreign key to workspaces
- user_id: Integer, foreign key to users (creator/assignee)
- title: String, required
- is_completed: Boolean, defaults to false
- created_at: Timestamp, auto-set
- Request arrives at the Chi router with middleware chain
- Logger middleware logs the request
- CORS middleware handles cross-origin requests
- If protected route: authentication middleware validates JWT
- If workspace-scoped: authorization middleware verifies workspace membership
- Route handler processes the request
- Data models execute database operations
- Handler returns JSON response
JWT tokens are generated upon successful login or signup. The token contains the user ID and email. Every protected request must include a valid, non-expired JWT token in the Authorization header.
Workspace authorization is handled by checking if the user is a member of the workspace before allowing data access. This prevents users from accessing data outside their workspaces.
The application uses a single PostgreSQL connection pool initialized at startup. Connection pool settings can be configured for production deployments. Migrations are applied automatically on server startup.
The API returns appropriate HTTP status codes:
- 200: Success
- 201: Resource created
- 204: No content (successful delete)
- 400: Bad request (validation error)
- 401: Unauthorized (missing or invalid token)
- 403: Forbidden (insufficient permissions)
- 404: Not found
- 500: Internal server error
Configuration is managed through environment variables. Create a .env file in the backend root directory:
# Database connection string
DATABASE_URL=postgres://user:password@localhost:5432/notenexus
# Server port
PORT=8080
# JWT signing secret key
JWT_SECRET=your-secret-key-change-this-in-production
# Allowed CORS origins (comma-separated)
ALLOWED_ORIGINS=http://localhost:3000,https://example.com- Create a handler function in the appropriate file (auth.go, notes.go, tasks.go, etc.)
- Define the request/response structs
- Add validation and error handling
- Register the route in main.go
- Write tests for the handler
- Update this README with endpoint documentation
- Create a new file in internal/data/ (e.g., comments.go)
- Define the data struct and database operations
- Register the model in models.go
- Create any necessary migrations
- Import and use in handlers
Migrations are SQL files in the migrations/ directory. To add a new migration:
- Create a new file:
migrations/002_add_feature.sql - Write the SQL DDL statements
- Update applyMigrations() to include the new migration
- Test locally before committing
Run all tests:
go test ./...Run tests with coverage:
go test -cover ./...Run tests for a specific package:
go test ./internal/dataFor integration tests that require a database, use a test database:
TEST_DATABASE_URL=postgres://user:password@localhost:5432/notenexus_test go test ./...Use curl or Postman to test endpoints:
# Health check
curl http://localhost:8080/health
# Sign up
curl -X POST http://localhost:8080/v1/signup \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'
# Login
curl -X POST http://localhost:8080/v1/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'
# List workspaces (using token from login)
curl http://localhost:8080/v1/workspaces \
-H "Authorization: Bearer YOUR_TOKEN_HERE"- Use database indexes on frequently queried fields (email, workspace_id, user_id)
- Connection pooling is enabled by default
- Consider caching for frequently accessed data like workspace lists
- Monitor slow queries in production
- Always use HTTPS in production
- Change JWT_SECRET to a strong random value in production
- Never commit .env files with secrets
- Validate all user input before database operations
- Regularly update dependencies for security patches
- Use parameterized queries to prevent SQL injection (chi/sql already handles this)
Enable detailed logging by running with debug flags:
go run -v cmd/api/main.goCheck database connection issues:
psql $DATABASE_URL -c "SELECT 1"View Go module dependencies:
go list -m all- Verify DATABASE_URL format: postgres://user:password@host:port/dbname
- Ensure PostgreSQL server is running
- Check firewall rules allowing database access
- Verify user credentials and permissions
- Ensure JWT_SECRET is set and consistent across restarts
- Check token expiration time
- Verify Authorization header format: "Bearer "
- Verify frontend origin is in allowed CORS origins list
- Check browser console for specific origin being rejected
- Test with curl to confirm backend is accessible
When contributing to the backend:
- Follow Go conventions and idioms
- Use meaningful variable and function names
- Keep functions focused and testable
- Add comments for exported functions
- Write tests for new functionality
- Keep the dependency list lean
- Update this README for significant changes
The backend is containerized and can be deployed to:
- Docker Swarm
- Kubernetes
- AWS ECS or Fargate
- Azure Container Instances
- Google Cloud Run
- Render, Railway, or similar container hosting
For production deployments:
- Use a managed database service (AWS RDS, Azure Database, etc.)
- Set environment variables securely
- Configure proper logging and monitoring
- Use SSL certificates for HTTPS
- Set up database backups
- Monitor application performance
This backend service is part of NoteNexus and is licensed under the MIT License.
- Chi Framework: https://github.com/go-chi/chi
- PostgreSQL Documentation: https://www.postgresql.org/docs/
- JWT Implementation: https://github.com/golang-jwt/jwt