Skip to content

About

NoteMind AI is an AI-powered notes platform currently under development for capturing, organizing, and enhancing knowledge. Built with Android (Jetpack Compose) and Spring Boot, it focuses on secure authentication, AI summarization, smart tagging, and fast full-text search.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

47 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿง  NoteMind AI

An intelligent, AI-powered note-taking platform that automatically generates summaries, tags, and flashcards from your notes.

Java 21 Spring Boot 4.0 PostgreSQL Redis Gradle Kotlin Status


๐Ÿ“‹ Quick Navigation

Documentation Purpose
๐Ÿ“– Setup Guide Installation & environment configuration
๐Ÿ”— API Reference Complete API endpoints & curl examples
๐Ÿ›ก๏ธ Security Authentication, best practices & configuration
๐Ÿ› Troubleshooting Common issues & solutions
๐Ÿค Contributing Development guidelines & code style

๐Ÿ“‹ Table of Contents


๐Ÿ’ก Overview

NoteMind AI is a full-stack intelligent notes platform built with Spring Boot 4.0 and PostgreSQL. It goes beyond basic CRUD โ€” every note you create is automatically enriched by AI with a generated summary, contextual tags, and optional study flashcards.

The backend features a clean, layered architecture with JWT + refresh token authentication, Redis caching, Cloudinary-based image storage, PostgreSQL full-text search, and AI integration through both Google Gemini and OpenRouter APIs.

What makes it different?

  • ๐Ÿค– AI-first โ€” Summaries and tags are generated automatically on every save
  • ๐Ÿƒ Flashcard generation โ€” AI creates Q&A flashcards from any note for active recall study
  • โœ… Quiz generation โ€” AI creates multiple-choice quizzes with answers and explanations
  • ๐Ÿ” Full-text search โ€” PostgreSQL tsvector/tsquery with GIN indexing searches across titles, content, and AI summaries
  • ๐Ÿ“ Folder organization โ€” Organize notes into user-scoped folders
  • ๐Ÿ–ผ๏ธ Multimodal AI โ€” Vision models analyze attached images alongside text content
  • โšก Redis caching โ€” Notes are cached with smart eviction on mutations

โœจ Features

๐Ÿ” Authentication & Security

Feature Details
JWT Authentication Stateless, token-based auth with HMAC-SHA signed JWTs
Refresh Tokens Persistent refresh tokens with expiry & revocation support
Password Encryption BCrypt hashing via Spring Security
Session Management Fully stateless โ€” no server-side sessions
Access Control Every note, folder, and flashcard is scoped to the authenticated user
Logout Revokes refresh token on logout

๐Ÿ“ Smart Notes

  • Create / Read / Update / Delete notes with title, content, and optional image
  • AI-generated summaries are created automatically on every create & update
  • AI-generated tags are extracted and persisted as reusable entities
  • Image attachments โ€” upload images that get stored on Cloudinary; vision-capable AI models analyze them
  • Summary types โ€” choose between SHORT, DETAILED, or BULLET_POINTS summaries
  • Refresh summary โ€” regenerate the summary with a different type on demand

๐Ÿƒ AI Flashcards

  • Generate Q&A flashcards from any note using AI (configurable count, 1โ€“50)
  • Regenerate โ€” wipe existing flashcards and generate a fresh set
  • Manual CRUD โ€” create, update, and delete individual flashcards
  • Bulk delete โ€” remove all flashcards for a note at once
  • AI uses both text content and attached images to produce flashcards

โœ… AI Quizzes

  • Generate 1โ€“20 multiple-choice questions from any note
  • Each question includes four options, the correct answer, and an explanation
  • AI uses note text and attached images as quiz sources

๐Ÿ“ Folders

  • Create, rename, and delete folders (unique name per user)
  • Move notes into/out of folders
  • Fetch folders with or without nested notes (?includeNotes=true)

๐Ÿ”Ž Full-Text Search

  • Powered by PostgreSQL's native full-text search engine
  • Uses tsvector columns with GIN indexing for fast ranked results
  • Searches across note title, content, and AI-generated summary
  • Results ranked by ts_rank relevance scoring

๐Ÿ–ผ๏ธ Image Storage

Client uploads image
        โ”‚
        โ–ผ
  Cloudinary CDN
        โ”‚
        โ–ผ
  Returns secure URL
        โ”‚
        โ–ผ
  URL stored in PostgreSQL
  • Max upload size: 10 MB
  • Cloud-hosted on Cloudinary for fast CDN delivery
  • Image URLs are persisted alongside the note

โšก Caching (Redis)

  • Individual notes cached by ID (@Cacheable)
  • Cache updated on create/update (@CachePut)
  • Smart eviction on delete and folder mutations (@CacheEvict)
  • Jackson-serialized values with StringRedisSerializer keys

๐Ÿ— Architecture

The project follows a layered 3-tier architecture:

Controllers โ†’ Services โ†’ Repositories โ†’ Database
     โ†“          โ†“
  Exceptions, Security, Caching

Key components:

  • Controllers - REST endpoints at /api/v1/
  • Services - Business logic & AI integration
  • Repositories - JPA data access layer
  • Security - JWT authentication & authorization
  • Caching - Redis for performance
  • External APIs - Google Gemini, OpenRouter for AI

See docs/API.md for endpoint details and docs/SECURITY.md for authentication strategy.


๐Ÿ› ๏ธ Tech Stack

Layer Technology
Language Java 21
Framework Spring Boot 4.0.5
Security Spring Security, JWT (jjwt 0.13.0), BCrypt
Data Spring Data JPA, Hibernate
Database PostgreSQL (with Full-Text Search + GIN indexes)
Caching Redis + Spring Cache
AI Google Gemini SDK (google-genai), OpenRouter API
Image Storage Cloudinary (cloudinary-http44)
Mapping MapStruct 1.5.5
Utilities Lombok, Jackson
Testing JUnit 5, Spring Test, Testcontainers (PostgreSQL)
Build Gradle (Kotlin DSL)
Android (planned) Kotlin, Jetpack Compose

๐Ÿ“‚ Project Structure

NoteMind-AI/
โ”œโ”€โ”€ android-app/                     # Planned Android client
โ”œโ”€โ”€ backend/
โ”‚   โ”œโ”€โ”€ build.gradle.kts             # Dependencies & plugins
โ”‚   โ”œโ”€โ”€ settings.gradle.kts
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ”œโ”€โ”€ main/
โ”‚       โ”‚   โ”œโ”€โ”€ java/com/dhaliwal/notemind/
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ NotemindApiApplication.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ config/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CloudinaryConfig.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ RedisConfig.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ RequiredBeans.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ StaticResourceConfig.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ controller/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AuthController.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NoteController.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FlashCardController.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ FolderController.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ dto/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NoteDto.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AINoteResponse.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ TagDto.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ flashCard/
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ folder/
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ entity/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Note.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ User.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FlashCard.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Folder.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Tag.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ RefreshToken.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ type/
โ”‚       โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ SummaryType.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ exception/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ GlobalExceptionHandler.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ... (16 custom exceptions)
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ mapper/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NoteMapper.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FlashCardMapper.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FolderMapper.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ TagMapper.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ repository/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NoteRepository.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ UserRepository.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FlashCardRepository.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FolderRepository.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ TagRepository.java
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ security/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ config/SecurityConfig.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AuthFilter/JwtAuthFilter.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ service/AuthService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ refresh/RefreshTokenService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ util/SecurityUtils.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ dto/
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ service/
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AIService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ NotesService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FlashCardService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FolderService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ImageManagerService.java
โ”‚       โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ impl/
โ”‚       โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ AIServiceImpl.java
โ”‚       โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ NotesServiceImpl.java
โ”‚       โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ FlashCardServiceImpl.java
โ”‚       โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ FolderServiceImpl.java
โ”‚       โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ ImageManagerServiceImpl.java
โ”‚       โ”‚   โ”‚   โ””โ”€โ”€ util/
โ”‚       โ”‚   โ”‚       โ””โ”€โ”€ Util.java
โ”‚       โ”‚   โ””โ”€โ”€ resources/
โ”‚       โ”‚       โ””โ”€โ”€ application.properties
โ”‚       โ””โ”€โ”€ test/
โ””โ”€โ”€ README.md

