I use a modular folder structure to organize the codebase by feature rather than by technical layer.
This approach makes the project more scalable, maintainable, and easier to navigate as new features are added.
All requirements from the initial repository README have been fulfilled.
Additional Features:
- Liquibase integration
- Dockerized Application
- Swagger Documentation: http://localhost:8080/swagger-ui/index.html#/ (accessible after starting the
notesServicecontainer) - Postman / Hoppscotch Collection for API testing
docker compose up --build
3. Follow the steps in tests.md
- Sign up
- Log in
- Perform CRUD operations for Notes
├── Dockerfile // Container build instructions for the application
├── README.md // Project overview, setup, and usage guide
├── db-changelog // Liquibase changelogs for database version control
├── docker-compose.yml // Compose file to spin up app and dependencies (DB, etc.)
├── pom.xml // Maven dependencies and build configuration
├── secret-keys // Externalized secret keys (encryption, JWT signing) (KEYS IN REPO ARE FOR TESTING ONLY - Exel)
├── src
│ ├── main
│ │ ├── java/com/agridence/microservice/Assignment
│ │ │ ├── configuration // Security filters, encryption setup, application configs
│ │ │ ├── dto // API request and response payload classes (clean separation from entities)
│ │ │ ├── exception // Global exception handling and custom application exceptions
│ │ │ ├── modules // Modular structure for isolated business features
│ │ │ │ ├── notes // Notes feature module: controller, entity, service, repository
│ │ │ │ └── users // Users feature module: controller, entity, service, repository
│ │ │ └── utils // Reusable utility classes (JWT operations, encryption, password hashing)
│ │ └── resources
│ │ └── application.properties // Application-specific configuration (ports, keys, etc.)
While the NOTE table has a foreign key relationship to USER in the database,
the Notes Service intentionally does not depend on the User entity or ORM mappings to retrieve user details.
This is a deliberate architectural choice to maintain strict modular boundaries between features:
- Each feature module (users, notes, etc.) operates independently, with minimal cross-dependencies.
- The Notes Service retrieves the authenticated user's ID directly from the JWT token, rather than relying on User entity lookups.
- This enforces clear separation of concerns:
- The Users module handles user registration, authentication, and secure credential storage.
- The Notes module manages note creation, retrieval, and ownership validation based on the user ID extracted from the security context.
Why I chose this:
- Promotes scalability and feature isolation as the codebase grows.
- Reduces unintended coupling between modules.
- Allows future add on services to evolve independently without tight ORM interdependencies.
erDiagram
USERS {
BIGSERIAL id PK
VARCHAR username
VARCHAR password
VARCHAR full_name
TIMESTAMP created_at
}
NOTES {
BIGSERIAL id PK
VARCHAR title
TEXT description
BIGINT user_id FK
TIMESTAMP created_at
}
USERS ||--o{ NOTES : "owns many"
sequenceDiagram
participant Client
participant AuthService
Client ->> AuthService: Sign Up (username, password, full name)
AuthService -->> Client: Sign Up Success
sequenceDiagram
participant Client
participant AuthService
Client ->> AuthService: Login (username, password)
alt Valid credentials
AuthService -->> Client: Return JWT Access Token
else Invalid credentials
AuthService -->> Client: Error "invalid username/password"
end
sequenceDiagram
participant Client
participant NotesService
Client ->> NotesService: Add Note (JWT, title, description)
NotesService ->> NotesService: Validate JWT
NotesService -->> Client: Note Created Success
sequenceDiagram
participant Client
participant NotesService
Client ->> NotesService: View Note Details (JWT, noteId)
NotesService ->> NotesService: Validate JWT
NotesService ->> NotesService: Check Note Ownership
alt Note belongs to user
NotesService -->> Client: Note Details (title, description)
else Unauthorized Access
NotesService -->> Client: Error "Access Denied"
end
sequenceDiagram
participant Client
participant NotesService
Client ->> NotesService: Delete Note (JWT, noteId)
NotesService ->> NotesService: Validate JWT
NotesService ->> NotesService: Check Note Ownership
alt Note belongs to user
NotesService -->> Client: Note Deleted
else Unauthorized Access
NotesService -->> Client: Error "Access Denied"
end