Project Requirements Review
Over the past 17 lectures, you built a blog platform piece by piece — each lecture adding one capability. This final lecture ties everything together into a coherent, production-ready system.
Functional Requirements
Our blog platform supports these user stories:
Visitors (unauthenticated):
- Browse published posts with pagination and sorting
- View a single post with its comments
- Search posts by keyword
- Browse posts by category or tag
- View author profiles
- Register a new account
Authenticated Users (ROLE_USER):
- Everything visitors can do
- Add comments on posts
- Reply to existing comments
- Upload and change their avatar
- Edit their own profile
Authors (ROLE_AUTHOR):
- Everything users can do
- Create new blog posts (saved as DRAFT)
- Edit and delete their own posts
- Upload cover images for their posts
- Publish their own draft posts
- Manage tags on their own posts
Admins (ROLE_ADMIN):
- Everything authors can do
- Edit and delete any post
- Publish any post
- Manage categories (CRUD)
- Manage tags (CRUD)
- Change user roles
- Deactivate user accounts
- View cache statistics and system health
Non-Functional Requirements
- Performance: Average response time < 200ms for cached endpoints, < 500ms for database queries
- Security: JWT authentication, BCrypt password hashing, input validation, role-based authorization
- Reliability: Health checks, graceful error handling, transaction management
- Maintainability: Layered architecture, DTOs, consistent error format, comprehensive tests
- Deployability: Docker containerization, environment-based configuration, CI/CD pipeline
System Architecture Diagram
The Full Stack
┌─────────────────────────────────────────────────────────────────┐
│ CLIENTS │
│ Browser Mobile App Postman Other APIs │
└──────────────────────────┬──────────────────────────────────────┘
│ HTTPS
┌──────────────────────────▼──────────────────────────────────────┐
│ NGINX (Reverse Proxy) │
│ • SSL Termination │
│ • Static file serving (/api/files/) │
│ • Rate limiting │
│ • Gzip compression │
└──────────────────────────┬──────────────────────────────────────┘
│ HTTP (port 8080)
┌──────────────────────────▼──────────────────────────────────────┐
│ SPRING BOOT APPLICATION │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Security Filter Chain │ │
│ │ CORS → JWT Filter → Authorization Filter │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Controller Layer │ │
│ │ AuthController PostController UserController │ │
│ │ FileController CategoryController AdminController │ │
│ │ • Receives HTTP requests │ │
│ │ • Validates input (@Valid) │ │
│ │ • Returns HTTP responses │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Service Layer │ │
│ │ AuthService PostService UserService CommentService │ │
│ │ UploadService CategoryService TagService │ │
│ │ • Business logic & validation │ │
│ │ • Transaction management (@Transactional) │ │
│ │ • DTO ↔ Entity conversion │ │
│ │ • Caching (@Cacheable, @CacheEvict) │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Repository Layer │ │
│ │ UserRepository PostRepository CommentRepository │ │
│ │ CategoryRepository TagRepository UploadedFileRepository │ │
│ │ • JpaRepository interfaces │ │
│ │ • Derived queries, @Query (JPQL/native) │ │
│ │ • Pagination and sorting │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Hibernate / JPA / HikariCP │ │
│ │ • ORM mapping (Entity ↔ Table) │ │
│ │ • SQL generation │ │
│ │ • Connection pooling │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
│ JDBC (port 3306)
┌──────────────────────────────▼──────────────────────────────────┐
│ MariaDB 11 │
│ • blogdb database │
│ • Flyway-managed schema (V1–V13 migrations) │
│ • InnoDB engine, utf8mb4 charset │
│ • Indexes for query performance │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ FILESYSTEM │
│ /var/data/blog-api/uploads/ │
│ ├── posts/ (cover images) │
│ └── avatars/ (user avatars) │
└──────────────────────────────────────────────────────────────────┘
Technology Stack Summary
| Layer | Technology | Lecture |
|---|---|---|
| Language | Java 17 | Prerequisite |
| Framework | Spring Boot 3.3 | Lecture 1–2 |
| Web | Spring MVC | Lecture 3 |
| Database | MariaDB 11 | Lecture 4 |
| ORM | Spring Data JPA + Hibernate | Lecture 5–7 |
| Validation | Jakarta Bean Validation | Lecture 8 |
| Error Handling | @ControllerAdvice | Lecture 8 |
| Transactions | Spring @Transactional | Lecture 9 |
| Logging | SLF4J + Logback | Lecture 9 |
| Migration | Flyway | Lecture 10 |
| Security | Spring Security + JWT | Lecture 11–12 |
| File Storage | Local filesystem | Lecture 13 |
| Documentation | SpringDoc OpenAPI / Swagger | Lecture 14 |
| Testing | JUnit 5, Mockito, TestContainers | Lecture 15 |
| Caching | Caffeine | Lecture 16 |
| Deployment | Docker, Docker Compose, Nginx | Lecture 17 |
| CI/CD | GitHub Actions | Lecture 17 |
Database Schema Final Design
Entity-Relationship Overview
users ──────────┐
│ │
│ 1:1 │ 1:N
▼ ▼
user_profiles posts ◄──── categories (N:1)
│
├─── comments (1:N, self-referencing for replies)
│
└─── post_tags ───► tags (M:N)
│
└─── uploaded_files (1:1 cover image)
users ──── uploaded_files (1:1 avatar)
Complete Table List
| Table | Purpose | Key Relationships |
|---|---|---|
users |
User accounts with credentials and roles | Has one profile, has one avatar |
user_profiles |
Extended user info (website, social links) | Belongs to one user |
categories |
Post grouping (Tutorial, News, etc.) | Has many posts |
tags |
Post labels (Java, Spring Boot, etc.) | Many-to-many with posts |
posts |
Blog articles | Belongs to user and category, has many comments and tags |
post_tags |
Junction table for posts ↔ tags | References posts and tags |
comments |
Post comments with nested replies | Belongs to post and user, self-referencing parent |
uploaded_files |
File metadata (name, path, type, size) | Belongs to uploader (user) |
flyway_schema_history |
Migration tracking (managed by Flyway) | System table |
Flyway Migrations Summary
V1__create_users_table.sql
V2__create_categories_table.sql
V3__create_tags_table.sql
V4__create_posts_table.sql
V5__create_post_tags_table.sql
V6__create_comments_table.sql
V7__add_views_count_to_posts.sql
V8__add_index_on_posts_published_at.sql
V9__normalize_post_status_values.sql
V10__remove_deprecated_meta_columns.sql
V11__ensure_user_security_fields.sql
V12__create_uploaded_files_table.sql
V13__add_performance_indexes.sql
V100__seed_initial_data.sql
R__create_post_statistics_view.sql
Each migration is immutable and version-controlled. Running all migrations from an empty database produces the complete schema.
Implementing All Features End-to-End
The Complete Project Package Structure
src/main/java/com/example/blogapi/
├── BlogApiApplication.java ← Entry point
│
├── config/
│ ├── CacheConfig.java ← Caffeine cache configuration
│ └── OpenApiConfig.java ← Swagger/OpenAPI configuration
│
├── controller/
│ ├── AuthController.java ← Register, login, refresh token
│ ├── PostController.java ← Post CRUD, publish, search, comments
│ ├── UserController.java ← User profile, avatar upload
│ ├── CategoryController.java ← Category CRUD
│ ├── TagController.java ← Tag CRUD
│ ├── FileController.java ← Serve uploaded files
│ └── AdminController.java ← User management, cache stats
│
├── dto/
│ ├── CreatePostRequest.java ← POST /api/posts body
│ ├── UpdatePostRequest.java ← PUT /api/posts/{id} body
│ ├── PostResponse.java ← Post data returned to client
│ ├── CreateCommentRequest.java ← POST /api/posts/{id}/comments body
│ ├── CommentResponse.java ← Comment data returned to client
│ ├── RegisterRequest.java ← POST /api/auth/register body
│ ├── LoginRequest.java ← POST /api/auth/login body
│ ├── AuthResponse.java ← Login/register response with JWT
│ ├── UserResponse.java ← User profile data
│ ├── FileUploadResponse.java ← Upload result metadata
│ └── ErrorResponse.java ← Consistent error format
│
├── exception/
│ ├── GlobalExceptionHandler.java ← @ControllerAdvice for all errors
│ ├── ResourceNotFoundException.java ← 404 errors
│ ├── DuplicateResourceException.java ← 409 errors
│ └── BadRequestException.java ← 400 errors
│
├── mapper/
│ ├── PostMapper.java ← Post entity ↔ PostResponse
│ ├── CommentMapper.java ← Comment entity ↔ CommentResponse
│ └── UserMapper.java ← User entity ↔ UserResponse
│
├── model/
│ ├── BaseEntity.java ← @MappedSuperclass with audit fields
│ ├── User.java ← User entity
│ ├── UserProfile.java ← User profile entity
│ ├── Post.java ← Post entity with relationships
│ ├── Comment.java ← Comment entity (self-referencing)
│ ├── Category.java ← Category entity
│ ├── Tag.java ← Tag entity
│ └── UploadedFile.java ← File metadata entity
│
├── repository/
│ ├── UserRepository.java ← findByUsername, findByEmail, exists
│ ├── PostRepository.java ← findByStatus, searchByKeyword, JOIN FETCH
│ ├── CommentRepository.java ← findTopLevelByPostId, countByPostId
│ ├── CategoryRepository.java ← findBySlug
│ ├── TagRepository.java ← findBySlug
│ └── UploadedFileRepository.java ← basic CRUD
│
├── security/
│ ├── SecurityConfig.java ← Filter chain, CORS, endpoint rules
│ ├── JwtTokenProvider.java ← Generate, validate, parse JWT
│ ├── JwtAuthenticationFilter.java ← Extract token from every request
│ ├── JwtAuthenticationEntryPoint.java ← Custom 401 response
│ ├── CustomUserDetailsService.java ← Load user from MariaDB
│ └── PostSecurity.java ← isAuthor() check for @PreAuthorize
│
├── service/
│ ├── AuthService.java ← Register, login, refresh
│ ├── PostService.java ← Post business logic + caching
│ ├── CommentService.java ← Comment business logic
│ ├── UserService.java ← User profile management
│ ├── CategoryService.java ← Category business logic
│ ├── TagService.java ← Tag business logic
│ ├── FileStorageService.java ← Store/load/delete files on disk
│ └── UploadService.java ← Tie files to posts and users
│
└── validation/
├── UniqueUsername.java ← Custom validator annotation
└── UniqueUsernameValidator.java ← Validator implementation
This is approximately 45 Java files — a realistic size for a well-structured Spring Boot application.
User Registration, Login, JWT Auth
The Complete Auth Flow
Register: POST /api/auth/register
→ Validate input (@Valid)
→ Check duplicate username/email
→ Hash password (BCrypt)
→ Save user (ROLE_USER)
→ Return success message
Login: POST /api/auth/login
→ Validate input (@Valid)
→ AuthenticationManager.authenticate()
→ CustomUserDetailsService.loadUserByUsername()
→ PasswordEncoder.matches()
→ Generate access token (24h)
→ Generate refresh token (7d)
→ Return tokens + user info
Refresh: POST /api/auth/refresh
→ Validate refresh token
→ Extract username from token
→ Verify user is still active
→ Generate new access token
→ Return new token
Every request:
→ JwtAuthenticationFilter extracts token from Authorization header
→ JwtTokenProvider validates signature + expiration
→ SecurityContext populated with user info
→ @PreAuthorize checks permissions
→ Controller handles request
Key Security Decisions
| Decision | Choice | Why |
|---|---|---|
| Password storage | BCrypt (strength 10) | Industry standard, salted, intentionally slow |
| Token type | JWT (HS256) | Stateless, self-contained, cross-platform |
| Access token TTL | 24 hours | Balance between security and UX |
| Refresh token TTL | 7 days | Users stay logged in for a week |
| Session management | STATELESS | No server-side session state |
| CSRF | Disabled | Not needed for stateless JWT APIs |
CRUD for Posts, Comments, Tags, Categories
Complete API Endpoint Map
Posts:
GET /api/posts ← List posts (paginated, filterable)
GET /api/posts/{id} ← Get single post with details
GET /api/posts/slug/{slug} ← Get post by URL slug
GET /api/posts/search?keyword= ← Search posts
POST /api/posts ← Create post [AUTHOR, ADMIN]
PUT /api/posts/{id} ← Update post [author of post, ADMIN]
PATCH /api/posts/{id}/publish ← Publish post [author of post, ADMIN]
PATCH /api/posts/{id}/archive ← Archive post [ADMIN]
DELETE /api/posts/{id} ← Delete post [ADMIN]
POST /api/posts/{id}/cover-image ← Upload cover image [author of post, ADMIN]
POST /api/posts/{id}/comments ← Add comment [authenticated]
GET /api/posts/{id}/comments ← List comments (paginated)
Categories:
GET /api/categories ← List all categories
GET /api/categories/{slug} ← Get category by slug
POST /api/categories ← Create category [ADMIN]
PUT /api/categories/{id} ← Update category [ADMIN]
DELETE /api/categories/{id} ← Delete category [ADMIN]
Tags:
GET /api/tags ← List all tags
POST /api/tags ← Create tag [ADMIN]
DELETE /api/tags/{id} ← Delete tag [ADMIN]
Users:
GET /api/users/{id} ← Get user profile (public info)
PUT /api/users/me ← Update own profile [authenticated]
POST /api/users/me/avatar ← Upload avatar [authenticated]
Admin:
GET /api/admin/users ← List all users [ADMIN]
PATCH /api/admin/users/{id}/role ← Change user role [ADMIN]
PATCH /api/admin/users/{id}/deactivate ← Deactivate user [ADMIN]
GET /api/admin/cache/stats ← Cache statistics [ADMIN]
DELETE /api/admin/cache ← Clear all caches [ADMIN]
Auth:
POST /api/auth/register ← Register new user
POST /api/auth/login ← Login and get JWT tokens
POST /api/auth/refresh ← Refresh access token
Files:
GET /api/files/{*path} ← Serve uploaded file (public)
Total: ~30 endpoints covering all CRUD operations, authentication, file management, and administration.
Search, Pagination, Filtering
Standard Pagination Parameters
Every list endpoint follows the same pagination pattern:
GET /api/posts?page=0&size=10&sort=createdAt&direction=desc&status=PUBLISHED
| Parameter | Default | Description |
|---|---|---|
page |
0 | Page number (0-indexed) |
size |
10 | Items per page |
sort |
createdAt | Field to sort by |
direction |
desc | Sort direction (asc/desc) |
Standard Pagination Response
Every paginated response uses Spring Data’s Page:
{
"content": [ ... ],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": { "sorted": true }
},
"totalElements": 45,
"totalPages": 5,
"first": true,
"last": false,
"numberOfElements": 10
}
Frontend developers can build pagination controls using totalPages, first, last, and pageNumber.
Search Implementation
GET /api/posts/search?keyword=spring+boot&page=0&size=10
The search query uses JPQL with LIKE for simple search or MariaDB FULLTEXT index for advanced search:
// JPQL search (works without special indexes)
@Query("SELECT p FROM Post p WHERE " +
"LOWER(p.title) LIKE LOWER(CONCAT('%', :keyword, '%')) OR " +
"LOWER(p.content) LIKE LOWER(CONCAT('%', :keyword, '%'))")
Page<Post> searchByKeyword(@Param("keyword") String keyword, Pageable pageable);
Filtering Options
GET /api/posts?status=PUBLISHED ← Filter by status
GET /api/posts?tag=spring-boot ← Filter by tag slug
GET /api/posts?category=tutorial ← Filter by category slug
GET /api/posts?author=alice ← Filter by author username
File Upload for Post Images
Upload Flow
Client Server
| |
| POST /api/posts/1/cover-image |
| Authorization: Bearer <token> |
| Content-Type: multipart/form-data |
| [file binary data] |
| ─────────────────────────────────────────>|
| |
| 1. Validate file (type, size, name) |
| 2. Generate unique filename (UUID) |
| 3. Store file on disk |
| 4. Save metadata to uploaded_files |
| 5. Link file to post (cover_image_id) |
| 6. Delete old cover image if exists |
| |
| 201 Created |
| {"fileId":1,"url":"/api/files/..."} |
| <─────────────────────────────────────────|
File Serving
Uploaded files are served publicly with caching headers:
GET /api/files/posts/a1b2c3d4.jpg
→ FileStorageService.loadFileAsResource()
→ Response with Content-Type: image/jpeg
→ Cache-Control: max-age=86400 (browser caches for 24h)
In production with Nginx, static files are served directly by Nginx (bypassing Spring Boot) for better performance.
Role-Based Access (Admin, Author, Reader)
The Authorization Matrix
| Action | Visitor | USER | AUTHOR | ADMIN |
|---|---|---|---|---|
| Browse published posts | ✅ | ✅ | ✅ | ✅ |
| Search posts | ✅ | ✅ | ✅ | ✅ |
| Register account | ✅ | — | — | — |
| Add comments | ❌ | ✅ | ✅ | ✅ |
| Upload avatar | ❌ | ✅ | ✅ | ✅ |
| Create posts | ❌ | ❌ | ✅ | ✅ |
| Edit own posts | ❌ | ❌ | ✅ | ✅ |
| Delete own posts | ❌ | ❌ | ❌ | ✅ |
| Edit any post | ❌ | ❌ | ❌ | ✅ |
| Delete any post | ❌ | ❌ | ❌ | ✅ |
| Manage categories | ❌ | ❌ | ❌ | ✅ |
| Manage users | ❌ | ❌ | ❌ | ✅ |
| View system health | ❌ | ❌ | ❌ | ✅ |
Implementation Layers
Authorization is enforced at two levels:
Level 1: URL-based (SecurityConfig) — Broad rules based on HTTP method and path.
.requestMatchers(HttpMethod.GET, "/api/posts/**").permitAll()
.requestMatchers(HttpMethod.POST, "/api/posts").hasAnyRole("AUTHOR", "ADMIN")
.requestMatchers("/api/admin/**").hasRole("ADMIN")
Level 2: Method-based (@PreAuthorize) — Fine-grained rules with business logic.
@PreAuthorize("hasRole('ADMIN') or @postSecurity.isAuthor(#id, authentication.name)")
public PostResponse updatePost(Long id, UpdatePostRequest request) { ... }
API Documentation, Testing, Docker Deployment
API Documentation
Swagger UI at /swagger-ui.html provides:
- Every endpoint with parameters and request/response schemas
- “Try it out” functionality for interactive testing
- JWT authentication via the “Authorize” button
- Grouped by tags: Authentication, Posts, Users, Categories, Tags, Files, Admin
Testing Strategy
| Test Type | Count | Coverage |
|---|---|---|
| Service layer unit tests (Mockito) | ~30 | Business logic, validation, exceptions |
| Repository tests (@DataJpaTest) | ~15 | Custom queries, pagination, data integrity |
| Controller tests (@WebMvcTest) | ~20 | HTTP status codes, validation, auth |
| Integration tests (@SpringBootTest) | ~5 | Full flows: register → login → CRUD |
| Total | ~70 | Service: 80%+, Controller: 70%+ |
Run all tests:
./mvnw verify
Docker Deployment
# Development
docker compose up -d
# Production (with .env secrets)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
The application starts in under 15 seconds:
MariaDB: Ready for connections (5s)
Flyway: Applied 15 migrations (3s)
Hibernate: Schema validated (2s)
Tomcat: Started on port 8080 (3s)
Application ready (Total: ~13s)
Code Review Checklist & Best Practices Recap
Architecture Checklist
☐ Layered architecture: Controller → Service → Repository
☐ Dependencies flow downward only
☐ Controllers handle HTTP, not business logic
☐ Services handle business logic, not HTTP
☐ Repositories handle data access, not business logic
☐ DTOs separate API contract from domain model
☐ Entities never cross the controller boundary
☐ Mappers convert between entities and DTOs
Entity Design Checklist
☐ Every relationship uses FetchType.LAZY
☐ @ManyToMany uses Set, not List
☐ Collections are initialized (= new ArrayList<>())
☐ equals() and hashCode() use id only, with null safety
☐ Helper methods keep bidirectional relationships in sync
☐ No @OneToMany for potentially unbounded collections
☐ @JsonIgnore on entity back-references (or use DTOs exclusively)
☐ @PrePersist/@PreUpdate or BaseEntity for timestamps
Service Layer Checklist
☐ @Transactional(readOnly = true) at class level
☐ @Transactional on write methods
☐ Guard clauses validate before doing work
☐ Custom exceptions (ResourceNotFoundException, BadRequestException)
☐ Logging at INFO for business events, WARN for unusual cases
☐ Private helper methods for reusable logic
☐ DTO mapping while Hibernate session is open
Security Checklist
☐ Passwords hashed with BCrypt (never stored plain text)
☐ JWT secret is 256+ bits, stored as environment variable
☐ CSRF disabled (stateless API)
☐ Sessions disabled (STATELESS)
☐ Public endpoints explicitly marked with permitAll()
☐ @PreAuthorize for method-level authorization
☐ Custom AuthenticationEntryPoint for consistent 401 responses
☐ File uploads validated (type, size, filename)
Database Checklist
☐ Flyway manages all schema changes (ddl-auto=validate)
☐ Migrations are immutable once applied
☐ Indexes on columns used in WHERE, ORDER BY, JOIN
☐ Foreign keys enforce referential integrity
☐ utf8mb4 charset for emoji support
☐ No SELECT * — use projections for list pages
☐ N+1 problems fixed with JOIN FETCH or @EntityGraph
Testing Checklist
☐ Unit tests for service layer business logic
☐ @DataJpaTest for custom repository queries
☐ @WebMvcTest for controller HTTP behavior
☐ Integration tests for critical flows (auth, CRUD)
☐ Tests follow Arrange-Act-Assert pattern
☐ Each test is independent (no shared mutable state)
☐ 80%+ line coverage on service layer
Deployment Checklist
☐ Multi-stage Dockerfile (build + runtime)
☐ Non-root user in Docker container
☐ Docker health check configured
☐ docker-compose.yml with depends_on health checks
☐ Named volumes for data persistence
☐ Secrets in environment variables, not in code
☐ Actuator health endpoint exposed
☐ Swagger UI disabled in production
☐ Logging to file with rotation
What You Have Learned
Looking back at where you started — a Java developer with no web experience — here is what you now know:
Web Fundamentals: HTTP protocol, request/response cycle, REST architecture, client-server communication, content negotiation.
Spring Boot: Auto-configuration, dependency injection, component scanning, profiles, property management, embedded server.
REST API Design: HTTP methods mapped to CRUD, path variables vs query parameters, response entities, status codes, API versioning.
Database: MariaDB administration, SQL queries, indexing, normalization, entity-relationship design.
ORM: JPA entities, Hibernate mapping, relationships (1:1, 1:N, M:N), cascade types, fetch strategies, dirty checking.
Spring Data JPA: Repository interfaces, derived queries, JPQL, native SQL, pagination, projections, auditing.
Architecture: Layered architecture, DTO pattern, service layer design, transaction management, business logic patterns.
Data Integrity: Bean validation, custom validators, global error handling, consistent error responses.
Logging: SLF4J, log levels, parameterized messages, file output, environment-specific configuration.
Database Migration: Flyway versioned migrations, repeatable migrations, baseline, team workflow.
Security: Spring Security filter chain, authentication vs authorization, BCrypt, JWT tokens, role-based access control.
Performance: Caching with Caffeine, query optimization with EXPLAIN, indexing strategies, connection pooling, batch operations.
Testing: Unit tests (Mockito), repository tests (@DataJpaTest), controller tests (@WebMvcTest), integration tests (@SpringBootTest), TestContainers.
Deployment: Docker, Docker Compose, Nginx reverse proxy, CI/CD with GitHub Actions, production configuration, health checks.
API Documentation: OpenAPI specification, Swagger UI, schema annotations, interactive testing.
Where to Go Next
This series gave you a complete foundation. Here are paths to continue your growth:
Deepen Spring Boot
- Spring WebFlux — Reactive programming for high-concurrency applications
- Spring Cloud — Microservices patterns (service discovery, config server, circuit breakers)
- Spring Batch — Large-scale batch processing (data imports, report generation)
- Spring WebSocket — Real-time bidirectional communication
Expand the Blog Platform
- Add a React or Vue frontend that consumes your API
- Implement email notifications (new comment, post published)
- Add full-text search with Elasticsearch
- Implement real-time comments with WebSocket
- Add social login (OAuth2 with Google/GitHub)
- Build an admin dashboard with analytics
Production Skills
- Kubernetes — Container orchestration for scaling beyond single-server
- Monitoring — Prometheus + Grafana for metrics visualization
- Log aggregation — ELK Stack (Elasticsearch, Logstash, Kibana)
- Message queues — RabbitMQ or Kafka for async processing
- CDN — CloudFront or Cloudflare for static file delivery
Best Practices
- Read “Effective Java” by Joshua Bloch — the definitive guide to writing good Java
- Study “Clean Architecture” by Robert Martin — architecture principles that transcend frameworks
- Practice on real projects — build something you actually use
Final Words
You started this series knowing Java but nothing about web development. Now you have built a production-ready REST API with authentication, file uploads, caching, testing, and Docker deployment — from scratch, understanding every layer.
The most important skill you have developed is not Spring Boot or JPA or Docker. It is the ability to decompose a complex system into manageable layers, each with clear responsibilities and well-defined interfaces. This skill transfers to any framework, any language, any platform.
Build something real. Deploy it. Show it to people. Break it, fix it, improve it. That is how you grow from a student to an engineer.
Good luck.
