diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644
index 0000000..e81a710
--- /dev/null
+++ b/DEVELOPMENT.md
@@ -0,0 +1,36 @@
+# APIS Development Environment Setup
+
+## Prerequisites
+* Docker & Docker Compose
+* Git
+
+## Setup Steps
+
+1. **Clone Dependencies**
+ Ensure all sub-repositories are cloned into the root structure:
+ * apis-bom
+ * apis-common
+ * apis-main
+ * apis-web
+ * apis-emulator
+
+2. **Start Sandbox Environment**
+ ```bash
+ docker-compose up --build
+ ```
+
+3. **Services**
+ * **Dashboard (Web)**: Endpoints available at `localhost:43900` and `localhost:9999`.
+ * **Grid Master (Main)**: Running autonomously.
+ * **Hardware (Emulator)**: Simulating 4 battery units.
+
+## Testing APIs
+See `validate_env.py` for automated testing.
+
+* **Energy Balance Check**: `GET http://localhost:43900/get/log`
+* **Power Allocation**: `POST http://localhost:9999/deal`
+
+## Troubleshooting
+* **Build Fails**: Ensure `apis-bom` and `apis-common` are using version 3.0.0 in `pom.xml`.
+* **Ports in Use**: Stop native services if running (`make stop`).
+* **Hazelcast Errors**: Docker Compose uses `hostname -i` to discover peers. Ensure firewall allows port 5701.
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..e3f4e07
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,49 @@
+# Stage 1: Build All Java Components
+FROM maven:3.9-eclipse-temurin-11 AS builder
+WORKDIR /build
+
+# Copy and install BOM
+COPY apis-bom /build/apis-bom
+# APPLY PATCH: Fix dependency versions
+COPY patches/apis-bom-pom.xml /build/apis-bom/pom.xml
+WORKDIR /build/apis-bom
+RUN mvn install -DskipTests
+
+# Copy and install Common
+COPY apis-common /build/apis-common
+# APPLY PATCH: Fix dependency versions
+COPY patches/apis-common-pom.xml /build/apis-common/pom.xml
+WORKDIR /build/apis-common
+RUN mvn install -DskipTests
+
+# Build apis-main
+COPY apis-main /build/apis-main
+WORKDIR /build/apis-main
+RUN mvn package -DskipTests
+
+# Build apis-web
+COPY apis-web /build/apis-web
+WORKDIR /build/apis-web
+RUN mvn package -DskipTests
+
+# Stage 2: APIS Main Runtime
+FROM eclipse-temurin:11-jre AS apis-main
+WORKDIR /app
+COPY --from=builder /build/apis-main/target/apis-main-*-fat.jar /app/apis-main.jar
+# Default config files will be mounted via Volume or use defaults
+COPY apis-main/exe/logging.properties /app/
+COPY apis-main/exe/config.json /app/
+COPY apis-main/exe/cluster.xml /app/
+ENV CLUSTER_HOST_IP=127.0.0.1
+# Entrypoint to dynamically set cluster host IP
+CMD ["sh", "-c", "java -Djava.net.preferIPv4Stack=true -Djava.util.logging.config.file=./logging.properties -Dvertx.hazelcast.config=./cluster.xml -jar apis-main.jar -conf ./config.json -cluster -cluster-host $(hostname -i)"]
+
+# Stage 3: APIS Web Runtime
+FROM eclipse-temurin:11-jre AS apis-web
+WORKDIR /app
+COPY --from=builder /build/apis-web/target/apis-web-*-fat.jar /app/apis-web.jar
+COPY apis-web/exe/logging.properties /app/
+COPY apis-web/exe/config.json /app/
+COPY apis-web/exe/cluster.xml /app/
+ENV CLUSTER_HOST_IP=127.0.0.1
+CMD ["sh", "-c", "java -Djava.net.preferIPv4Stack=true -Djava.util.logging.config.file=./logging.properties -jar apis-web.jar -conf ./config.json -cp ./ -cluster -cluster-host $(hostname -i)"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..5fc44e6
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,40 @@
+version: '3.8'
+
+services:
+ mongodb:
+ image: mongo:4.4
+ container_name: apis-mongo
+ ports:
+ - "27017:27017"
+
+ apis-main:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ target: apis-main
+ container_name: apis-main
+ depends_on:
+ - mongodb
+ ports:
+ - "5701:5701" # Hazelcast
+
+ apis-web:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ target: apis-web
+ container_name: apis-web
+ depends_on:
+ - apis-main
+ ports:
+ - "43830:43830" # Budo Emulator
+ - "43900:43900" # Emulator Emulator
+ - "9999:9999" # API Server (Deals/Errors)
+
+ apis-emulator:
+ build:
+ context: .
+ dockerfile: emulator.Dockerfile
+ container_name: apis-emulator
+ command: python3 startEmul.py 4
+ network_mode: service:apis-main # Run in same net namespace to simulate local Hardware connection if using multicast, simplifed for now
diff --git a/emulator.Dockerfile b/emulator.Dockerfile
new file mode 100644
index 0000000..81af311
--- /dev/null
+++ b/emulator.Dockerfile
@@ -0,0 +1,8 @@
+FROM python:3.9-slim
+WORKDIR /app
+COPY apis-emulator/requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+COPY apis-emulator/ .
+# Fix line endings if cloned on Windows
+RUN apt-get update && apt-get install -y dos2unix && dos2unix *.py *.sh
+CMD ["python3", "startEmul.py", "4"]
diff --git a/patches/apis-bom-pom.xml b/patches/apis-bom-pom.xml
new file mode 100644
index 0000000..68d2858
--- /dev/null
+++ b/patches/apis-bom-pom.xml
@@ -0,0 +1,58 @@
+
+ 4.0.0
+
+
+ UTF-8
+ 3.7.1
+ 4.12
+ 2.4
+
+
+ jp.co.sony.csl.dcoes.apis
+ apis-bom
+ 3.0.0
+ pom
+
+ APIS BOM
+
+
+
+
+ jp.co.sony.csl.dcoes.apis
+ apis-common
+ ${project.version}
+
+
+ io.vertx
+ vertx-core
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-mongo-client
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-hazelcast
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-unit
+ ${vertx.version}
+
+
+ junit
+ junit
+ ${junit.version}
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+
+
+
diff --git a/patches/apis-common-pom.xml b/patches/apis-common-pom.xml
new file mode 100644
index 0000000..6c18f48
--- /dev/null
+++ b/patches/apis-common-pom.xml
@@ -0,0 +1,59 @@
+
+ 4.0.0
+
+
+ UTF-8
+ 3.7.1
+
+
+ jp.co.sony.csl.dcoes.apis
+ apis-common
+ 3.0.0
+
+ APIS COMMON
+
+
+
+
+ jp.co.sony.csl.dcoes.apis
+ apis-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+ io.vertx
+ vertx-core
+
+
+ io.vertx
+ vertx-unit
+ test
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 1.8
+ 1.8
+
+
+
+
+
+
diff --git a/validate_env.py b/validate_env.py
new file mode 100644
index 0000000..63fb1da
--- /dev/null
+++ b/validate_env.py
@@ -0,0 +1,55 @@
+import requests
+import json
+import time
+
+print("Waiting for services to start...")
+time.sleep(10) # Simple wait, or use retry logic
+
+# 1. Energy Balance Check (Get Hardware Logs)
+try:
+ print("\n--- Testing Energy Balance Check API ---")
+ url = "http://localhost:43900/get/log"
+ print(f"GET {url}")
+ response = requests.get(url, timeout=5)
+ print(f"Status: {response.status_code}")
+ if response.status_code == 200:
+ data = response.json()
+ print("Success! Received hardware telemetry.")
+ # Check first key (usually 'apis' or specific unit ID)
+ print(f"Keys: {list(data.keys())[:3]}...")
+ else:
+ print("Failed to get logs.")
+except Exception as e:
+ print(f"Error: {e}")
+
+# 2. Power Allocation (Deal Generation)
+try:
+ print("\n--- Testing Power Allocation API ---")
+ url = "http://localhost:9999/deal"
+
+ # Mock OpenPAYGO Deal Payload (Example shape based on code)
+ payload = {
+ "dealId": "test-deal-001",
+ "requestUnitId": "unit1",
+ "acceptUnitId": "unit2",
+ "amountWh": 100,
+ "type": "charge"
+ }
+
+ # The API expects form-data with a 'json' field containing the stringified JSON
+ files = {
+ 'json': (None, json.dumps(payload))
+ }
+
+ print(f"POST {url} with payload: {payload}")
+ response = requests.post(url, files=files, timeout=5)
+ print(f"Status: {response.status_code}")
+ print(f"Response: {response.text}")
+
+ if response.status_code == 200:
+ print("Success! Deal request submitted.")
+ else:
+ print("Deal submission failed.")
+
+except Exception as e:
+ print(f"Error: {e}")