A Spring Boot backend that implements a chat system using Redis for storage and real-time Pub/Sub messaging.
- Chat rooms: Create and join rooms with unique names
- Messaging: Send and retrieve messages (last N) per room
- Real-time: Redis Pub/Sub for broadcasting; optional SSE stream for clients
- Error handling: Duplicate room names, non-existent rooms
- Optional: Chat room deletion; Redis persistence (RDB/AOF) via server config
- Java 17+
- Maven 3.6+ (optional if you use an IDE)
- Redis 6+ (localhost:6379 by default)
-
Start Redis (required first):
docker run -d --name redis -p 6379:6379 redis:7-alpine
-
Run the app (from project root):
mvn spring-boot:run
Or run
ChatAppApplication.javafrom your IDE. When you seeStarted ChatAppApplication, the API is at http://localhost:8080. -
Test the API (Postman):
- Import in Postman:
postman/ChatApp-API.postman_collection.jsonandpostman/ChatApp-local.postman_environment.json. - Select the ChatApp Local environment (top-right). If using port 8081, set
baseUrltohttp://localhost:8081in that environment. - Open the ChatApp API collection → Run (Collection Runner) → Run ChatApp API to execute all requests and see test results.
- Import in Postman:
-
Run unit/integration tests (optional):
mvn test(Integration tests need Docker for Redis Testcontainers.)
-
Install Java 17+
-
Start Redis (the app needs it before starting)
- With Docker:
docker run -d --name redis -p 6379:6379 redis:7-alpine - Without Docker: install Redis and start it (e.g.
redis-serveror Windows Redis service).
- With Docker:
-
Run the app
- From Cursor / VS Code:
- Open the
ChatAppfolder. - Open
src/main/java/chatapp/ChatAppApplication.java. - Click Run (play icon) above
public static void main, or right‑click the file → Run Java.
- Open the
- From IntelliJ IDEA:
- File → Open → select the
ChatAppfolder (open the folder that containspom.xml). - Wait for Maven to import.
- Open
src/main/java/chatapp/ChatAppApplication.java. - Click the green Run button next to the class or right‑click → Run 'ChatAppApplication'.
- File → Open → select the
- From terminal (if Maven is installed):
On Windows PowerShell you can use the same commands.
cd D:\myWork\Projects\Assignments\FreightFox\ChatApp mvn spring-boot:run
- From Cursor / VS Code:
-
Check it’s running
- In the console you should see something like:
Started ChatAppApplication. - Open in browser or Postman:
http://localhost:8080(you may see a blank or error page; the API is under/api/chatapp/...). - Try creating a room: POST
http://localhost:8080/api/chatapp/chatroomswith body{"roomName":"general"}.
- In the console you should see something like:
If Redis is not running, the app will fail to start with a connection error. Start Redis first, then run the app again.
# Using Docker
docker run -d --name redis -p 6379:6379 redis:7-alpine
# Or install and run Redis locally (e.g. redis-server)cd ChatApp
mvn clean install
mvn spring-boot:runThe API is available at http://localhost:8080.
Port 8080 already in use? Run on another port (e.g. 8081):
mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8081"Then use http://localhost:8081 for the API. To free port 8080 (WSL/Linux): lsof -ti :8080 | xargs kill -9. On Windows: netstat -ano | findstr :8080, then taskkill /PID <pid> /F.
For durability, configure Redis (e.g. redis.conf):
- RDB snapshots:
save 900 1(and similar lines) - AOF:
appendonly yes
Base path: /api/chatapp
Endpoint: POST /api/chatapp/chatrooms
Request body:
{
"roomName": "general"
}Response (200):
{
"message": "Chat room 'general' created successfully.",
"roomId": "general",
"status": "success"
}Errors:
- 409 Conflict – Room name already exists
Endpoint: POST /api/chatapp/chatrooms/{roomId}/join
Example: POST /api/chatapp/chatrooms/general/join
Request body:
{
"participant": "guest_user"
}Response (200):
{
"message": "User 'guest_user' joined chat room 'general'.",
"status": "success"
}Errors:
- 404 Not Found – Room does not exist
Endpoint: POST /api/chatapp/chatrooms/{roomId}/messages
Example: POST /api/chatapp/chatrooms/general/messages
Request body:
{
"participant": "guest_user",
"message": "Hello, everyone!"
}Response (200):
{
"message": "Message sent successfully.",
"status": "success"
}Errors:
- 404 Not Found – Room does not exist
Endpoint: GET /api/chatapp/chatrooms/{roomId}/messages
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 50 | Max messages (1–100) |
Example: GET /api/chatapp/chatrooms/general/messages?limit=10
Response (200):
{
"messages": [
{
"participant": "guest_user",
"message": "Hello, everyone!",
"timestamp": "2024-01-01T10:00:00Z"
},
{
"participant": "another_user",
"message": "Hi, guest_user!",
"timestamp": "2024-01-01T10:01:00Z"
}
]
}Errors:
- 404 Not Found – Room does not exist
Endpoint: GET /api/chatapp/chatrooms/{roomId}/stream
Example: GET /api/chatapp/chatrooms/general/stream
Opens a Server-Sent Events stream. New messages in the room are pushed as events (event name: message, body: JSON ChatMessage).
Errors:
- 404 Not Found – Room does not exist
Endpoint: DELETE /api/chatapp/chatrooms/{roomId}
Example: DELETE /api/chatapp/chatrooms/general
Response (200):
{
"message": "Chat room 'general' deleted successfully.",
"status": "success"
}Errors:
- 404 Not Found – Room does not exist
Import the collection and run tests:
-
Import collection and environment
- In Postman: Import → select
postman/ChatApp-API.postman_collection.jsonandpostman/ChatApp-local.postman_environment.json. - In the top-right, choose the ChatApp Local environment (so
baseUrlandroomIdare used). If your app runs on port 8081, edit the environment and setbaseUrltohttp://localhost:8081.
- In Postman: Import → select
-
Run all requests (with tests)
- Open the ChatApp API collection → click Run (Collection Runner).
- Select all requests (or leave default) → Run ChatApp API.
- Each request runs in order; the Test Results tab shows pass/fail for status codes and response body checks.
-
What the collection does
- 1–4: Create room → Join → Send message → Get history.
- 5–6: Send another message → Get history with
limit=2. - Error: Create duplicate room (expect 409), send to non-existent room (expect 404).
- 7: Delete chat room.
- Real-Time Stream: Optional; open in a tab and send messages from another request to see SSE events (run only when the room exists).
| Structure | Key pattern | Purpose |
|---|---|---|
| Hash | chatapp:room:{roomId}:metadata |
Room metadata |
| Set | chatapp:room:{roomId}:participants |
Participants in room |
| List | chatapp:room:{roomId}:messages |
Messages (chronological) |
| Set | chatapp:rooms |
All room IDs |
| Pub/Sub | chatapp:channel:room:{roomId} |
Real-time message channel |
Messages in the List are stored as JSON strings:
{
"participant": "guest_user",
"message": "Hello, everyone!",
"timestamp": "2024-01-01T10:00:00Z"
}src/main/java/chatapp/
├── ChatAppApplication.java
├── config/
│ ├── RedisConfig.java
│ └── RedisKeyConstants.java
├── controller/
│ └── ChatRoomController.java
├── dto/
│ ├── ApiResponse.java
│ ├── CreateRoomRequest.java
│ ├── JoinRoomRequest.java
│ ├── MessagesResponse.java
│ └── SendMessageRequest.java
├── exception/
│ ├── ChatAppException.java
│ ├── GlobalExceptionHandler.java
│ ├── RoomAlreadyExistsException.java
│ └── RoomNotFoundException.java
├── messaging/
│ ├── MessagePublisher.java
│ ├── RedisMessageSubscriber.java
│ └── SseRoomRegistry.java
├── model/
│ └── ChatMessage.java
├── repository/
│ ├── ChatRoomRepository.java
│ └── RedisChatRoomRepository.java
└── service/
└── ChatRoomService.java
mvn test- Unit tests: Service, controller, exception handler (MockMvc) — no Redis required
- Integration tests: Repository with Testcontainers (Redis) — requires Docker for
RedisChatRoomRepositoryTest
src/main/resources/application.yml:
spring.data.redis.host– defaultlocalhostspring.data.redis.port– default6379server.port– default8080
Override via environment variables or application-*.yml as needed.
Internal use / assignment project.