Back to Portfolio
Tech Lead · 6-person TeamBackend Complete · Frontend in Progress2025 – Present

Flood Rescue Coordination

“Designed the architecture. Set up the infrastructure. Led the team.”

Spring Boot (Java 21)Next.jsMySQL (per service)RabbitMQApache KafkaNginxDocker ComposeGitHub ActionsVPS (Ubuntu)SSEREST

Overview

A 6-person team project to build a real-time coordination platform for flood rescue operations in Vietnam. As Tech Lead, my responsibility was architecture design, technology selection, full infrastructure setup, CI/CD pipeline, module skeleton (frontend + backend), and sprint management via Jira. The team builds features on top of the foundation I set up.

The Problem

Flood rescue operations in Vietnam suffer from coordination failures: rescue requests get lost, teams can't be tracked in real-time, relief supplies are distributed without visibility, and there's no unified operations view for coordinators.

No request visibility

Citizens have no way to submit structured rescue requests or track status. Coordinators receive requests through informal channels (phone, Zalo) with no geographic data.

No live team tracking

Coordinators can't see where rescue teams are in real-time. Assignment is done by phone call without proximity awareness.

Supply blindness

Relief supply managers have no visibility into inventory levels, distribution, or when to restock.

System Architecture

5-layer architecture: Client → Nginx API Gateway → 6 Spring Boot Microservices → RabbitMQ + Kafka → MySQL per service. Full DevOps automation via GitHub Actions → Docker Hub → VPS.

Architecture Diagram

Sprint 1 Progress — What's Built

Sprint 1 (4 Mar – 11 Mar): 6 of 10 tasks DONE, 1 IN PROGRESS. Core infrastructure and service skeletons are live.

6/10
Sprint 1 tasks completed
✓
Auth + API Gateway live
✓
RescueRequest + Dispatch impl
✓
FE + BE module skeleton
▶
SSE Notification (in progress)

Key Architectural Decisions

Three decisions that defined the entire system design:

Modular Monolith first, Microservices after

✓ Chosen
Modular Monolith in Sprint 1
✗ Rejected
Full microservices from day 1

Why: A 6-person team starting with 6 independent microservices means 6× the DevOps complexity before any business logic is validated. We validate domain boundaries in Sprint 1 as a modular monolith, then extract services once the seams are clear.

RabbitMQ + Kafka — not one or the other

✓ Chosen
RabbitMQ for task events, Kafka for streaming/audit
✗ Rejected
Kafka only or RabbitMQ only

Why: RabbitMQ gives exactly-once delivery for rescue task assignments — critical when one team must be assigned to exactly one request. Kafka gives a replayable audit log of all GPS positions and status changes — essential for post-incident analysis and reporting.

Database per Service from day 1

✓ Chosen
MySQL per microservice
✗ Rejected
Shared database, split later

Why: Sharing a database across services creates invisible coupling that's painful to remove later. Dedicated MySQL per service enforces the contract at the infrastructure level from the start.

System Design — 6 Microservices

Each service owns its domain, its database, and its API. Communication via RabbitMQ (task events) and Kafka (audit streams). Nginx as reverse proxy. GitHub Actions → Docker Hub → SSH VPS on push to main.

user-service :8081

rescue-request-service :8082

dispatch-service :8083

resource-service :8084

notification-service :8085

reporting-service :8086

CI/CD Pipeline

Every push to main triggers build → Docker image push → SSH deploy to VPS. Zero manual steps.

.github/workflows/deploy.ymlyaml
name: Deploy to VPS

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Build & push Docker image
        run: |
          docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/flood-rescue:latest .
          echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login \
            -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
          docker push ${{ secrets.DOCKERHUB_USERNAME }}/flood-rescue:latest

      - name: Deploy to VPS via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.VPS_SSH_KEY }}
          script: |
            cd /opt/flood-rescue
            docker compose pull
            docker compose up -d --remove-orphans

My Contribution as Tech Lead

What I personally designed and built before the team started feature development:

FE+BE
Module skeleton for entire team
Jira
Sprint planning + task delegation
Sprint 1
Active development now