Microservice for managing groups in a shared expense management application. The service provides RESTful APIs to create, update, delete, and manage user groups, with support for subscription plans, Redis caching, pub/sub events, and integration with external services.
- Features
- Architecture
- Technologies
- Prerequisites
- Installation
- Configuration
- Starting the Service
- API Endpoints
- Subscription Plans
- Implemented Patterns
- Testing
- Docker
- Complete group management: creation, modification, deletion, and retrieval
- Member management: add and remove members with permission control
- Plan system: FREE, PRO, ENTERPRISE with differentiated limits
- JWT authentication: middleware for token verification
- Intelligent caching: Redis for performance optimization
- Event-driven architecture: event publishing via Redis Pub/Sub
- Circuit Breaker: protection against external service failures
- Unsplash integration: random images for groups
- Materialized Views: pre-calculated group summaries
- API documentation: integrated Swagger UI
- Event consumer: listen to events from expenses-service
The service follows a microservice architecture with the following components:
βββββββββββββββββββ
β API Gateway β
ββββββββββ¬βββββββββ
β
ββββββΌββββββββββββββββββ
β Groups Service β
β (Hono + OpenAPI) β
ββββ¬βββββββββββββββββ¬βββ
β β
ββββββΌβββββ ββββββΌβββββ
β MongoDB β β Redis β
β (Groups)β β (Cache) β
βββββββββββ ββββββ¬βββββ
β
ββββββΌβββββββββ
β Pub/Sub β
β Events β
βββββββββββββββ
- Routes: OpenAPI endpoint definitions with Zod validation
- Services: Business logic for group operations
- Middleware: JWT authentication and request validation
- Consumers: Redis event subscription from other services
- Circuit Breaker: Resilience for external service calls
- Cache Layer: Redis for frequent query optimization
- Runtime: Bun - High-performance JavaScript/TypeScript runtime
- Framework: Hono - Ultra-lightweight web framework
- Database: MongoDB with Mongoose ODM
- Cache/Pub-Sub: Redis with ioredis
- API Documentation: @hono/zod-openapi + Swagger UI
- Validation: Zod for type-safe schema validation
- Authentication: JWT with jose library
- External APIs: Unsplash API for images
# Clone the repository
git clone <repository-url>
cd groups-service
# Install dependencies
bun installCreate a .env file in the project root with the following variables:
# Server
PORT=3000
# MongoDB
MONGODB_URL=mongodb://admin:password@localhost:27017/groupsdb?authSource=admin
# Redis
REDIS_URL=redis://localhost:6379
# JWT
JWT_SECRET_KEY=your-jwt-secret-key-here
# Users Service (for member validation)
USERS_SERVICE_URL=http://localhost:3001
# Unsplash API (optional - for group images)
ACCES_KEY_UNSPLASH=your-unsplash-access-key
# Environment
NODE_ENV=developmentUnsplash API (optional):
- Sign up at Unsplash Developers
- Create a new application
- Copy the Access Key
# Start MongoDB and Redis
docker-compose up -d
# Start the service
bun run dev# Ensure MongoDB and Redis are running
# Then start the service in development mode
bun run devThe service will be available at: http://localhost:3000
Interactive API documentation available at: http://localhost:3000/api/docs
All endpoints require a JWT token in the header:
Authorization: Bearer <token>
Retrieve the materialized summary of a group (with caching).
Response:
{
"groupId": "string",
"name": "string",
"description": "string",
"members": ["userId1", "userId2"],
"membersCount": 2,
"owner": "ownerId",
"imageUrl": "https://...",
"createdAt": "2026-01-07T...",
"updatedAt": "2026-01-07T..."
}Verify if a user is a member of a group (used by expenses-service).
Response:
{
"groupId": "string",
"userId": "string",
"isMember": true
}Create a new group.
Body:
{
"name": "Group Name",
"description": "Optional description"
}Response: 201 Created
{
"_id": "groupId",
"name": "Group Name",
"description": "Description",
"owner": "userId",
"members": ["userId"],
"imageUrl": "https://...",
"createdAt": "2026-01-07T...",
"updatedAt": "2026-01-07T..."
}Delete a group (owner only).
Response: 200 OK
{
"success": true,
"message": "Group deleted successfully"
}Add or remove members from a group (owner only).
Body:
{
"groupId": "string",
"members": ["email-to-add@example.com", "email-to-remove@example.com"]
}Update group name or description (owner only).
Body:
{
"name": "New Name",
"description": "New Description"
}Retrieve all groups for a user.
Query Parameters:
memberId(optional): User ID (default: authenticated user)
Response:
[
{
"_id": "groupId",
"name": "Group Name",
"members": [...],
"owner": "userId",
...
}
]The service implements three plan tiers:
| Plan | Max Groups | Max Members per Group |
|---|---|---|
| FREE | 3 | 5 |
| PRO | β | 50 |
| ENTERPRISE | β | β |
Limits are automatically enforced during:
- Group creation
- Member addition
Protection against external service failures (Unsplash, Users Service):
// States: CLOSED -> OPEN -> HALF_OPEN
// Threshold: 5 failures
// Timeout: 60 secondsEvents published on Redis:
group.createdgroup.deletedgroup.updatedgroup.member.addedgroup.member.removed
Pre-calculated group summaries with Redis caching (TTL: 1 hour).
- User query cache (email β userId)
- Group summary cache
- Daily counter cache
- Configured TTLs per data type
# Run all tests
bun test
# Specific tests
bun test src/tests/auth.test.ts
bun test src/tests/circuitBreaker.test.ts
bun test src/tests/routes.test.tsThe project includes tests for:
- JWT authentication
- Circuit Breaker
- Route handlers
- Middleware
docker build -t groups-service .docker run -p 3000:3000 \
-e PORT=3000 \
-e MONGODB_URL=mongodb://... \
-e REDIS_URL=redis://... \
-e JWT_SECRET_KEY=... \
groups-serviceThe docker-compose.yml file includes:
- Redis with persistence
- MongoDB with authentication
- Configured health checks
# Start complete stack
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -vgroups-service/
βββ src/
β βββ index.ts # Entry point
β βββ api/
β β βββ openapi.ts # OpenAPI configuration + Swagger
β βββ config/
β β βββ plans.ts # Subscription plans definition
β βββ consumers/
β β βββ expensesConsumer.ts # Expenses events consumer
β βββ db/
β β βββ db.ts # MongoDB connection
β βββ lib/
β β βββ circuitBreaker.ts # Circuit Breaker implementation
β β βββ redisPublisher.ts # Redis events publisher
β β βββ redisSubscriber.ts# Redis events subscriber
β β βββ unsplash.ts # Unsplash API client
β βββ middlware/
β β βββ auth.ts # JWT authentication middleware
β βββ routes/
β β βββ groups.ts # Groups routes (OpenAPI)
β βββ services/
β β βββ services.ts # Groups business logic
β β βββ summaryGroup.ts # Materialized views
β βββ tests/ # Test suite
β βββ types/
β β βββ app.ts # Type definitions
β βββ utils/
β βββ jwt.ts # JWT utilities
βββ types/
β βββ appEnv.ts # Environment types
βββ docker-compose.yml # Local stack MongoDB + Redis
βββ Dockerfile # Service build
βββ package.json
βββ tsconfig.json
βββ README.md
Verify that MongoDB is running and the URL is correct:
docker-compose ps
# Or test the connection
mongosh "mongodb://admin:password@localhost:27017/groupsdb?authSource=admin"Verify that Redis is running:
docker-compose ps
redis-cli ping # Should respond "PONG"Make sure that:
- The token is valid and not expired
- The
JWT_SECRET_KEYis the same used to generate the token - The
Authorizationheader is in the format:Bearer <token>
If you see "service unavailable" errors, the circuit breaker is open:
- Wait 60 seconds for automatic reset
- Verify that the external service is available
- The service uses Bun as runtime for optimal performance
- All endpoints are documented with OpenAPI 3.0
- Input validation happens via Zod schemas
- Events are published asynchronously on Redis
- Unsplash images are optional (graceful fallback)
To contribute to the project:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is distributed under the MIT License.
Developed by the 0debt team