Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Madda Logo

Madda - B2B Procurement Platform

A modern, real-time Request for Quotation (RFQ) platform connecting businesses with suppliers

Spring Boot Next.js TypeScript PostgreSQL Docker WebSocket

📖 Documentation🚀 Quick Start📡 API Docs🔧 Architecture


Table of Contents


Overview

Madda is a comprehensive B2B procurement platform that streamlines the Request for Quotation (RFQ) process between buyers and suppliers. Built with a microservices architecture, it offers real-time collaboration, secure authentication, and efficient business communication.

Key Capabilities

  • 🏢 Business Registration with license verification
  • 📝 RFQ Management with file attachments
  • 💬 Real-time Quotations via WebSocket
  • Quotation Lifecycle (Submit → Accept/Reject/Withdraw)
  • 👨‍💼 Admin Dashboard for user verification
  • 🔐 JWT-based Security with role-based access
  • 🐳 Docker Containerization for easy deployment

Features

🔐 Authentication & Authorization

  • JWT-based authentication with access and refresh tokens
  • Role-based access control (ADMIN, USER, SUPER_ADMIN)
  • Secure password hashing with BCrypt
  • Email verification with business license upload
  • Admin approval workflow for new registrations

📋 RFQ Management

  • Create, update, and manage RFQs
  • Upload multiple files per RFQ (brochures, specifications)
  • Set quantity requirements and categories
  • Track RFQ status (OPEN, CLOSED, CANCELLED)
  • Real-time updates to all connected clients

💰 Quotation System

  • Submit quotations in response to RFQs
  • Accept/Reject/Withdraw quotation workflow
  • One quotation per supplier per RFQ policy
  • Real-time notification via WebSocket
  • Quotation history and audit trail

👨‍💼 Admin Portal

  • Dashboard with user management
  • Approve/reject business registrations
  • View verification documents
  • Manage user roles and permissions
  • System-wide monitoring

🌐 Real-time Features

  • WebSocket connections for instant updates
  • STOMP protocol over SockJS
  • Automatic reconnection handling
  • Topic-based message routing
  • Cross-browser synchronization

Architecture

Microservices Design

┌─────────────────────────────────────────────────────────────────┐
│                        CLIENT LAYER                               │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │   Next.js    │  │   Next.js    │  │   Next.js    │          │
│  │   (Web)      │  │   (Web)      │  │   (Web)      │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     API GATEWAY (Port 8080)                       │
│              Spring Cloud Gateway + Load Balancer               │
└─────────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
┌─────────────────┐ ┌───────────────┐ ┌─────────────────┐
│  Admin Service  │ │ User Service  │ │  RFQ Service    │
│   (Port 8081)   │ │ (Port 8082)   │ │  (Port 8083)    │
│                 │ │               │ │                 │
│ • Auth/Admin    │ │ • User CRUD   │ │ • RFQ CRUD    │
│ • Bootstrap     │ │ • Auth/Login  │ │ • File Upload │
│ • Dashboard     │ │ • Register    │ │ • WebSocket   │
└─────────────────┘ └───────────────┘ └─────────────────┘
                                              │
┌─────────────────┐                  ┌─────────┴─────────┐
│ Quotation Svc   │◄─────────────────│                   │
│  (Port 8084)    │                  │  PostgreSQL DB    │
│                 │                  │  (RFQ Files)      │
│ • Quotations    │                  │                   │
│ • WebSocket     │                  └───────────────────┘
│ • Bid Status    │
└─────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                  INFRASTRUCTURE SERVICES                        │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────────┐    ┌──────────────────┐                  │
│  │  Eureka Server   │    │  PostgreSQL      │                  │
│  │  (Port 8761)     │    │  (Port 5432)     │                  │
│  │                  │    │                  │                  │
│  │ • Service Reg    │    │ • User DB        │                  │
│  │ • Load Balancing │    │ • RFQ DB         │                  │
│  │ • Health Checks  │    │ • Quotation DB   │                  │
│  └──────────────────┘    │ • Admin DB       │                  │
│                          └──────────────────┘                  │
└─────────────────────────────────────────────────────────────────┘

Service Communication

  • Synchronous: REST APIs via API Gateway
  • Asynchronous: WebSocket STOMP for real-time updates
  • Service Discovery: Eureka for service registration
  • Database: Separate PostgreSQL schemas per service

Tech Stack

Backend

Technology Purpose
Spring Boot 3.2+ Microservices framework
Spring Cloud Gateway API Gateway & routing
Spring Security Authentication & authorization
Spring WebSocket Real-time messaging
Eureka Service discovery
PostgreSQL Primary database
Flyway Database migrations
JWT Token-based auth
Lombok Boilerplate reduction
MapStruct DTO mapping

Frontend

Technology Purpose
Next.js 16 React framework
TypeScript Type safety
Tailwind CSS Styling
shadcn/ui UI components
@stomp/stompjs WebSocket client
Zustand State management
React Query Server state management
Axios HTTP client
Lucide React Icons

DevOps & Infrastructure

Technology Purpose
Docker Containerization
Docker Compose Multi-container orchestration
Maven Build tool
npm/pnpm Package management

Quick Start

Prerequisites

  • Java 17+
  • Node.js 18+
  • Docker & Docker Compose
  • Maven 3.8+

1. Clone Repository

git clone https://github.com/sileshidev/Madda.git
cd Madda

2. Start Infrastructure

cd backend
docker compose up -d postgres eureka
cd ..

3. Build & Start Backend Services

# Build all services
cd backend
mvn clean install -DskipTests

# Start all services with Docker
docker compose up -d

4. Start Frontend

cd frontend
npm install --legacy-peer-deps
npm run dev

5. Access Application

Default Credentials

Admin Bootstrap:

  • Email: admin@madda.et
  • Password: AdminPass123!

Test Users:

  • User 1: abebe.bikila@ethiopiantech.et / SecurePass123!
  • User 2: selamawit.girma@addisbuilders.et / SecurePass123!

Installation

Backend Setup

Option A: Docker (Recommended)

cd backend
docker compose up -d

Option B: Local Development

# 1. Start PostgreSQL
docker run -d \
  --name madda-postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  postgres:15-alpine

# 2. Start Eureka
mvn -f discovery-service/pom.xml spring-boot:run

# 3. Start services in order
mvn -f admin-service/pom.xml spring-boot:run
mvn -f user-service/pom.xml spring-boot:run
mvn -f rfq-service/pom.xml spring-boot:run
mvn -f quotation-service/pom.xml spring-boot:run
mvn -f api-gateway/pom.xml spring-boot:run

Frontend Setup

cd frontend

# Install dependencies
npm install --legacy-peer-deps

# Environment setup
cp .env.example .env.local

# Start development server
npm run dev

Environment Variables

Backend (.env or application.yml)

# Database
spring.datasource.url=jdbc:postgresql://localhost:5432/madda
spring.datasource.username=postgres
spring.datasource.password=postgres

# JWT
jwt.secret=your-secret-key-here
jwt.expiration=86400000

# Services
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

Frontend (.env.local)

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_RFQ_WS_URL=ws://localhost:8083/ws/rfqs
NEXT_PUBLIC_QUOTATION_WS_URL=ws://localhost:8084/ws/quotations

API Documentation

Authentication Endpoints

Method Endpoint Description
POST /api/v1/auth/register User registration
POST /api/v1/auth/login User login
POST /api/v1/auth/refresh Refresh token
POST /admin/auth/bootstrap Admin bootstrap
POST /admin/auth/login Admin login

User Endpoints

Method Endpoint Description
GET /api/v1/users/me Get current user
PUT /api/v1/users/me Update profile
POST /api/v1/users/me/company-logo Upload logo
POST /api/v1/users/{id}/verify Admin verify user

RFQ Endpoints

Method Endpoint Description
POST /api/v1/rfqs Create RFQ
GET /api/v1/rfqs List RFQs
GET /api/v1/rfqs/{id} Get RFQ details
PUT /api/v1/rfqs/{id} Update RFQ
DELETE /api/v1/rfqs/{id} Delete RFQ
POST /api/v1/rfqs/{id}/files Upload file
POST /api/v1/rfqs/{id}/cancel Cancel RFQ
POST /api/v1/rfqs/{id}/close Close RFQ

Quotation Endpoints

Method Endpoint Description
POST /api/v1/quotations Submit quotation
GET /api/v1/quotations List quotations
GET /api/v1/quotations/my My quotations
PUT /api/v1/quotations/{id} Update quotation
DELETE /api/v1/quotations/{id} Delete quotation
POST /api/v1/quotations/{id}/withdraw Withdraw quotation
POST /api/v1/quotations/{id}/accept Accept quotation
POST /api/v1/quotations/{id}/reject Reject quotation

Example Requests

User Registration

curl -X POST http://localhost:8080/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "fullName": "Abebe Bikila",
    "email": "abebe.bikila@ethiopiantech.et",
    "password": "SecurePass123!",
    "phoneNumber": "+251911234567",
    "companyName": "Ethiopian Tech Solutions",
    "companyType": "TECHNOLOGY",
    "businessLicenseNumber": "BLS-2024-12345",
    "verificationDocumentUrl": "https://drive.google.com/file/d/..."
  }'

Create RFQ

curl -X POST http://localhost:8080/api/v1/rfqs \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Server Infrastructure",
    "description": "Looking for cloud servers",
    "category": "TECHNOLOGY",
    "quantity": 10,
    "unit": "PCS"
  }'

Submit Quotation

curl -X POST http://localhost:8080/api/v1/quotations \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "rfqId": "550e8400-e29b-41d4-a716-446655440000",
    "description": "We can provide AWS EC2 instances..."
  }'

WebSocket Real-time Updates

Connection

Connect to WebSocket endpoints for real-time updates:

// RFQ Service WebSocket
const rfqClient = new Client({
  brokerURL: 'ws://localhost:8083/ws/rfqs',
  onConnect: () => {
    // Subscribe to public RFQ updates
    rfqClient.subscribe('/topic/rfqs/public', (message) => {
      console.log('New RFQ:', JSON.parse(message.body));
    });
    
    // Subscribe to user-specific updates
    rfqClient.subscribe(`/topic/rfqs/user/${userId}`, (message) => {
      console.log('Your RFQ updated:', JSON.parse(message.body));
    });
  }
});
rfqClient.activate();

WebSocket Topics

Topic Purpose Message Format
/topic/rfqs/public All RFQ updates {type: 'CREATED'|'UPDATED'|'DELETED', data: {...}}
/topic/rfqs/user/{id} User's RFQ updates {type: 'CREATED'|'UPDATED'|'DELETED', data: {...}}
/topic/quotations/public All quotation updates {type: 'CREATED'|'UPDATED'|'STATUS_CHANGED', data: {...}}
/topic/quotations/user/{id} User's quotation updates {type: 'CREATED'|'UPDATED'|'STATUS_CHANGED', data: {...}}
/topic/quotations/rfq/{id} RFQ-specific quotations {type: 'CREATED'|'UPDATED', data: {...}}

Message Types

interface WebSocketMessage {
  type: 'CREATED' | 'UPDATED' | 'DELETED' | 'STATUS_CHANGED';
  data: RFQ | Quotation;
  timestamp: string;
}

Database Schema

Entity Relationship Diagram

┌─────────────────┐       ┌─────────────────┐       ┌─────────────────┐
│     users       │       │      rfqs       │       │  quotations     │
├─────────────────┤       ├─────────────────┤       ├─────────────────┤
│ id (PK)         │       │ id (PK)         │       │ id (PK)         │
│ full_name       │       │ user_id (FK)    │◄──────│ rfq_id (FK)     │
│ email           │       │ title           │       │ user_id (FK)    │
│ password        │       │ description     │       │ description     │
│ phone_number    │       │ category        │       │ status          │
│ company_name    │       │ quantity        │       │ created_at      │
│ company_type    │       │ unit            │       │ updated_at      │
│ business_license│       │ status          │       └─────────────────┘
│ verified        │       │ created_at      │
│ role            │       │ updated_at      │
│ created_at      │       └─────────────────┘
│ updated_at      │              │
└─────────────────┘              │       ┌─────────────────┐
                                 └──────►│   rfq_files   │
                                        ├─────────────────┤
                                        │ id (PK)         │
                                        │ rfq_id (FK)     │
                                        │ file_name       │
                                        │ file_url        │
                                        │ created_at      │
                                        └─────────────────┘

Key Tables

users

  • Stores user and business information
  • Includes verification status and business license
  • Supports ADMIN, USER, SUPER_ADMIN roles

rfqs

  • Request for Quotation entities
  • Status: OPEN, CLOSED, CANCELLED
  • Linked to user (buyer)

quotations

  • Supplier responses to RFQs
  • Status: PENDING, ACCEPTED, REJECTED, WITHDRAWN
  • One quotation per supplier per RFQ

rfq_files

  • Attachments for RFQs
  • Stores file metadata and URLs

Configuration

Service Ports

Service Port Description
API Gateway 8080 Entry point for all clients
Eureka Server 8761 Service registry
Admin Service 8081 Admin operations
User Service 8082 User management
RFQ Service 8083 RFQ operations + WebSocket
Quotation Service 8084 Quotation operations + WebSocket
PostgreSQL 5432 Database
Frontend 3000 Next.js dev server

Security Configuration

# JWT Configuration
jwt:
  secret: ${JWT_SECRET:your-256-bit-secret-key-here}
  expiration: 86400000  # 24 hours
  refresh-expiration: 604800000  # 7 days

# CORS Configuration
cors:
  allowed-origins: 
    - http://localhost:3000
    - https://madda.app
  allowed-methods: GET, POST, PUT, DELETE, OPTIONS
  allowed-headers: Authorization, Content-Type

Development

Project Structure

Madda/
├── backend/
│   ├── api-gateway/           # Spring Cloud Gateway
│   │   └── src/main/
│   │       ├── java/com/madda/gateway/
│   │       └── resources/application.yml
│   ├── discovery-service/     # Eureka Server
│   ├── admin-service/         # Admin operations
│   ├── user-service/          # User management
│   ├── rfq-service/           # RFQ + WebSocket
│   ├── quotation-service/     # Quotations + WebSocket
│   └── docker-compose.yml
├── frontend/
│   ├── src/
│   │   ├── app/              # Next.js pages
│   │   ├── components/       # React components
│   │   ├── hooks/            # Custom hooks (useWebSocket)
│   │   ├── lib/              # Utilities
│   │   └── types/            # TypeScript types
│   ├── public/               # Static assets
│   └── package.json
├── README.md
└── LICENSE

Code Organization

Backend:

  • Controller → Service → Repository pattern
  • DTOs for request/response
  • Entities for database
  • Mappers (MapStruct) for conversion
  • Global exception handling
  • WebSocket controllers for real-time

Frontend:

  • App Router (Next.js 13+)
  • Server and Client components
  • Custom hooks for WebSocket
  • Zustand for global state
  • React Query for server state
  • API client with Axios

Running Tests

# Backend tests
cd backend
mvn test

# Frontend tests
cd frontend
npm test

# E2E tests (if configured)
npm run test:e2e

Adding a New Service

  1. Create new Spring Boot module
  2. Add to pom.xml parent
  3. Configure Eureka client
  4. Add API Gateway route
  5. Update docker-compose.yml

Deployment

Docker Compose (Production)

version: '3.8'
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data

  eureka:
    build: ./discovery-service
    ports:
      - "8761:8761"

  api-gateway:
    build: ./api-gateway
    ports:
      - "8080:8080"
    environment:
      - EUREKA_URL=http://eureka:8761/eureka

  # ... other services

Environment Variables

Create .env file:

# Database
DB_PASSWORD=secure_password_here

# JWT
JWT_SECRET=your-super-secret-jwt-key-min-256-bits

# Services
EUREKA_URL=http://eureka:8761/eureka

Deploy

docker compose -f docker-compose.prod.yml up -d

Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Contribution Guidelines

  • Follow existing code style
  • Write meaningful commit messages
  • Add tests for new features
  • Update documentation
  • Ensure all tests pass

License

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


Support


Acknowledgments

  • Spring Boot team for the amazing framework
  • Next.js team for the React framework
  • shadcn/ui for beautiful components
  • The open-source community

Built with ❤️ by the Madda Team

⬆ Back to Top

About

Madd Request For Quotation Platform

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages