This repository contains a complete, production-ready implementation of the TopBloc Backend Code Challenge for an Enterprise Candy Planning (ECP) system. What started as a basic API challenge has been transformed into a full-stack application with modern architecture, comprehensive testing, and containerized deployment.
- Backend: Java 11 + Spark Framework + SQLite
- Frontend: React 18 + TypeScript + Material-UI
- Database: SQLite with relational schema
- Containerization: Docker + Docker Compose
- Build Tools: Maven (backend), npm (frontend)
┌─────────────────────────────────────────────────────────────┐
│ TopBloc Full Stack │
├─────────────────────┬─────────────────────┬─────────────────┤
│ React Frontend │ Java Backend │ SQLite Browser │
│ (Port 3000) │ (Port 4567) │ (Port 8080) │
│ │ │ │
│ ┌─────────────────┐ │ ┌─────────────────┐ │ ┌─────────────┐ │
│ │ Nginx │ │ │ Spark API │ │ │ Web UI │ │
│ │ + React SPA │ │ │ + Maven │ │ │ (Optional) │ │
│ └─────────────────┘ │ └─────────────────┘ │ └─────────────┘ │
│ │ │ │ │ │ │
└─────────┼───────────┴─────────┼───────────┴─────────┼───────┘
│ │ │
└─────────────────────┼─────────────────────┘
│
┌─────────────────────┐
│ SQLite Database │
│ (challenge.db) │
└─────────────────────┘
The backend follows a Route-Handler Pattern with Data Access Layer:
┌─────────────────────────┐ ┌──────────────────────────┐
│ Main.java │ │ DatabaseManager.java │
│ (Spark Routes + │────▶│ (Data Access Layer + │
│ Request Handlers) │ │ Business Logic) │
└─────────────────────────┘ └──────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌──────────────────────────┐
│ HTTP Requests │ │ SQLite Database │
│ (Spark Framework) │ │ (challenge.db) │
└─────────────────────────┘ └──────────────────────────┘
Key Components:
- Main.java: Route definitions using Spark's DSL + request handling logic
- DatabaseManager.java: Data access layer with SQL operations and business logic
- Spark Framework: Lightweight web framework for HTTP request routing
- SQLite Database: Persistent data storage with normalized schema
The SQLite database implements a normalized schema for candy inventory management:
items (17 records)
├── id (PK)
└── name (unique)
inventory (17 records)
├── id (PK)
├── item (FK → items.id)
├── stock
└── capacity
distributors (3 records)
├── id (PK)
└── name (unique)
distributor_prices (27 records)
├── id (PK)
├── distributor (FK → distributors.id)
├── item (FK → items.id)
└── costGET /inventory- All inventory items with stock levelsGET /inventory/out-of-stock- Items with stock = 0GET /inventory/overstocked- Items where stock > capacityGET /inventory/low-stock- Items with stock < 35% of capacityGET /inventory/:id- Specific item inventory detailsGET /distributors- All distributorsGET /distributors/:id/items- Items by distributor with pricingGET /items/:id/distributors- All distributor offerings for an item
POST /items- Add new candy itemsPOST /inventory- Add items to inventoryPOST /distributors- Add new distributorsPOST /distributors/:id/items- Add distributor pricingPUT /inventory/:id- Update stock/capacityPUT /distributors/:distId/items/:itemId- Update pricingDELETE /inventory/:id- Remove from inventoryDELETE /distributors/:id- Remove distributorDELETE /distributors/:distId/items/:itemId- Remove pricing
GET /items/:id/cheapest?quantity=N- Find cheapest restock optionGET /stream/events- Real-time database streaming via Server-Sent EventsGET /stream- Interactive streaming dashboard- Comprehensive error handling with proper HTTP status codes
- Input validation and SQL injection protection
- CORS support for frontend integration
Implemented a complete real-time streaming system that broadcasts database changes to connected clients:
Features:
- Server-Sent Events (SSE) for real-time communication
- Event Broadcasting - All database modifications are streamed live
- Multi-client Support - Handles multiple concurrent streaming connections
- Interactive Dashboard - Built-in web interface for testing and monitoring
- Automatic Cleanup - Failed clients are automatically removed from the pool
Endpoints:
GET /stream/events- SSE endpoint for real-time database updatesGET /stream- Interactive dashboard for viewing live changes
Supported Events:
INSERToperations (items, inventory, distributors)UPDATEoperations (inventory stock/capacity, pricing)DELETEoperations (all entities)- Connection events and heartbeat monitoring
Usage Example:
const eventSource = new EventSource('http://localhost:4567/stream/events');
eventSource.addEventListener('update', function(e) {
const data = JSON.parse(e.data);
console.log(`${data.eventType} on ${data.table}:`, data.data);
});Built a React application with:
-
Material-UI Components - Modern, responsive design
-
TypeScript Integration - Type-safe API interactions
-
Four Management Modules:
InventoryManager- Stock tracking with visual indicatorsDistributorManager- Supplier and pricing managementItemManager- Product catalog managementExportManager- CSV export functionality
-
Advanced Features:
- Real-time filtering (out-of-stock, low-stock, overstocked)
- Complete CRUD operations with form validation
- Success/error notifications
- Responsive layout with tabbed navigation
Implemented complete containerization with:
- Multi-stage Docker builds for optimized images
- Docker Compose orchestration with 3 services:
- Backend API (Java/Spark)
- Frontend SPA (React/Nginx)
- Database Browser (SQLite Web UI)
- Production features:
- Health checks for all services
- Volume mounting for data persistence
- Environment variable configuration
- Network isolation and service discovery
Created a secure table export system:
- Export any database table to CSV format
- Proper CSV escaping for special characters
- Security validation against table injection
- RESTful endpoint:
GET /export/csv?table=tablename
Developed TestSuite.java with 79 automated tests covering:
- Valid requests - All endpoints with correct data
- Error scenarios - Invalid inputs, malformed requests
- Edge cases - Boundary values, empty parameters
- Security testing - SQL injection, XSS protection
- HTTP compliance - Proper status codes and headers
-
Clean separation of concerns (Route-Handler pattern with Data Access Layer)
-
Comprehensive error handling and logging
-
Input validation and sanitization
-
Consistent JSON response format
-
Modern Java practices with prepared statements
-
Comprehensive error scenarios testing
- Docker & Docker Compose
- Java 11+ (for local development)
- Node.js 16+ (for frontend development)
# Clone the repository
git clone <repository-url>
cd backend-code-challenge
# Start the entire stack with Docker
docker-compose up --build -d
# Access the applications
echo "Frontend: http://localhost:3000"
echo "Backend API: http://localhost:4567"
echo "DB Browser: http://localhost:8080"
# Test the setup
curl "http://localhost:4567/inventory"# Backend (Terminal 1)
mvn exec:java -Dexec.mainClass="com.topbloc.codechallenge.Main"
# Frontend (Terminal 2)
cd frontend
npm install
npm start
# Run comprehensive tests (Terminal 3)
mvn compile
java -cp "target/classes" com.topbloc.codechallenge.TestSuiteTo reset the database to its original state with fresh seed data:
Step 1: Stop Docker containers (if running)
docker compose downStep 2: Start the backend server locally Choose one of these options in your first terminal:
# Option A: IDE - Press the "Run" button on Main.java
# Option B: Full command
mvn exec:java -Dexec.mainClass="com.topbloc.codechallenge.Main"
# Option C: Short command (uses pom.xml configuration)
mvn exec:javaStep 3: Trigger the database reset In a second terminal, call the reset endpoint:
curl "http://localhost:4567/reset"Step 4: Verify the reset worked You should see this output in your first terminal:
Applying schema
Schema applied
Seeding database
Database seeded
Step 5: Confirm database state (optional) Verify the reset by checking the data:
curl "http://localhost:4567/inventory"
curl "http://localhost:4567/items"
curl "http://localhost:4567/distributors"# Test core endpoints
curl "http://localhost:4567/version"
curl "http://localhost:4567/inventory"
curl "http://localhost:4567/inventory/low-stock"
curl "http://localhost:4567/distributors"
# Test CSV export
curl "http://localhost:4567/export/csv?table=items" -o items.csv
# Test cheapest restock
curl "http://localhost:4567/items/1/cheapest?quantity=50"Basic Endpoints:
# Server info
curl "http://localhost:4567/version"
curl "http://localhost:4567/items"
# Database reset
curl "http://localhost:4567/reset"Inventory Management:
# Get all inventory
curl "http://localhost:4567/inventory"
# Filter inventory by status
curl "http://localhost:4567/inventory/out-of-stock"
curl "http://localhost:4567/inventory/low-stock"
curl "http://localhost:4567/inventory/overstocked"
# Get specific inventory item
curl "http://localhost:4567/inventory/1"
# Add new inventory item
curl -X POST "http://localhost:4567/inventory?itemId=1&stock=25&capacity=50"
# Update inventory stock and capacity
curl -X PUT "http://localhost:4567/inventory/1?stock=30"
curl -X PUT "http://localhost:4567/inventory/1?capacity=75"
curl -X PUT "http://localhost:4567/inventory/1?stock=40&capacity=80"
# Delete inventory item
curl -X DELETE "http://localhost:4567/inventory/1"Item Management:
# Add new items
curl -X POST "http://localhost:4567/items?name=Test%20Candy"
curl -X POST "http://localhost:4567/items?name=Super%20Gummy%20Bears"
# Get distributors for specific item
curl "http://localhost:4567/items/1/distributors"
# Find cheapest restock option
curl "http://localhost:4567/items/1/cheapest?quantity=25"
curl "http://localhost:4567/items/2/cheapest?quantity=100"Distributor Management:
# Get all distributors
curl "http://localhost:4567/distributors"
# Add new distributor
curl -X POST "http://localhost:4567/distributors?name=Sweet%20Supplier%20Co"
# Get items by distributor
curl "http://localhost:4567/distributors/1/items"
# Add pricing for distributor
curl -X POST "http://localhost:4567/distributors/1/items?itemId=1&cost=2.50"
curl -X POST "http://localhost:4567/distributors/2/items?itemId=3&cost=1.75"
# Update distributor pricing
curl -X PUT "http://localhost:4567/distributors/1/items/1?cost=2.25"
# Delete distributor pricing
curl -X DELETE "http://localhost:4567/distributors/1/items/1"
# Delete entire distributor
curl -X DELETE "http://localhost:4567/distributors/3"Data Export:
# Export all tables to CSV
curl "http://localhost:4567/export/csv?table=items" -o items.csv
curl "http://localhost:4567/export/csv?table=inventory" -o inventory.csv
curl "http://localhost:4567/export/csv?table=distributors" -o distributors.csv
curl "http://localhost:4567/export/csv?table=distributor_prices" -o pricing.csv
# Invalid table (for error testing)
curl "http://localhost:4567/export/csv?table=invalid"Real-Time Streaming:
# Test streaming connection (run in background)
curl -N "http://localhost:4567/stream/events" &
# While streaming is active, make changes to see live updates:
curl -X PUT "http://localhost:4567/inventory/1?stock=15"
curl -X PUT "http://localhost:4567/inventory/2?capacity=30"
curl -X POST "http://localhost:4567/items?name=Live%20Test%20Candy"
# View streaming dashboard in browser
open "http://localhost:4567/stream"Error Testing (for validation):
# Invalid parameters
curl -X POST "http://localhost:4567/inventory?itemId=999&stock=10&capacity=20"
curl -X PUT "http://localhost:4567/inventory/999?stock=10"
curl -X POST "http://localhost:4567/items?name="
curl -X POST "http://localhost:4567/distributors/1/items?itemId=1&cost=-5"
# Malformed requests
curl -X PUT "http://localhost:4567/inventory/abc?stock=10"
curl -X POST "http://localhost:4567/inventory?itemId=abc&stock=10&capacity=20"Load Testing Sequence:
# Quick sequence to generate multiple streaming events
for i in {1..5}; do
curl -X PUT "http://localhost:4567/inventory/$i?stock=$((RANDOM % 50))"
sleep 1
done
# Batch operations
curl -X POST "http://localhost:4567/items?name=Batch%20Test%201"
curl -X POST "http://localhost:4567/items?name=Batch%20Test%202"
curl -X POST "http://localhost:4567/items?name=Batch%20Test%203"Complete Workflow Test:
# 1. Reset database
curl "http://localhost:4567/reset"
# 2. Add new item
curl -X POST "http://localhost:4567/items?name=Workflow%20Test%20Candy"
# 3. Add to inventory
curl -X POST "http://localhost:4567/inventory?itemId=18&stock=50&capacity=100"
# 4. Add distributor
curl -X POST "http://localhost:4567/distributors?name=Test%20Distributor"
# 5. Add pricing
curl -X POST "http://localhost:4567/distributors/4/items?itemId=18&cost=3.00"
# 6. Update stock
curl -X PUT "http://localhost:4567/inventory/18?stock=25"
# 7. Check cheapest option
curl "http://localhost:4567/items/18/cheapest?quantity=10"
# 8. Export results
curl "http://localhost:4567/export/csv?table=inventory" -o workflow_test.csvThis project includes a comprehensive test suite with 79 automated tests that validate all API endpoints, error handling, and edge cases.
# 1. Start your server first
mvn exec:java -Dexec.mainClass="com.topbloc.codechallenge.Main"
# 2. In another terminal, compile and run tests
mvn compile
java -cp "target/classes" com.topbloc.codechallenge.TestSuite# Start the full stack
docker-compose up --build -d
# Run tests against the containerized API
mvn compile
java -cp "target/classes" com.topbloc.codechallenge.TestSuite- All API endpoints - GET, POST, PUT, DELETE operations
- Valid requests - Normal operations that should succeed
- Invalid inputs - Bad parameters, wrong formats, missing data
- Edge cases - Boundary conditions, empty values, very large numbers
- Security - SQL injection attempts, XSS protection
- Error handling - Proper HTTP status codes and error messages
You'll see results like:
TOPBLOC BACKEND CODE CHALLENGE - COMPREHENSIVE TEST SUITE
======================================================================
BASIC ENDPOINTS
--------------------------------------------------
✓ PASS GET /version
✓ PASS GET /items
✓ PASS GET /reset
INVENTORY ENDPOINTS
--------------------------------------------------
✓ PASS GET /inventory - Valid
✓ PASS GET /inventory/out-of-stock - Valid
...
======================================================================
TEST RESULTS SUMMARY
======================================================================
Total Tests: 79
Passed: 79
Failed: 0
Success Rate: 100.0%
ALL TESTS PASSED! Your API is working perfectly!
======================================================================
- Server not running? Make sure the API is accessible at
http://localhost:4567 - Tests failing? Try resetting the database:
curl "http://localhost:4567/reset" - Compilation issues? Run
mvn clean compilefirst
backend-code-challenge/
├── src/main/java/com/topbloc/codechallenge/
│ ├── Main.java # Spark route definitions & request handlers
│ ├── TestSuite.java # 79 comprehensive tests
│ └── db/DatabaseManager.java # Data access layer & business logic
├── frontend/ # React TypeScript application
│ ├── src/
│ │ ├── components/ # UI management modules
│ │ ├── services/api.ts # Typed API client
│ │ └── App.tsx # Main application
│ ├── public/ # Static assets
│ └── Dockerfile # Frontend container config
├── challenge.db # SQLite database file
├── docker-compose.yml # Multi-service orchestration
├── Dockerfile # Backend container config
├── pom.xml # Maven dependencies
└── README.md # Original challenge requirements
- Route-Handler pattern with Spark Framework for lightweight API design
- Direct route definitions with embedded request handling logic
- Data Access Layer (DatabaseManager) separating SQL operations from HTTP logic
- Comprehensive input validation and error handling
- SQL injection protection with prepared statements
- CORS configuration for cross-origin requests
- Database connection management and transactions
- Modern React 18 with TypeScript for type safety
- Material-UI for professional component library
- Responsive design with mobile-friendly layout
- Real-time inventory status indicators
- Advanced filtering and search capabilities
- Form validation with user-friendly error messages
- Production-ready Docker configuration
- Multi-stage builds for optimized container size
- Health checks and automatic restart policies
- Environment-based configuration
- Database persistence with volume mounting
- Automated test suite with 100% endpoint coverage
- Security testing for common vulnerabilities
- Performance considerations with connection pooling
- Proper HTTP status code implementation
- Comprehensive error scenarios testing
- Database: SQLite with proper indexing and foreign key constraints
- API: Efficient SQL queries with prepared statements
- Frontend: Production build with code splitting and minification
- Container: Multi-stage builds reducing image size by 60%
- Caching: Browser caching headers for static assets