๐Ÿš€ Quick Start

Get the project running in 5 minutes:

# 1. Clone repository
git clone https://github.com/sukhmmeet/NoteMind-AI.git
cd NoteMind-AI/backend

# 2. Set environment variables (see docs/SETUP.md for details)
export DB_URL="jdbc:postgresql://localhost:5432/notemind_ai"
export JWT_SECRET_KEY="your-256-bit-secret-key"
export GOOGLE_API_KEY="AIza..."

# 3. Start services (PostgreSQL & Redis must be running)
./gradlew bootRun

# 4. Test the API
curl http://localhost:8080/api/v1/auth/signup

Full setup instructions โ†’ ๐Ÿ“– Setup Guide

  • Step-by-step installation for all platforms
  • Environment variable configuration
  • Docker Compose setup
  • Verification checklist | PUT | /notes/{id} | Update a note (multipart) | | DELETE | /notes/{id} | Delete a note | | GET | /notes/search?query=... | Full-text search across notes | | GET | /notes/refresh-summary/{id}?type=SHORT | Regenerate AI summary |
๐Ÿ“ Detailed Notes Examples

POST /notes โ€” Create a new note with AI-generated summary

# Basic note (without image)
curl -X POST http://localhost:8080/api/v1/notes \
  -H "Authorization: Bearer <your-jwt-token>" \
  -F 'note={"title":"Quantum Computing","content":"Quantum computers use qubits instead of bits...","summaryType":"DETAILED"};type=application/json'

# Response 201
{
  "id": 1,
  "title": "Quantum Computing",
  "content": "Quantum computers use qubits instead of bits...",
  "summary": "Quantum computing is a revolutionary computing paradigm...",
  "summaryType": "DETAILED",
  "tags": [
    { "id": 1, "name": "quantum-computing" },
    { "id": 2, "name": "technology" }
  ],
  "imageUrl": null,
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z",
  "folderId": null
}

POST /notes (with image) โ€” Create a note with an image

curl -X POST http://localhost:8080/api/v1/notes \
  -H "Authorization: Bearer <your-jwt-token>" \
  -F 'note={"title":"Architecture Diagram","content":"This is our microservices architecture...","summaryType":"BULLET_POINTS"};type=application/json' \
  -F 'image=@diagram.png'

# Response 201 (with image URL from Cloudinary)
{
  "id": 2,
  "title": "Architecture Diagram",
  "imageUrl": "https://res.cloudinary.com/.../diagram.png",
  "summary": "โ€ข Microservices architecture\nโ€ข API Gateway pattern\nโ€ข Database per service",
  ...
}

GET /notes โ€” Retrieve all notes (paginated)

curl -X GET "http://localhost:8080/api/v1/notes?page=0&size=10" \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "content": [
    {
      "id": 1,
      "title": "Quantum Computing",
      "summary": "...",
      "tags": [...],
      "createdAt": "2024-01-15T10:30:00Z"
    }
  ],
  "pageable": {
    "pageNumber": 0,
    "pageSize": 10,
    "totalElements": 42,
    "totalPages": 5
  }
}

GET /notes/{id} โ€” Retrieve a specific note

curl -X GET http://localhost:8080/api/v1/notes/1 \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "id": 1,
  "title": "Quantum Computing",
  "content": "...",
  "summary": "...",
  "tags": [...],
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z"
}

PUT /notes/{id} โ€” Update a note

curl -X PUT http://localhost:8080/api/v1/notes/1 \
  -H "Authorization: Bearer <your-jwt-token>" \
  -F 'note={"title":"Updated Title","content":"Updated content...","summaryType":"SHORT"};type=application/json' \
  -F 'image=@new-image.jpg'

# Response 200 (with regenerated summary and tags)

GET /notes/search?query=... โ€” Full-text search

curl -X GET "http://localhost:8080/api/v1/notes/search?query=quantum&limit=20" \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "results": [
    {
      "id": 1,
      "title": "Quantum Computing",
      "summary": "...",
      "relevanceScore": 0.95
    }
  ],
  "totalResults": 5
}

GET /notes/refresh-summary/{id}?type=... โ€” Regenerate summary

# Available types: SHORT, DETAILED, BULLET_POINTS
curl -X GET "http://localhost:8080/api/v1/notes/1/refresh-summary?type=BULLET_POINTS" \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "id": 1,
  "summary": "โ€ข Point 1\nโ€ข Point 2\nโ€ข Point 3",
  "summaryType": "BULLET_POINTS"
}

DELETE /notes/{id} โ€” Delete a note

curl -X DELETE http://localhost:8080/api/v1/notes/1 \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 204 (No Content)

Flashcard Endpoints

Method Endpoint Description
POST /notes/{noteId}/flashcards/generate?count=5 AI-generate flashcards from a note
POST /notes/{noteId}/flashcards/regenerate?count=5 Delete existing & regenerate flashcards
GET /notes/{noteId}/flashcards Get all flashcards for a note
GET /flashcards/{flashCardId} Get a specific flashcard
POST /notes/{noteId}/flashcards Manually create a flashcard
PATCH /flashcards/{flashCardId} Update a flashcard
DELETE /flashcards/{flashCardId} Delete a flashcard
DELETE /notes/{noteId}/flashcards Delete all flashcards of a note
๐Ÿƒ Detailed Flashcard Examples

POST /notes/{noteId}/flashcards/generate โ€” Generate flashcards from note

curl -X POST "http://localhost:8080/api/v1/notes/1/flashcards/generate?count=5" \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 201
{
  "noteId": 1,
  "flashcards": [
    {
      "id": 1,
      "question": "What is a qubit?",
      "answer": "A qubit (quantum bit) is the fundamental unit of quantum computing...",
      "createdAt": "2024-01-15T10:35:00Z"
    },
    {
      "id": 2,
      "question": "How does quantum superposition work?",
      "answer": "Quantum superposition allows a qubit to exist in multiple states...",
      "createdAt": "2024-01-15T10:35:00Z"
    }
  ],
  "totalGenerated": 5
}

GET /notes/{noteId}/flashcards โ€” List all flashcards for a note

curl -X GET http://localhost:8080/api/v1/notes/1/flashcards \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "flashcards": [
    {
      "id": 1,
      "question": "What is a qubit?",
      "answer": "...",
      "createdAt": "2024-01-15T10:35:00Z"
    }
  ],
  "totalCount": 5
}

PATCH /flashcards/{flashCardId} โ€” Update a flashcard

curl -X PATCH http://localhost:8080/api/v1/flashcards/1 \
  -H "Authorization: Bearer <your-jwt-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is a quantum bit?",
    "answer": "Updated answer with more detail..."
  }'

# Response 200

DELETE /notes/{noteId}/flashcards โ€” Delete all flashcards for a note

curl -X DELETE http://localhost:8080/api/v1/notes/1/flashcards \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 204 (No Content)

Folder Endpoints

Method Endpoint Description
POST /folder Create a folder
GET /folder Get all folders (add ?includeNotes=true for nested notes)
GET /folder/{id} Get folder by ID
PATCH /folder/{id} Rename a folder
DELETE /folder/{id} Delete a folder
๐Ÿ“ Detailed Folder Examples

POST /folder โ€” Create a new folder

curl -X POST http://localhost:8080/api/v1/folder \
  -H "Authorization: Bearer <your-jwt-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Study Notes"
  }'

# Response 201
{
  "id": 1,
  "name": "Study Notes",
  "createdAt": "2024-01-15T10:40:00Z"
}

GET /folder โ€” Get all folders with nested notes

curl -X GET "http://localhost:8080/api/v1/folder?includeNotes=true" \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 200
{
  "folders": [
    {
      "id": 1,
      "name": "Study Notes",
      "notes": [
        {
          "id": 1,
          "title": "Quantum Computing",
          "summary": "..."
        }
      ],
      "noteCount": 1
    }
  ]
}

PATCH /folder/{id} โ€” Rename a folder

curl -X PATCH http://localhost:8080/api/v1/folder/1 \
  -H "Authorization: Bearer <your-jwt-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Advanced Study Notes"
  }'

# Response 200

DELETE /folder/{id} โ€” Delete a folder

curl -X DELETE http://localhost:8080/api/v1/folder/1 \
  -H "Authorization: Bearer <your-jwt-token>"

# Response 204 (No Content)

๐Ÿงช Testing

The project includes comprehensive test coverage using JUnit 5, Spring Test, and Testcontainers.

Running Tests

# Run all tests
./gradlew test

# Run a specific test class
./gradlew test --tests com.dhaliwal.notemind.controller.NoteControllerTest

# Run with coverage report
./gradlew test jacocoTestReport

# View coverage report (generated in build/reports/jacoco/test/html/index.html)

Test Structure

src/test/java/com/dhaliwal/notemind/
โ”œโ”€โ”€ controller/           # Controller integration tests
โ”œโ”€โ”€ service/             # Service unit tests
โ”œโ”€โ”€ repository/          # Repository tests with Testcontainers
โ”œโ”€โ”€ security/            # JWT and Auth filter tests
โ””โ”€โ”€ resources/
    โ””โ”€โ”€ application-test.properties

Key Testing Patterns

  • Integration Tests: Use @SpringBootTest with Testcontainers for PostgreSQL
  • Unit Tests: Mock dependencies using Mockito
  • Security Tests: Use @WithMockUser for testing secured endpoints
  • Repository Tests: Test complex JPA queries with real database

Example Test

@SpringBootTest
@Testcontainers
public class NoteControllerTest {
    @Container
    static PostgreSQLContainer<?> postgres = 
        new PostgreSQLContainer<>("postgres:15")
            .withDatabaseName("notemind_ai_test");

    @Test
    void testCreateNote_shouldGenerateSummary() {
        // Test implementation
    }
}

โšก Performance & Optimization

Caching Strategy

  • L1 Cache (Redis): Individual notes cached with TTL
  • Cache Invalidation: Automatic eviction on update/delete operations
  • Cache Keys: Structured as note::{id} for easy management

Database Optimization

Optimization Implementation
Full-Text Search PostgreSQL tsvector with GIN indexes
Query Indexing Indexes on user_id, folder_id, created_at
Pagination All list endpoints support page and size parameters
N+1 Prevention JPA lazy loading with @Fetch(FetchMode.JOIN)

Database Indexes

-- Automatically created indexes
CREATE INDEX idx_note_user_id ON note(user_id);
CREATE INDEX idx_note_folder_id ON note(folder_id);
CREATE INDEX idx_note_search_vector ON note USING GIN(search_vector);
CREATE INDEX idx_flashcard_note_id ON flash_card(note_id);
CREATE INDEX idx_refresh_token_user_id ON refresh_token(user_id);

Load Testing Recommendations

  1. Use tools like JMeter or Locust
  2. Test with concurrent users (10, 50, 100)
  3. Monitor Redis memory usage and eviction rates
  4. Monitor PostgreSQL query performance with pg_stat_statements

Example Load Test Command:

# Using Apache JMeter
jmeter -n -t load-test.jmx -l results.jtl -j logs.log -Jthreads=50 -Jduration=300

๐Ÿ” Security Best Practices

Authentication & Authorization

Practice Implementation
Password Storage BCrypt hashing (strength 10)
JWT Signing HMAC-SHA256 with 256-bit key
Token Expiry 15-minute access tokens, 7-day refresh tokens
Refresh Token Revocation Database tracking with revocation flag
User Isolation All queries automatically filtered by @AuthenticationPrincipal

API Security

// Example: All user notes are scoped
@GetMapping
public ResponseEntity<?> getAllNotes() {
    User currentUser = securityUtils.getCurrentUser(); // Automatic
    List<Note> notes = noteRepository.findByUser(currentUser);
    // Only current user's notes are returned
}

Data Protection

  • HTTPS Only: Configure SSL/TLS certificates in production
  • CORS Configuration: Restrict to trusted origins only
  • Rate Limiting: Implement to prevent brute force attacks
  • Input Validation: All DTOs validated with @Valid and custom validators
  • SQL Injection Prevention: All queries use JPA parameterized queries

Environment Variable Security

Never commit secrets! Use environment variables:

# โœ… Good - Environment variable
export GOOGLE_API_KEY="${GOOGLE_API_KEY}"

# โŒ Bad - Hardcoded in code
String apiKey = "AIza...";

Security Configuration

Key configuration in SecurityConfig.java:

  • CORS policies
  • CSRF protection disabled for stateless APIs
  • JWT filter registration
  • Password encoder configuration

๐Ÿ› Troubleshooting

Common Issues & Solutions

1. "Connection refused" - PostgreSQL

Problem: org.postgresql.util.PSQLException: Connection refused

Solution:

# Verify PostgreSQL is running
psql -U postgres -d postgres -c "SELECT version();"

# If not running, start it
# macOS
brew services start postgresql

# Linux
sudo systemctl start postgresql

# Verify connection string in application.properties
# Should be: jdbc:postgresql://localhost:5432/notemind_ai

2. "Connection refused" - Redis

Problem: io.lettuce.core.RedisConnectionException

Solution:

# Verify Redis is running
redis-cli ping  # Should return PONG

# If not running, start it
# macOS
brew services start redis

# Linux
sudo systemctl start redis-server

3. JWT Token Expired or Invalid

Problem: 401 Unauthorized

Solution:

# Get a new token using refresh token
curl -X POST http://localhost:8080/api/v1/auth/refresh-token \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "your-refresh-token"}'

# Or login again
curl -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "user", "password": "pass"}'

4. "Environment variable not found"

Problem: java.lang.NullPointerException or missing config values

Solution:

# Verify environment variables are set
echo $JWT_SECRET_KEY
echo $GOOGLE_API_KEY

# If missing, set them
export JWT_SECRET_KEY="your-secret"
export GOOGLE_API_KEY="your-key"

# Or uncomment values in application.properties for local development

5. Image Upload Fails (Cloudinary)

Problem: 403 Forbidden or Invalid Cloudinary credentials

Solution:

# Verify Cloudinary credentials
export CLOUD_NAME_CLOUDINARY="your-cloud-name"
export CLOUD_API_KEY_CLOUDINARY="your-api-key"
export CLOUD_API_SECRET_CLOUDINARY="your-api-secret"

# Test API key validity
curl -X GET "https://api.cloudinary.com/v1_1/${CLOUD_NAME_CLOUDINARY}/resources/image" \
  -u "${CLOUD_API_KEY_CLOUDINARY}:${CLOUD_API_SECRET_CLOUDINARY}"

6. Out of Memory (Gradle Build)

Problem: java.lang.OutOfMemoryError: Java heap space

Solution:

# Increase Gradle memory
export GRADLE_OPTS="-Xmx1024m"

# Or configure in gradle.properties
echo "org.gradle.jvmargs=-Xmx1024m" >> gradle.properties

# Run build
./gradlew build

7. Tests Failing with "Testcontainer not found"

Problem: Docker not running or Testcontainers configuration issue

Solution:

# Ensure Docker is running
docker --version
docker ps

# If Docker is not installed, install it
# Visit: https://www.docker.com/products/docker-desktop

# Run tests again
./gradlew test

Debug Mode

Enable debug logging to troubleshoot issues:

# Set debug level in application.properties
logging.level.root=INFO
logging.level.com.dhaliwal.notemind=DEBUG
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.web=DEBUG

# Or via environment variable
export LOGGING_LEVEL_COM_DHALIWAL_NOTEMIND=DEBUG
./gradlew bootRun

Health Check Endpoint

# Check application health (once added to config)
curl http://localhost:8080/actuator/health

# Expected response
{
  "status": "UP",
  "components": {
    "db": { "status": "UP" },
    "redis": { "status": "UP" }
  }
}

Getting Help

  1. Check logs: Look in build/reports/tests/test/index.html for test failures
  2. Database logs: Check PostgreSQL logs in /var/log/postgresql/
  3. Redis logs: Check Redis logs with redis-cli monitor
  4. Spring Boot logs: Look for stack traces in terminal output or logs directory

๐Ÿค Contributing

Getting Started

  1. Fork the repository

    git clone https://github.com/sukhmmeet/NoteMind-AI.git
    cd NoteMind-AI
  2. Create a feature branch

    git checkout -b feature/your-feature-name
  3. Make changes and commit

    git add .
    git commit -m "feat: add your feature description"
  4. Push and create a Pull Request

    git push origin feature/your-feature-name

Code Style Guidelines

  • Java: Follow Google Java Style Guide
  • Naming: Use descriptive names for variables, methods, and classes
  • Comments: Add comments for complex logic
  • Tests: Write tests for new features
  • Formatting: Use IDE auto-format (Ctrl+Alt+L in IntelliJ)

Git Commit Messages

type(scope): description

feat(auth): add OAuth2 support
fix(notes): resolve N+1 query issue
docs(readme): add Docker setup instructions
test(flashcards): add test for regenerate endpoint
refactor(services): extract AI logic to separate class

Commit Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • test: Tests
  • refactor: Code refactoring
  • perf: Performance improvement
  • chore: Dependency/build updates

Submitting Issues

When reporting bugs, include:

  1. Clear title and description
  2. Steps to reproduce
  3. Expected vs actual behavior
  4. Environment details (OS, Java version, etc.)
  5. Error logs/stack traces

๐Ÿ—„ Database Schema

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   app_users  โ”‚       โ”‚     note     โ”‚       โ”‚  flash_card  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค       โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค       โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ id (PK)      โ”‚โ”€โ”€โ”    โ”‚ id (PK)      โ”‚โ”€โ”€โ”    โ”‚ id (PK)      โ”‚
โ”‚ username     โ”‚  โ”‚    โ”‚ title        โ”‚  โ”‚    โ”‚ question     โ”‚
โ”‚ password     โ”‚  โ”‚    โ”‚ content      โ”‚  โ”‚    โ”‚ answer       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚    โ”‚ summary      โ”‚  โ”‚    โ”‚ created_at   โ”‚
                  โ”‚    โ”‚ summary_type โ”‚  โ”‚    โ”‚ note_id (FK) โ”‚โ”€โ”€โ†’ note
                  โ”‚    โ”‚ image_url    โ”‚  โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ”‚    โ”‚ search_vectorโ”‚  โ”‚
                  โ”‚    โ”‚ created_at   โ”‚  โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                  โ”‚    โ”‚ updated_at   โ”‚  โ”‚    โ”‚     tag      โ”‚
                  โ””โ”€โ”€โ†’ โ”‚ user_id (FK) โ”‚  โ”‚    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
                       โ”‚ folder_id(FK)โ”‚โ”€โ”€โ”ผโ”€โ”€โ†’ โ”‚ id (PK)      โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚    โ”‚ name (UNIQUE)โ”‚
                              โ”‚          โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚          โ”‚           โ”‚
                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚  note_tags   โ”‚  โ”‚    โ”‚   folder     โ”‚
                       โ”‚  (join table)โ”‚  โ”‚    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
                       โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚    โ”‚ id (PK)      โ”‚
                       โ”‚ note_id (FK) โ”‚  โ”‚    โ”‚ name         โ”‚
                       โ”‚ tag_id (FK)  โ”‚  โ”‚    โ”‚ user_id (FK) โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                         โ”‚    โ”‚ refresh_token โ”‚
                                         โ”‚    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
                                         โ”‚    โ”‚ id (PK)       โ”‚
                                         โ”‚    โ”‚ token (UNIQUE)โ”‚
                                         โ””โ”€โ”€โ†’ โ”‚ user_id (FK)  โ”‚
                                              โ”‚ expiry_date   โ”‚
                                              โ”‚ revoked       โ”‚
                                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key indexes:

  • GIN index on note.search_vector for full-text search
  • Unique constraint on (user_id, name) in folder table
  • Unique constraint on tag.name

๐Ÿ”ฎ Roadmap

Phase 1: Core Completion โœ…

  • Authentication & JWT
  • Note CRUD operations
  • AI summaries & tags
  • Flashcard generation
  • Image storage (Cloudinary)
  • Full-text search

Phase 2: Android App ๐Ÿ“ฑ

  • Android app with Kotlin & Jetpack Compose
  • Offline mode with local database
  • Push notifications
  • Mobile-optimized UI

Phase 3: Advanced Features ๐Ÿš€

  • ๐Ÿ’ฌ AI chat with notes (conversational Q&A over your notes)
  • ๐ŸŽ™๏ธ Voice notes with speech-to-text transcription
  • โœ๏ธ Rich Markdown editor with live preview
  • ๐Ÿ“Š Study analytics & spaced repetition scheduling
  • ๐ŸŽฏ Flashcard performance tracking

Phase 4: Collaboration & Scaling ๐ŸŒŸ

  • ๐Ÿ”— Note sharing & collaboration links
  • ๐Ÿ‘ฅ Real-time collaboration (WebSocket)
  • ๐Ÿ” Elasticsearch integration for advanced search
  • ๐Ÿ—‚๏ธ Tags and labels system enhancements
  • ๐Ÿ“ค Export notes to PDF, Word, Markdown

Phase 5: Integration & APIs ๐Ÿ”Œ

  • Notion API integration
  • Google Drive sync
  • Slack bot for quick notes
  • Browser extension for web clipping

๐Ÿ“Š Project Statistics

Metric Value
Backend Controllers 4
Service Classes 5+
Entities 8
API Endpoints 20+
Test Coverage 16+ test classes
External Integrations 3 (Google AI, OpenRouter, Cloudinary)

๐Ÿ“š Additional Resources


๐Ÿ‘จโ€๐Ÿ’ป Author

Sukhmeet Dhaliwal โ€” Computer Science Engineering Student

Acknowledgments

Special thanks to the open-source community for amazing tools like:

  • Spring Boot framework
  • PostgreSQL database
  • Redis caching
  • Google AI & OpenRouter for AI capabilities
  • Cloudinary for image storage

๐Ÿ“„ License

This project is open source and available under the MIT License.


โญ If you find this project useful, please consider giving it a star!

Built with โค๏ธ using Java, Spring Boot, PostgreSQL & AI

Stars Forks Issues License

About

NoteMind AI is an AI-powered notes platform currently under development for capturing, organizing, and enhancing knowledge. Built with Android (Jetpack Compose) and Spring Boot, it focuses on secure authentication, AI summarization, smart tagging, and fast full-text search.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages