A personal Java interview-prep tool. Build a glossary of Java concepts, track where each definition came from, and work through a structured book-based learning roadmap — all in one place.
Java Dictionary is a personal interview-prep tool for building a glossary of Java concepts. Each term stores two definitions — a casual one (your own mental model) and a formal one (the polished, interviewer-ready answer) — because writing both is what builds real understanding, not just memorization. Terms are grouped by name across source books and chapters, so the same concept can appear multiple times as your understanding evolves, and you can add terms manually outside of any book.
- Create, edit, and delete terms manually
- Flat term model: each entry has a casual and formal definition, a source (book + chapter), and tags
- Multiple entries per term name — one per source, grouped together for display
- Tag entries for categorization and filtering
- Filter and search terms by keyword, tag, or source book
- Learning Roadmap — a YAML-driven structured path through Java fundamentals, with curated resources and research hints for each term; submit definitions directly from the roadmap without leaving the page
- Duplicate protection — manual terms deduplicated by name, book-sourced terms by (name, book, chapter)
- Smart delete redirect — stays on the group page if other entries exist, returns to index if the last one is deleted
- REST API with OpenAPI/Swagger UI documentation
- Thymeleaf-rendered UI
- Schema version control via Flyway
- Java 21
- Maven (or use the included
./mvnwwrapper — no separate install needed) - Docker Desktop
git clone https://github.com/SerenePrince/java-dictionary.git
cd java-dictionaryMake sure Docker Desktop is running. If this is your first project, create the shared container once:
docker run -d \
--name postgres \
--restart unless-stopped \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres:18Then create the database for this project:
docker exec -it postgres psql -U postgres -c "CREATE DATABASE dictionary;"The container starts automatically with Docker Desktop — no manual restarts needed.
./mvnw spring-boot:runThe app starts on http://localhost:8080. Flyway runs the schema migrations automatically — no manual setup needed.
./mvnw testTests use Mockito for unit tests and @WebMvcTest for controller slice tests. No database connection required.
If you ever need to repair the schema history (e.g. after editing a migration file that was already applied):
./mvnw flyway:repair| Layer | Technology |
|---|---|
| Framework | Spring Boot 4 |
| Language | Java 21 |
| Frontend | Thymeleaf + Bootstrap 5 |
| Database | PostgreSQL 18 |
| Migrations | Flyway |
| Build Tool | Maven |
| API Docs | SpringDoc OpenAPI (Swagger UI) |
The decision to use Thymeleaf instead of a separate frontend framework was intentional. This project demonstrates Spring Boot end-to-end — backend, templating, data layer, all of it.
The app uses Spring profiles to separate local and production configuration:
| Profile | File | When it's used |
|---|---|---|
dev |
application-dev.properties |
Local development |
prod |
application-prod.properties |
Deployment / production |
application.properties holds shared settings common to both profiles. The dev profile is active by default — no flags needed to run locally.
Prod profile — set the following as secrets in your deployment service:
SPRING_PROFILES_ACTIVE=prod
DB_URL=jdbc:postgresql://<host>:<port>/<database>
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password
Base path: /api/v1/terms
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/terms |
Get all term groups. Supports ?search=, ?tag=, and ?book= query params |
GET |
/api/v1/terms/slug/{slug} |
Get a single term group by slug (all entries sharing that name) |
GET |
/api/v1/terms/{id} |
Get a single term entry by database ID |
POST |
/api/v1/terms |
Create a new manual term (no source book or chapter) |
PUT |
/api/v1/terms/{id} |
Update a term entry. Manual terms: all fields. Book-sourced: definitions only |
DELETE |
/api/v1/terms/{id} |
Delete a single term entry |
The full interactive API reference is available at /swagger-ui.html when the app is running. The Thymeleaf views are served under /terms and /roadmap.
Terms are stored flat. There is no nested definition or experience-level structure.
| Field | Type | Notes |
|---|---|---|
id |
Long | Primary key |
name |
String | Display name (e.g. "Garbage Collection") |
slug |
String | URL-safe identifier derived from name (e.g. "garbage-collection") |
casualDefinition |
String | Plain-language explanation |
formalDefinition |
String | Precise, interview-ready definition |
sourceBook |
String | Source book title; null for manual terms |
sourceChapter |
String | Chapter within the source book; null for manual terms |
tags |
Set | Keyword tags (stored in term_tags table) |
A manual term has both sourceBook and sourceChapter set to null. The database enforces uniqueness with two separate constraints: a composite unique on (name, source_book, source_chapter) for book-sourced terms, and a partial unique index on name WHERE both source columns are null for manual terms — because SQL treats NULL != NULL and a standard unique constraint cannot cover this case.
The same term name can appear in multiple rows when sourced from different books or chapters. The service layer groups these rows by slug before returning them to the UI or API.
The learning roadmap is defined entirely in src/main/resources/roadmap.yaml. No code changes are needed to add new volumes, chapters, or terms — just edit the YAML.
Each volume maps to a source book. Each chapter within a volume maps to a chapter in that book. Each entry specifies the term to define, suggested tags, external learning resources, and guided research hints (what, why, how).
When a definition is submitted from the roadmap UI, it is saved as a book-sourced term with sourceBook and sourceChapter set from the YAML config. If a definition already exists for that (term, book, chapter) combination, the UI asks for confirmation before overriding it.
Standard Spring Boot layered architecture:
src/
└── main/
├── java/com/noahparknguyen/javadictionary/
│ ├── config/
│ │ ├── OpenApiConfig.java # SpringDoc API metadata
│ │ └── roadmap/ # @ConfigurationProperties for roadmap.yaml
│ ├── controller/
│ │ ├── TermController.java # REST API (/api/v1/terms)
│ │ ├── TermViewController.java # Thymeleaf UI (/terms)
│ │ └── RoadmapController.java # Thymeleaf UI (/roadmap)
│ ├── dto/
│ │ ├── request/ # POST / PUT / roadmap form bodies
│ │ └── response/ # Term, group, and roadmap view models
│ ├── exception/ # GlobalExceptionHandler + custom exceptions
│ ├── mapper/
│ │ └── TermMapper.java # Entity ↔ DTO conversion + grouping logic
│ ├── model/
│ │ └── Term.java # JPA entity
│ ├── repository/
│ │ └── TermRepository.java # Spring Data JPA + custom JPQL queries
│ └── service/
│ ├── TermService.java # Term CRUD + uniqueness rules
│ └── RoadmapService.java # Config-DB bridge for roadmap views
└── resources/
├── db/migration/ # Flyway SQL migrations (V1, V2, V3)
├── static/ # CSS + JS assets
├── templates/ # Thymeleaf views (terms, roadmap, fragments)
├── application.properties # Shared config
├── application-dev.properties # Local dev overrides
├── application-prod.properties # Production overrides
└── roadmap.yaml # Roadmap volumes, chapters, entries, and hints
- Complete the Core Java Vol I roadmap content
- Deployment on Render
- Authentication — currently a single-user personal tool
MIT © Noah Park-Nguyen