Capstone Project
Capstone Project
Reconciliation
Services Overview
1. User Service
Description: Manages user-related operations such as registration, authentication,
and profile management.
Functionalities:
User Registration: Allows new users to create an account.
User Login: Authenticates users using JWT (JSON Web Tokens).
Profile Management: Enables users to update their profile information.
Interactions:
Interacts with the Account Service to create a user wallet upon registration.
Validates JWT tokens for other services to ensure secure access.
2. Account Service
Description: Manages wallet accounts, including creating, updating, and retrieving
account details.
Functionalities:
Create Wallet: Generates a new wallet account for users.
Update Wallet: Allows users to update wallet details.
Retrieve Wallet: Fetches wallet information for users.
Interactions:
Interacts with the User Service to link wallets to user profiles.
Communicates with the Transaction Service to handle financial operations.
3. Transaction Service
Description: Handles financial transactions, including deposits, withdrawals,
transfers, and payments.
Functionalities:
Deposit Funds: Adds money to a user’s wallet.
Withdraw Funds: Allows users to withdraw money from their wallet.
Transfer Funds: Enables transferring money between wallets.
Process Payments: Handles payments to third-party vendors.
Interactions:
Works with the Account Service to update wallet balances.
Interacts with the Payment Gateway Service to process external payments.
Uses the Notification Service to send transaction alerts.
4. Payment Gateway Service
Description: Integrates with third-party payment gateways for processing payments.
Functionalities:
Process Payment: Interfaces with external payment gateways like Stripe to
handle transactions.
Verify Payment: Confirms payment status and updates the transaction record.
Interactions:
Communicates with the Transaction Service to process and verify payments.
Sends status updates to the Bank Reconciliation Service for record-keeping.
5. Bank Reconciliation Service
Description: Reconciles transactions with bank records to ensure accuracy and
consistency.
Functionalities:
Reconcile Transactions: Matches internal transaction records with bank
statements.
Generate Reports: Creates reconciliation reports for audit purposes.
Interactions:
Interfaces with the Payment Gateway Service to verify transaction records.
Works with the Transaction Service to update and correct transaction
discrepancies.
6. Notification Service
Description: Sends real-time notifications for account activities and transactions.
Functionalities:
Send Email Notifications: Sends email alerts for various account activities.
Send SMS Notifications: Sends SMS alerts for critical transactions.
Real-time Alerts: Uses WebSockets to provide instant notifications.
Interactions:
Communicates with the Transaction Service to send transaction alerts.
Interacts with the User Service to manage notification preferences.
7. Caching Service
Description: Implements caching for frequently accessed data to improve
performance.
Functionalities:
Cache User Data: Stores user profile data for quick retrieval.
Cache Transactions: Caches recent transactions to reduce load on the
Transaction Service.
Interactions:
Works with all services to cache and retrieve data, improving overall
performance.
payment-gateway/
├── user-service/
│ └── main_test.go
├── account-service/
│ └── main_test.go
├── transaction-service/
│ └── main_test.go
├── payment-gateway-service/
│ └── main_test.go
├── bank-reconciliation-service/
│ └── main_test.go
├── notification-service/
│ └── main_test.go
├── caching-service/
│ └── main_test.go
└── tests/
└── integration_test.go
package tests
import (
"bytes"
"encoding/json"
"net/http"
"testing"
"time"
)
const (
userServiceURL = "http://localhost:8080"
accountServiceURL = "http://localhost:8081"
transactionServiceURL = "http://localhost:8082"
paymentGatewayURL = "http://localhost:8083"
notificationServiceURL = "http://localhost:8085"
reconciliationServiceURL = "http://localhost:8084"
)
return nil
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("expected status 200 OK, got %v",
resp.StatusCode)
}
Explanation
1. Register User: Registers a new user by sending a POST request to the User Service.
2. Login User: Logs in the user and retrieves a JWT token.
3. Create Account: Creates a new account for the user.
4. Make a Transaction: Creates a transaction (e.g., deposit) for the account.
5. Process Payment: Simulates a payment using the Payment Gateway Service.
6. Send Notification: Sends a notification about the transaction.
7. Reconcile with Bank: Simulates bank reconciliation for the transaction.
go test ./tests -v
Enhancements
Setup and Teardown: Implement setup and teardown functions to create a test
environment and clean up after tests.
Environment Variables: Use environment variables to configure service URLs and other
settings.
Error Handling: Improve error handling and logging for better test diagnostics.
Test Data: Use fixtures or factories to generate test data.
High-Level Architecture
1. User Service
2. Account Service
3. Transaction Service
4. Payment Gateway Service
5. Bank Reconciliation Service
6. Notification Service
7. Caching Service
Tech Stack
Language: Go 1.2x
Database: PostgreSQL
Cache: Redis
API Gateway and Ingress: Traefik
Containerization: Docker
Orchestration: Kubernetes
Continuous Deployment: ArgoCD
Initial Setup
1. Repository Structure
2. Common Libraries and Packages
3. Docker Configuration
4. Kubernetes Manifests
1. Repository Structure
payment-gateway/
├── user-service/
├── account-service/
├── transaction-service/
├── payment-gateway-service/
├── bank-reconciliation-service/
├── notification-service/
├── caching-service/
├── common/
│ ├── middleware/
│ ├── models/
│ ├── utils/
│ └── config/
└── deploy/
├── docker/
├── kubernetes/
└── scripts/
package config
import (
"github.com/spf13/viper"
)
Cfg = &Config{
DBHost: viper.GetString("db.host"),
DBPort: viper.GetString("db.port"),
DBUser: viper.GetString("db.user"),
DBPassword: viper.GetString("db.password"),
DBName: viper.GetString("db.name"),
RedisHost: viper.GetString("redis.host"),
RedisPort: viper.GetString("redis.port"),
JwtSecret: viper.GetString("jwt.secret"),
}
}
3. Docker Configuration
Dockerfile Example ( user-service/Dockerfile )
FROM golang:1.2x-alpine
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY . .
EXPOSE 8080
CMD ["/user-service"]
4. Kubernetes Manifests
Deployment Example ( deploy/kubernetes/user-service-
deployment.yaml )
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerPort: 8080
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: db-config
key: db-host
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: db-user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: db-password
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: jwt-secret
key: secret
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
Service Implementations
1. User Service
Functionality: Handles user registration, authentication, and profile management.
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/dgrijalva/jwt-go"
"time"
"common/config"
"common/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var db *gorm.DB
var jwtKey = []byte(config.Cfg.JwtSecret)
func main() {
config.LoadConfig()
dsn := "host=" + config.Cfg.DBHost + " user=" + config.Cfg.DBUser + "
password=" + config.Cfg.DBPassword + " dbname=" + config.Cfg.DBName + "
port=" + config.Cfg.DBPort + " sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
db.AutoMigrate(&models.User{})
router := mux.NewRouter()
router.HandleFunc("/register", Register).Methods("POST")
router.HandleFunc("/login", Login).Methods("POST")
router.HandleFunc("/profile", Profile).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", router))
}
http.SetCookie(w, &http.Cookie{
Name: "token",
Value: tokenString,
Expires: expirationTime,
})
}
tokenStr := cookie.Value
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenStr, claims, func(token
*jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil {
if err == jwt.ErrSignatureInvalid {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusBadRequest)
return
}
if !token.Valid {
w.WriteHeader(http.StatusUnauthorized)
return
}
var user models.User
db.Where("username = ?", claims.Username).First(&user)
json.NewEncoder(w).Encode(user)
}
2. Account Service
Functionality: CRUD operations for wallet accounts.
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"common/config"
"common/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var db *gorm.DB
func main() {
config.LoadConfig()
dsn := "host=" + config.Cfg.DBHost + " user=" + config.Cfg.DBUser + "
password=" + config.Cfg.DBPassword + " dbname=" + config.Cfg.DBName + "
port=" + config.Cfg.DBPort + " sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
db.AutoMigrate(&models.Account{})
router := mux.NewRouter()
router.HandleFunc("/accounts", CreateAccount).Methods("POST")
router.HandleFunc("/accounts/{id}", GetAccount).Methods("GET")
router.HandleFunc("/accounts/{id}", UpdateAccount).Methods("PUT")
router.HandleFunc("/accounts/{id
}", DeleteAccount).Methods("DELETE")
log.Fatal(http.ListenAndServe(":8081", router))
}
Next Steps
1. Implement remaining services: Repeat the pattern used in User Service and Account
Service to implement Transaction Service, Payment Gateway Service, Bank Reconciliation
Service, Notification Service, and Caching Service.
2. Database Schema: Define and migrate database schema for each service.
3. Inter-Service Communication: Set up REST/gRPC communication between services.
4. Security: Enhance security with TLS, API Gateway, and RBAC.
5. Deployment: Finalize Docker and Kubernetes configurations for all services.
6. Monitoring and Logging: Integrate Prometheus, Grafana, and ELK stack for monitoring
and logging.
7. Testing: Write unit tests and integration tests for all services.
1. Transaction Service
2. Payment Gateway Service
3. Bank Reconciliation Service
4. Notification Service
5. Caching Service
3. Transaction Service
Functionality: Processes transactions, including deposits, withdrawals, transfers, and
payments.
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"common/config"
"common/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var db *gorm.DB
func main() {
config.LoadConfig()
dsn := "host=" + config.Cfg.DBHost + " user=" + config.Cfg.DBUser + "
password=" + config.Cfg.DBPassword + " dbname=" + config.Cfg.DBName + "
port=" + config.Cfg.DBPort + " sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
db.AutoMigrate(&models.Transaction{})
router := mux.NewRouter()
router.HandleFunc("/transactions", CreateTransaction).Methods("POST")
router.HandleFunc("/transactions/{id}", GetTransaction).Methods("GET")
log.Fatal(http.ListenAndServe(":8082", router))
}
db.Create(&transaction)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(transaction)
}
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"common/config"
"common/models"
)
func main() {
config.LoadConfig()
router := mux.NewRouter()
router.HandleFunc("/payments", ProcessPayment).Methods("POST")
log.Fatal(http.ListenAndServe(":8083", router))
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(paymentResponse)
}
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"common/config"
"common/models"
)
func main() {
config.LoadConfig()
router := mux.NewRouter()
router.HandleFunc("/reconcile", ReconcileTransactions).Methods("POST")
log.Fatal(http.ListenAndServe(":8084", router))
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(reconciliationResult)
}
6. Notification Service
Functionality: Sends notifications for account activities.
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"common/config"
"common/models"
)
func main() {
config.LoadConfig()
router := mux.NewRouter()
router.HandleFunc("/notifications", SendNotification).Methods("POST")
log.Fatal(http.ListenAndServe(":8085", router))
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "sent"})
}
7. Caching Service
Functionality: Implements caching for frequently accessed data using Redis.
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/go-redis/redis/v8"
"context"
"common/config"
"common/models"
)
func main() {
config.LoadConfig()
rdb = redis.NewClient(&redis.Options{
Addr: config.Cfg.RedisHost + ":" + config.Cfg.RedisPort,
Password: "", // no password set
DB: 0, // use default DB
})
router := mux.NewRouter()
router.HandleFunc("/cache", SetCache).Methods("POST")
router.HandleFunc("/cache/{key}", GetCache).Methods("GET")
log.Fatal(http.ListenAndServe(":8086", router))
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "set"})
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"value": value})
}
package models
import "gorm.io/gorm"
"`
Message string `json:"message"`
}
Deployment
To deploy these services, ensure you have the correct Dockerfiles and Kubernetes manifests.
Here’s a sample Kubernetes manifest for the transaction-service .
apiVersion: apps/v1
kind: Deployment
metadata:
name: transaction-service
labels:
app: transaction-service
spec:
replicas: 3
selector:
matchLabels:
app: transaction-service
template:
metadata:
labels:
app: transaction-service
spec:
containers:
- name: transaction-service
image: transaction-service:latest
ports:
- containerPort: 8082
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: db-config
key: db-host
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: db-user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: db-password
---
apiVersion: v1
kind: Service
metadata:
name: transaction-service
spec:
selector:
app: transaction-service
ports:
- protocol: TCP
port: 80
targetPort: 8082
Testing
Implement unit tests and integration tests for each service. Use Go’s built-in testing package to
write tests for the business logic.
Integrating Kafka
Kafka can be used for several purposes, including:
Here's how you can incorporate Kafka into your capstone project:
Kafka Setup
1. Kafka Cluster: Set up a Kafka cluster using Docker or Kubernetes.
2. Topics: Define Kafka topics for different types of messages (e.g., transactions,
notifications).
Transaction Service
This service handles creating transactions and publishing them to Kafka.
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/segmentio/kafka-go"
"common/config"
"common/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var (
db *gorm.DB
kafkaWriter *kafka.Writer
)
func main() {
config.LoadConfig()
dsn := "host=" + config.Cfg.DBHost + " user=" + config.Cfg.DBUser + "
password=" + config.Cfg.DBPassword + " dbname=" + config.Cfg.DBName + "
port=" + config.Cfg.DBPort + " sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
db.AutoMigrate(&models.Transaction{})
kafkaWriter = &kafka.Writer{
Addr: kafka.TCP("localhost:9092"),
Topic: "transactions",
Balancer: &kafka.LeastBytes{},
}
router := mux.NewRouter()
router.HandleFunc("/transactions", CreateTransaction).Methods("POST")
router.HandleFunc("/transactions/{id}", GetTransaction).Methods("GET")
log.Fatal(http.ListenAndServe(":8082", router))
}
db.Create(&transaction)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(transaction)
}
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/segmentio/kafka-go"
"common/config"
"common/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var db *gorm.DB
func main() {
config.LoadConfig()
dsn := "host=" + config.Cfg.DBHost + " user=" + config.Cfg.DBUser + "
password=" + config.Cfg.DBPassword + " dbname=" + config.Cfg.DBName + "
port=" + config.Cfg.DBPort + " sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
db.AutoMigrate(&models.Transaction{})
go consumeKafkaMessages()
router := mux.NewRouter()
router.HandleFunc("/reconcile", ReconcileTransactions).Methods("POST")
log.Fatal(http.ListenAndServe(":8084", router))
}
func consumeKafkaMessages() {
kafkaReader := kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{"localhost:9092"},
Topic: "transactions",
GroupID: "bank-reconciliation",
})
for {
message, err := kafkaReader.ReadMessage(context.Background())
if err != nil {
log.Fatal("Failed to read message from Kafka:", err)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(reconciliationResult)
}
return models.ReconciliationResult{
Status: "reconciled",
Discrepancies: discrepancies,
}, nil
}
Summary
Transaction Service: Handles transaction creation, saves to the database, and publishes
to Kafka.
Bank Reconciliation Service: Consumes transaction messages from Kafka, stores them,
and handles reconciliation requests.