This monorepo consists of:
product-service(port 3001, TCP port 4001) — A hybrid HTTP & TCP NestJS microservice.order-service(port 3002) — An HTTP NestJS service that integrates withproduct-servicevia TCP.dynamic-form(port 3000) — A Next.js (App Router) + TypeScript client that renders responsive forms dynamically based on a JSON config.
Assignment/
├── apps/
│ ├── product-service/ # NestJS Hybrid HTTP/TCP service (Port: 3001, TCP: 4001)
│ ├── order-service/ # NestJS HTTP service (Port: 3002)
│ └── dynamic-form/ # Next.js client application (Port: 3000)
├── product.db # SQLite database for product-service
├── order.db # SQLite database for order-service
├── package.json # Monorepo dependencies & scripts
└── test-integration.sh # Automated end-to-end integration test script
Ensure you have Node.js installed, and run npm install in the root workspace directory first.
To run the projects, execute these commands from the root directory:
# 1. Run product-service
npx nx serve product-service
# 2. Run order-service
npx nx serve order-service
# 3. Run Next.js Dynamic Form client
npx nx serve dynamic-form| Service | Protocol | Host/Port | Details |
|---|---|---|---|
| Next.js Client | HTTP | http://localhost:3000 |
Web UI Dashboard |
| Product Service | HTTP | http://localhost:3001 |
REST CRUD Endpoints |
| Product Service | TCP | localhost:4001 |
Inter-service microservice TCP channel |
| Order Service | HTTP | http://localhost:3002 |
REST Orders Endpoints |
You can verify the backend services using the following HTTP endpoints:
-
Create a product (Validation constraints: positive stock & price, category, and unique SKU):
curl -X POST http://localhost:3001/products \ -H "Content-Type: application/json" \ -d '{"name": "Gaming Mouse", "description": "Wireless RGB gaming mouse", "price": 49.99, "stock": 50, "sku": "MS-GAME-01", "category": "Peripherals"}'
-
Retrieve all products:
curl http://localhost:3001/products
-
Retrieve a single product by UUID:
curl http://localhost:3001/products/<uuid>
-
Update product price/stock (PATCH):
curl -X PATCH http://localhost:3001/products/<uuid> \ -H "Content-Type: application/json" \ -d '{"price": 45.99, "stock": 45}'
-
Delete a product:
curl -X DELETE http://localhost:3001/products/<uuid>
-
Create a multi-item order (Validates existence & stock via TCP, decrements product stock, computes totalAmount, saves snapshot):
curl -X POST http://localhost:3002/orders \ -H "Content-Type: application/json" \ -d '{"items": [{"productId": "<uuid>", "quantity": 2}], "customerName": "Jane Smith"}'
-
Retrieve all orders:
curl http://localhost:3002/orders
-
Retrieve a single order by UUID:
curl http://localhost:3002/orders/<uuid>
The DynamicForm component renders the following Material UI components dynamically on the screen based on the JSON array config object:
{
"id": "Unique string ID",
"name": "Form attribute name (used for register keys)",
"fieldType": "TEXT | LIST | RADIO",
"defaultValue": "Initial field state value",
"required": true | false,
"minLength": 3, // Optional (only applicable for TEXT fieldType)
"maxLength": 30, // Optional (only applicable for TEXT fieldType)
"listOfValues1": ["Option A", "Option B"] // Array of options (required for LIST & RADIO)
}-
TEXTfieldType ➡️ Renders a Material UI<TextField>- Handled by
react-hook-form's<Controller>. - Automatically configures validation rules in yup:
required: Appends.required("name is required").minLength: Appends.min(minLength).maxLength: Appends.max(maxLength).
- Handled by
-
LISTfieldType ➡️ Renders a Material UI<Select>dropdown inside<FormControl>- Renders
<MenuItem>options based on the elements defined inlistOfValues1. - Automatically handles empty states and defaults.
- Renders
-
RADIOfieldType ➡️ Renders a Material UI<RadioGroup>inside<FormControl>- Renders a series of
<FormControlLabel>buttons representing each value inlistOfValues1inside a horizontal group.
- Renders a series of