Skip to content

remsysc/BulagFaust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

81 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BulagFaust - Modern Blog Platform Backend

Java Spring Boot PostgreSQL License

A RESTful blog platform built with Spring Boot 3

Features β€’ Tech Stack β€’ Getting Started β€’ API Documentation β€’ Project Highlights β€’ Future Roadmap


πŸ“‹ Table of Contents


🎯 Overview

BulagFaust is a full-featured blog platform backend that demonstrates enterprise-level Spring Boot development practices. The system provides complete CRUD operations for blog posts, categories, and tags, with role-based access control, JWT authentication, and production-ready error handling.

The name "BulagFaust" represents a journey from blindness (Bulag) to mastery (Faust) β€” symbolizing the learning process throughout this project's development.


✨ Features

Core Functionality

  • πŸ“ Post Management - Create, read, update, and delete blog posts with draft/published status
  • 🏷️ Tag System - Dynamic tag creation and assignment (auto-creates tags if they don't exist)
  • πŸ“ Category Organization - Hierarchical content categorization
  • πŸ‘€ User Authentication - JWT-based authentication with role-based authorization
  • πŸ” Role-Based Access Control - ADMIN and USER roles with granular permissions

Technical Features

  • Pagination & Sorting - Efficient data retrieval with customizable page sizes
  • Filtering - Filter posts by category, tag, or author
  • Reading Time Calculation - Automatic reading time estimation (200 WPM)
  • Soft Validation - Comprehensive input validation with meaningful error messages
  • Database Indexing - Optimized queries with strategic indexes on status, author, and timestamps
  • N+1 Query Prevention - Batch loading with @BatchSize for efficient tag retrieval

πŸ› οΈ Tech Stack

Category Technology
Language Java 21
Framework Spring Boot 3.2.4
Security Spring Security + JWT (JJWT 0.13.0)
Database PostgreSQL
ORM Spring Data JPA + Hibernate
Validation Jakarta Validation API 3.1.1
Object Mapping MapStruct 1.6.3
Boilerplate Reduction Lombok 1.18.42
Containerization Docker + Docker Compose
Build Tool Maven 3.x

πŸš€ Getting Started

Prerequisites

  • Java 21 or higher
  • Maven 3.6+
  • Docker & Docker Compose (for database)
  • Git

Quick Start

  1. Clone the repository

    git clone https://github.com/yourusername/BulagFaust.git
    cd BulagFaust
  2. Start the database with Docker Compose

    docker-compose up -d

    This starts:

    • PostgreSQL on localhost:5432
    • Adminer (database UI) on localhost:8081
  3. Configure the application

    Update src/main/resources/application.properties if needed:

    spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
    spring.datasource.username=postgres
    spring.datasource.password=postgres
  4. Build and run

    ./mvnw clean install
    ./mvnw spring-boot:run
  5. Access the application

    • API Base URL: http://localhost:8080/api/v1
    • Default Admin: admin@localhost / admin123

Database Credentials (Development)

Service Host Port Username Password
PostgreSQL localhost 5432 postgres postgres
Adminer localhost 8081 postgres postgres

⚠️ Security Notice: Change default credentials in production!


πŸ“š API Documentation

Authentication Endpoints

Method Endpoint Description Auth Required
POST /api/v1/auth/register Register new user ❌
POST /api/v1/auth/login User login ❌

Post Endpoints

Method Endpoint Description Auth Required
GET /api/v1/posts Get all posts (paginated) ❌
GET /api/v1/posts/{id} Get post by ID ❌
POST /api/v1/posts Create new post βœ…
PATCH /api/v1/posts/{id} Update post βœ… (Owner only)
DELETE /api/v1/posts/{id} Delete post βœ… (Owner only)

Query Parameters for GET /posts:

  • categoryId - Filter by category UUID
  • tagId - Filter by tag UUID
  • page - Page number (default: 0)
  • size - Page size (default: 20)
  • sort - Sort field (default: createdAt, DESC)

Category Endpoints

Method Endpoint Description Auth Required
GET /api/v1/categories Get all categories ❌
POST /api/v1/categories Create category βœ… (ADMIN only)
PATCH /api/v1/categories/{id} Update category βœ… (ADMIN only)
DELETE /api/v1/categories/{id} Delete category βœ… (ADMIN only)

Tag Endpoints

Method Endpoint Description Auth Required
GET /api/v1/tags Get all tags ❌
POST /api/v1/tags Create tag βœ…

Example Usage

1. Register a New User

curl -X POST http://localhost:8080/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "username": "johndoe",
    "email": "john@example.com",
    "password": "securepass123"
  }'

Response:

{
  "timestamp": "2026-03-03T10:30:00",
  "status": 201,
  "message": "Registered successfully",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": "uuid-here",
      "username": "johndoe",
      "email": "john@example.com"
    }
  }
}

2. Login

curl -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "john@example.com",
    "password": "securepass123"
  }'

3. Create a Post

curl -X POST http://localhost:8080/api/v1/posts \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "title": "My First Blog Post",
    "content": "This is the content of my amazing post...",
    "categoryIds": ["category-uuid-here"],
    "tagNames": ["spring", "java", "backend"]
  }'

4. Get All Posts (with filtering)

curl -X GET "http://localhost:8080/api/v1/posts?size=10&page=0&sort=createdAt,desc"

5. Update a Post

curl -X PATCH http://localhost:8080/api/v1/posts/{post-id} \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "title": "Updated Title",
    "status": "PUBLISHED"
  }'

🌟 Project Highlights

What Was Done Well

1. Clean Architecture & Separation of Concerns

com.sysc.bulag_faust/
β”œβ”€β”€ auth/          # Authentication & authorization
β”œβ”€β”€ category/      # Category management
β”œβ”€β”€ post/          # Post business logic
β”œβ”€β”€ tag/           # Tag management
β”œβ”€β”€ user/          # User management
β”œβ”€β”€ role/          # Role-based access
└── core/          # Cross-cutting concerns
    β”œβ”€β”€ exceptions/
    β”œβ”€β”€ security/
    β”œβ”€β”€ response/
    └── utils/

Why it matters: Each module is self-contained, making the codebase maintainable and testable.

2. Efficient Database Queries

  • Batch Loading: Used @BatchSize(size = 20) to prevent N+1 queries when loading tags
  • Strategic Indexing: Added indexes on frequently queried columns (status, author_id, created_at)
  • Pagination: All list endpoints support pagination to handle large datasets
// Example: Efficient tag resolution - single SELECT for all tags
private Set<Tag> resolveOrCreateTags(Set<String> tagNames) {
    List<Tag> existing = tagRepository.findAllByNameIn(normalized);
    // Only INSERT new tags, avoiding duplicate queries
}

3. Robust Error Handling

  • Centralized @RestControllerAdvice with 15+ exception handlers
  • Consistent error response format with timestamps
  • Appropriate HTTP status codes for different error scenarios
  • Detailed logging for debugging without exposing sensitive info

4. Security Best Practices

  • JWT token-based authentication (stateless)
  • BCrypt password hashing
  • Role-based authorization (hasRole("ADMIN"), authenticated())
  • CORS configuration for frontend integration
  • SQL injection prevention via JPA parameterized queries

5. Domain-Driven Design

  • Rich domain models with business logic encapsulated in entities
  • @PrePersist and @PreUpdate for automatic timestamp management
  • Entity validation methods (validateForPublish())
  • Immutable DTOs with Java records

6. Performance Optimizations

  • Automatic reading time calculation (200 WPM algorithm)
  • Lazy loading for relationships
  • open-in-view=false to prevent session leaks
  • Efficient batch operations for tag creation

πŸ“– Lessons Learned

Things Done Differently (Growth Moments)

1. From Anemic to Rich Domain Models

Before: Entities were just data containers with getters/setters.

Now: Entities encapsulate business logic:

// Post entity handles its own validation
public void publish() {
    this.status = PostStatus.PUBLISHED;
    validateForPublish(); // Self-validation
}

Why: Reduces service layer bloat and keeps logic close to data.

2. From save() to Lifecycle Callbacks

Before: Manual timestamp and reading time calculation in services.

Now: Using JPA lifecycle callbacks:

@PrePersist
protected void onCreate() {
    this.createdAt = LocalDateTime.now();
    setReadingTime(); // Automatic
}

Why: DRY principle - logic defined once, triggered automatically.

3. From Generic Exceptions to Custom Hierarchy

Before: Throwing IllegalArgumentException everywhere.

Now: Custom exception hierarchy:

throw new NotFoundException("Post", id);
throw new AlreadyExistException("User", email);

Why: Clearer intent, consistent error responses, easier debugging.

4. From Eager to Strategic Lazy Loading

Before: FetchType.EAGER on all relationships.

Now: FetchType.LAZY with @BatchSize for collections:

@BatchSize(size = 20)
private Set<Tag> tags;

Why: Prevents performance issues with large datasets.

5. From Manual Mapping to MapStruct

Before: Manual DTO-to-entity conversion.

Now: Type-safe compile-time mapping with MapStruct:

@Mapper
public interface PostMapper {
    PostResponse toResponse(Post post);
}

Why: Reduces boilerplate, catches mapping errors at compile time.

6. From Monolithic Services to Layered Architecture

Before: All logic in controllers.

Now: Clear separation:

Controller β†’ Service β†’ Repository β†’ Entity
     ↓          ↓          ↓          ↓
  HTTP      Business    Data      Domain
  Logic     Logic      Access    Logic

Why: Testability, maintainability, single responsibility.


πŸ”§ Areas for Improvement

Current Limitations

1. Testing Coverage

  • ❌ No unit tests for services
  • ❌ No integration tests for controllers
  • ❌ No test containers for database testing
  • ❌ No mock objects for external dependencies

Impact: Risk of regressions, harder refactoring.

2. Caching Strategy

  • ❌ No Redis or second-level cache
  • ❌ Repeated database queries for frequently accessed data
  • ❌ No cache invalidation strategy

Impact: Slower response times under load.

3. Rate Limiting & Security Hardening

  • ❌ No rate limiting on authentication endpoints
  • ❌ No account lockout after failed attempts
  • ❌ No brute force protection
  • ❌ No request throttling

Impact: Vulnerable to DoS and brute force attacks.

4. API Versioning

  • ⚠️ Only v1 endpoints exist
  • ⚠️ No backward compatibility strategy
  • ⚠️ Breaking changes would require immediate migration

Impact: Difficult to evolve API without disrupting clients.

5. Documentation

  • ❌ No OpenAPI/Swagger documentation
  • ❌ No API contract testing
  • ❌ Minimal inline documentation

Impact: Harder for frontend teams to integrate.

6. Database Migrations

  • ❌ No Flyway/Liquibase for version control
  • ❌ Manual schema management
  • ❌ No rollback strategy

Impact: Risk of schema drift between environments.

7. Logging & Monitoring

  • ⚠️ Basic logging with SLF4J
  • ❌ No structured logging (JSON)
  • ❌ No metrics collection (Micrometer)
  • ❌ No distributed tracing

Impact: Difficult to debug production issues.

8. Code Quality

  • ⚠️ No SonarQube integration
  • ⚠️ No code coverage reports
  • ⚠️ Inconsistent exception messages

πŸš€ Future Roadmap (API v2)

Security & Performance

Feature Why
Redis Rate Limiting Prevent API abuse and DDoS attacks by limiting requests per user/IP
Account Lockout Mechanism Protect against brute force attacks by locking accounts after failed login attempts
Redis Caching Reduce database load and improve response times for frequently accessed data

Testing

Feature Why
JUnit 5 Write unit tests to verify business logic and catch regressions early
Mockito Mock dependencies for isolated, fast unit testing
TestContainers Run integration tests against real PostgreSQL instances in Docker
MockMvc Test REST controllers without starting the full server

API v2 Features

Feature Why
Comments System Enable user engagement and discussions on blog posts
Reactions/Likes Allow readers to express appreciation without writing comments
User Analytics Provide insights on post performance and reader engagement
Image Upload Support rich content with embedded images in posts
Full-Text Search Help users find relevant content quickly across all posts

Database & Code Quality

Feature Why
Flyway/Liquibase Version control database schema changes and enable safe rollbacks
OpenAPI/Swagger Auto-generated API documentation for easier frontend integration

πŸ“ API Response Format

Success Response

{
  "timestamp": "2026-03-03T10:30:00",
  "status": 200,
  "message": "Retrieved all posts",
  "data": {
    "content": [...],
    "pageable": {...},
    "totalElements": 100,
    "totalPages": 5
  }
}

Error Response

{
  "timestamp": "2026-03-03T10:30:00",
  "code": "NOT_FOUND",
  "message": "Post not found with id: 123e4567-e89b-12d3-a456-426614174000"
}

πŸ—οΈ Architecture Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client    β”‚ ──────> β”‚   Controller β”‚ ──────> β”‚   Service   β”‚
β”‚ (Frontend)  β”‚  HTTP   β”‚   (REST)     β”‚  Call   β”‚  (Business) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”‚
                                                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PostgreSQL β”‚ <────── β”‚  Repository  β”‚ <────── β”‚    Entity   β”‚
β”‚  (Database) β”‚   JPA   β”‚    (JPA)     β”‚  Query  β”‚   (Domain)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ‘¨β€πŸ’» Author

Developed by: Rem Project: BulagFaust - Spring Boot Blog Platform


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


Built with ❀️ using Spring Boot

⬆ Back to Top

About

A blog post.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages