mohd-faraz

_blogs

// blogs / 20260608.md

Dev Log: June 08 Wrap-up

2026-06-08
#Spring Boot#SQL#Database Design#Flyway#Backend

Overview

Today was a mix of architectural groundwork and some deep-sea diving into query logic. I moved from the 'high-level drawing' phase of the new e-commerce backend into actually laying down the database schema and getting the automation pipeline ready.

What I Worked On

Turning Diagrams into Reality

I spent a good chunk of time translating my ER diagrams into actual SQL migrations. I started with the coupons system. Since this is a multi-tenant setup, everything has to be scoped by a tenant_id. It’s a simple table on the surface—handling percentage and flat discounts—but getting the unique constraints right for tenant-specific codes is key.

I also spent some time on product_variants. I decided to use JSONB for variant attributes (like size or color). Schema flexibility is a lifesaver here because I really didn't want to deal with a separate table for every possible product property. It keeps the queries cleaner and the code a lot more maintainable.

Automating the Boring Stuff (Flyway)

I'm a big believer in 'day zero' migrations. I integrated Flyway into the Maven build today. There’s always that annoying 5-second window where your Spring Boot app tries to connect to a Dockerized Postgres instance before the DB is actually ready to talk. I added some retry logic in the dev profile to handle that:

spring:
  flyway:
    connect-retries: 5
    # No more crashing because Docker was sleepy

It's a small change, but it stops the 'app-crash-on-startup' loop that usually kills my flow.

Untangling Query Conflicts

Later in the day, I had to jump into a different project to fix some issues in a lead management decorator. We were seeing some conflicts where specific queries were clashing, especially when negating certain values. I ended up refactoring the way filter expressions are normalized before they hit the service layer.

I added a new query type for custom pagination and cleaned up the logic so that the filter normalization happens once, consistently, across all query types (sums, counts, and lists).

public BaseResource[] processQuery(Context ctx, String queryType, Map<String, Object> params) {
    // Normalize the expression early to prevent logic conflicts downstream
    Expression filter = normalize_logic(service.getExpression(ctx));
    
    return switch (queryType) {
        case "GET_TOTAL" -> handle_sum(filter, params);
        case "GET_PAGINATED" -> handle_page(filter, params);
        default -> throw new RuntimeException("Unknown query type");
    };
}

Wrapping Up

The backend foundation is feeling solid. It’s always satisfying to see the V10__ migration files start to pile up. Tomorrow, I’ll probably start looking at the security layer—specifically how I want to handle those tenant-scoped JWTs.

Catch you tomorrow.