Skip to content
Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Messaging Service

A production-grade unified messaging service that supports SMS, MMS, and Email messaging with conversation management, built with Go 1.24 and clean architecture principles.

πŸš€ Features

  • Unified Messaging API: Send SMS, MMS, and Email messages through a single API
  • Conversation Management: Automatic grouping of messages into conversations
  • Data Persistence: PostgreSQL database with proper indexing and constraints
  • Webhook Support: Handle incoming messages from external providers
  • Error Handling: Retry logic with exponential backoff for provider errors (500, 429)
  • Production-Ready: Dockerized with multi-stage builds, health checks, and security
  • API Documentation: Interactive Swagger/OpenAPI documentation served by the main application
  • Clean Architecture: Separation of concerns with dependency injection
  • Comprehensive Testing: Unit, integration, and API tests
  • HTTP Error Handling: Robust retry logic for provider errors (500, 429, etc.)

πŸ› οΈ Quick Start

Prerequisites

  • Go 1.24+
  • Docker and Docker Compose
  • Make (optional, for convenience)

Development Setup

  1. Clone and setup:

    git clone <repository-url>
    cd messaging-service
    make setup
  2. Generate Swagger documentation:

    make swagger
  3. Start the application:

    make run
  4. Access the API:

Docker Setup

  1. Start the full stack (database + application):

    make docker-up
  2. Access the application:

  3. Stop the stack:

    make docker-down

πŸ“š API Documentation

The API documentation is automatically generated and served by the main application:

Available Endpoints

Method Endpoint Description
POST /api/messages/message Send SMS/MMS message
POST /api/messages/email Send email message
POST /api/webhooks/message Handle incoming SMS/MMS
POST /api/webhooks/email Handle incoming email
GET /api/conversations List conversations by query - query params required
GET /api/conversations/:id/messages Get messages in conversation
GET /health Health check endpoint

πŸ—„οΈ Database Schema

Conversations Table

CREATE TABLE conversations (
    id SERIAL PRIMARY KEY,
    participant1 VARCHAR(255) NOT NULL,
    participant2 VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Messages Table

CREATE TABLE messages (
    id SERIAL PRIMARY KEY,
    conversation_id INTEGER REFERENCES conversations(id),
    from_address VARCHAR(255) NOT NULL,
    to_address VARCHAR(255) NOT NULL,
    message_type VARCHAR(10) NOT NULL,
    body TEXT NOT NULL,
    attachments JSONB,
    provider_message_id VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

πŸ§ͺ Testing

Run All Tests

make test

Run Specific Test Types

# Unit tests only
go test ./internal/... -v

# Integration tests only
go test ./tests/... -v

# API tests
./bin/test.sh

🐳 Docker Commands

Command Description
make docker-build Build Docker image
make docker-up Start the full stack (database + app)
make docker-down Stop the full stack
make docker-logs View logs

βš™οΈ Configuration

The application uses environment variables for configuration. See CONFIGURATION.md for all available options.

Key Environment Variables

# Server Configuration
SERVER_PORT=8080
SERVER_READ_TIMEOUT=30s
SERVER_WRITE_TIMEOUT=30s
SERVER_IDLE_TIMEOUT=60s

# Database Configuration
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=messaging_service
DATABASE_USER=messaging_user
DATABASE_PASSWORD=messaging_password
DATABASE_MAX_OPEN_CONNS=25
DATABASE_MAX_IDLE_CONNS=5
DATABASE_CONN_MAX_LIFETIME=5m

πŸ—οΈ Architecture

System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Client Applications                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚   Web App   β”‚  β”‚  Mobile App β”‚  β”‚   External  β”‚          β”‚
β”‚  β”‚             β”‚  β”‚             β”‚  β”‚   Services   β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ HTTP/HTTPS
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Messaging Service API                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    Middleware Layer                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚   β”‚
β”‚  β”‚  β”‚ Request ID  β”‚ β”‚  Logging    β”‚ β”‚   Metrics   β”‚     β”‚   β”‚
β”‚  β”‚  β”‚             β”‚ β”‚             β”‚ β”‚             β”‚     β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                              β”‚                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    HTTP Handlers                       β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚   β”‚
β”‚  β”‚  β”‚   SMS/MMS   β”‚ β”‚    Email    β”‚ β”‚ Webhooks    β”‚     β”‚   β”‚
β”‚  β”‚  β”‚   Handler   β”‚ β”‚   Handler   β”‚ β”‚   Handler   β”‚     β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Business Logic Layer                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                  Service Layer                          β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚   β”‚
β”‚  β”‚  β”‚ Messaging   β”‚ β”‚Conversation β”‚ β”‚ Validation  β”‚     β”‚   β”‚
β”‚  β”‚  β”‚  Service    β”‚ β”‚  Service    β”‚ β”‚   Logic     β”‚     β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Data Access Layer                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                 Repository Layer                        β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚   β”‚
β”‚  β”‚  β”‚   Message   β”‚ β”‚Conversation β”‚ β”‚   Database  β”‚     β”‚   β”‚
β”‚  β”‚  β”‚ Repository  β”‚ β”‚ Repository  β”‚ β”‚  Connection β”‚     β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    External Services                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚   SMS/MMS   β”‚  β”‚    Email    β”‚  β”‚  Database   β”‚          β”‚
β”‚  β”‚  Provider   β”‚  β”‚  Provider   β”‚  β”‚ (PostgreSQL)β”‚          β”‚
β”‚  β”‚             β”‚  β”‚             β”‚  β”‚             β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Request Flow

1. Client Request
   ↓
2. Middleware Processing
   β”œβ”€β”€ Request ID Generation
   β”œβ”€β”€ Structured Logging
   └── Metrics Collection
   ↓
3. Route Matching
   ↓
4. Handler Processing
   β”œβ”€β”€ Request Validation
   β”œβ”€β”€ Business Logic
   └── Response Formatting
   ↓
5. Service Layer
   β”œβ”€β”€ Business Rules
   β”œβ”€β”€ Data Validation
   └── External Calls
   ↓
6. Repository Layer
   β”œβ”€β”€ Database Operations
   └── Data Persistence
   ↓
7. External Providers
   β”œβ”€β”€ SMS/MMS Delivery
   β”œβ”€β”€ Email Delivery
   └── Webhook Processing

Data Flow Examples

Outbound Message Flow:

Client β†’ POST /api/messages/message
  ↓
Handler.SendSMS() β†’ Validate Request
  ↓
Service.SendSMS() β†’ Business Logic
  ↓
Provider.SendSMS() β†’ External SMS Service
  ↓
Repository.Create() β†’ Save to Database
  ↓
Response β†’ Success/Error

Inbound Webhook Flow:

External Service β†’ POST /api/webhooks/message
  ↓
Handler.HandleInboundSMS() β†’ Parse Webhook
  ↓
Service.HandleInboundSMS() β†’ Process Message
  ↓
Repository.Create() β†’ Save to Database
  ↓
Response β†’ Acknowledgment

πŸ“ Project Structure

messaging-service/
β”œβ”€β”€ cmd/
β”‚   └── server/
β”‚       └── main.go              # Application entry point
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ app/                     # Application lifecycle
β”‚   β”œβ”€β”€ config/                  # Configuration management
β”‚   β”œβ”€β”€ container/               # Dependency injection
β”‚   β”œβ”€β”€ domain/                  # Domain models and interfaces
β”‚   β”œβ”€β”€ handler/                 # HTTP handlers
β”‚   β”œβ”€β”€ logger/                  # Structured logging
β”‚   β”œβ”€β”€ middleware/              # HTTP middleware
β”‚   β”œβ”€β”€ provider/                # External service providers
β”‚   β”œβ”€β”€ repository/              # Data access layer
β”‚   β”œβ”€β”€ router/                  # HTTP routing
β”‚   β”œβ”€β”€ service/                 # Business logic
β”‚   └── telemetry/               # OpenTelemetry setup
β”œβ”€β”€ tests/                       # Integration tests
β”œβ”€β”€ docs/                        # Generated Swagger docs
β”œβ”€β”€ init.sql/                    # Database schema
β”œβ”€β”€ bin/                         # Scripts
β”œβ”€β”€ Dockerfile                   # Multi-stage Docker build
β”œβ”€β”€ docker-compose.yml           # Development environment
β”œβ”€β”€ Makefile                     # Build and deployment commands
└── README.md                    # This file

πŸ”§ Development Commands

Command Description
make setup Initialize project dependencies
make run Start the messaging service
make test Run all tests
make swagger Generate Swagger documentation
make docs Generate Swagger documentation
make help Show all available commands

πŸš€ Production Deployment

Docker Compose (Recommended)

# Start production stack
make docker-up

# View logs
make docker-logs

# Stop stack
make docker-down

Manual Deployment

# Build the application
go build -o messaging-service ./cmd/server

# Set environment variables
export DATABASE_HOST=your-db-host
export DATABASE_PORT=5432
# ... other environment variables

# Run the application
./messaging-service

πŸ“Š Monitoring

Health Check

curl http://localhost:8080/health

Database Connection

The application includes database connection monitoring and will log connection status on startup.

πŸ”’ Security

  • Non-root user in Docker containers
  • Input validation on all endpoints
  • SQL injection protection through parameterized queries
  • Boilerplate for Authorization through api-key Authorization header

πŸ“Š Observability

  • Request ID tracking with X-Request-ID header
  • Structured logging with request details and timing
  • OpenTelemetry metrics with Prometheus exporter
  • Request/response metrics including duration and size

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

πŸ“„ License

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

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages