This repository contains the backend REST API for a multi-user notes management service (conceptually similar to Google Keep or Apple Notes). The system handles secure user authentication, granular data isolation, and secure cross-user note sharing.
This project was engineered to satisfy the requirements of an intensive backend engineering internship assignment, with a strong emphasis on edge-case handling, security, and scalability.
** Live Environment Base URL:** https://notes-app-5-arhb.onrender.com
The application is built using a modern, scalable Java ecosystem.
- Language: Java 17+
- Framework: Spring Boot 3.2.x (Spring Web, Spring Security, Spring Data JPA)
- Database: PostgreSQL (Cloud-hosted via Render)
- Authentication: Stateless JSON Web Tokens (JWT) via
io.jsonwebtoken - Password Security: BCrypt Hashing Algorithm
- Rate Limiting: Bucket4j (Token-bucket algorithm)
- Containerization: Docker (Stretch goal achieved)
- Deployment: Render (PaaS)
Instead of relying on server-side session cookies (which limit scalability), this API uses Stateless JWT Authentication.
- Upon successful login, the server issues an encrypted JWT signed with a secret key.
- The client must attach this token as a
Bearertoken in theAuthorizationheader for all protected requests. - The server verifies the token's cryptographic signature on every request, ensuring the user is authenticated without hitting the database just to check session state.
Every API endpoint that interacts with a Note entity enforces strict ownership checks. A user can only fetch, modify, or delete a note if their User ID matches the Note's owner_id, or if the note has been explicitly shared with them via the sharing table. Unauthorized attempts yield a 403 Forbidden or 404 Not Found to prevent data leakage.
- Brute-Force Protection: The
/loginendpoint is protected by a Bucket4j rate limiter, restricting users to 5 attempts per minute. Excess attempts yield a429 Too Many Requests. - Duplicate Identity Protection: The registration endpoint gracefully catches
DataIntegrityViolationExceptionand returns a400 Bad Requestif an email is already in use, preventing raw SQL errors from leaking to the client. - Archive/Trash Feature (Soft Delete): Instead of immediately destroying data on a
DELETErequest, the application supports a trash/archive state to prevent accidental data loss, fulfilling the custom product feature requirement.
The PostgreSQL database relies on three core entities:
usersTable:
id(UUID, Primary Key)email(String, Unique, Not Null)password_hash(String, BCrypt, Not Null)
notesTable:
id(UUID, Primary Key)title(String, Not Null)content(Text)owner_id(UUID, Foreign Key -> users.id)created_at(Timestamp)updated_at(Timestamp)is_archived/is_trashed(Boolean for custom feature)
shared_notesTable (Many-to-Many mapping):
note_id(UUID, Foreign Key -> notes.id)shared_with_user_id(UUID, Foreign Key -> users.id)
- Endpoint:
GET /about - Purpose: Exposes developer details and metadata about custom features.
- Response (200 OK):
{
"name": "Harshith Banothu",
"email": "your-email@example.com",
"my features": {
"Archive and Trash Management": "Soft-delete system preventing accidental data loss.",
"Bucket4j Rate Limiting": "Protects /login from brute force attacks."
}
}
- Endpoint:
GET /openapi.json - Purpose: Returns the full Swagger/OpenAPI v3 schema for the application.
- Endpoint:
POST /register - Payload:
{
"email": "user@example.com",
"password": "securePassword123"
}
- Success Response (201 CREATED): Status code
201with a success message. - Failure Responses:
400 Bad Request(Invalid email format, weak password, or email already exists).
- Endpoint:
POST /login - Payload: Same as registration.
- Success Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
- Failure Responses: *
401 Unauthorized(Wrong credentials) 429 Too Many Requests(Rate limit exceeded)
*All requests below require the HTTP Header: Authorization: Bearer <your_jwt_token>*
- Endpoint:
POST /notes - Payload:
{
"title": "Project Architecture",
"content": "Designing the database schema."
}
- Success Response (201 CREATED):
{
"id": "uuid-string",
"title": "Project Architecture",
"content": "Designing the database schema.",
"created_at": "2024-05-17T12:00:00Z",
"updated_at": "2024-05-17T12:00:00Z"
}
- Endpoint:
GET /notes - Success Response (200 OK): Returns a JSON Array
[...]containing all active notes owned by the authenticated user.
- Endpoint:
GET /notes/{id} - Success Response (200 OK): Returns the specific note JSON object.
- Security Edge Case: If the requested ID belongs to a different user (and hasn't been shared), returns
404 Not Foundor403 Forbiddento prevent object-level enumeration.
- Endpoint:
PUT /notes/{id} - Payload:
{
"title": "Updated Title",
"content": "Updated content."
}
- Success Response (200 OK): Returns the updated note JSON with a refreshed
updated_attimestamp.
- Endpoint:
DELETE /notes/{id} - Success Response (204 NO CONTENT): Returns an empty body. Note is moved to trash/archived state (Custom feature).
- Endpoint:
POST /notes/{id}/share - Payload:
{
"share_with_email": "colleague@example.com"
}
- Success Response (200 OK): Returns a success message.
- Logic: The system looks up
colleague@example.com. If they exist, it adds an entry to theshared_notestable. The colleague can now query this note usingGET /notes/{id}.
This application is fully containerized to ensure perfect environment parity between local development and production.
- The
Dockerfilecompiles the Spring Boot application using Maven and packages it into an executable.jarrunning on a lightweight Alpine Linux Java runtime. - Render utilizes this Dockerfile to build and deploy the container natively.
- Clone the repo:
git clone https://github.com/har8shith/notes-app.git - Set Environment Variables:
SPRING_DATASOURCE_URL: PostgreSQL JDBC URLSPRING_DATASOURCE_USERNAME: Database UsernameSPRING_DATASOURCE_PASSWORD: Database PasswordJWT_SECRET: A 256-bit secure random string for token signing
- Run via Maven:
./mvnw spring-boot:run - Run via Docker:
docker build -t notes-api . && docker run -p 8080:8080 notes-api