Developer Quickstart
What you'll learn: Clone the repo, start all services, run your first Unit Commitment solve against the IEEE 118-bus test network, and run your first parametric experiment.
Time: approximately 20 minutes on a developer laptop with Docker already installed.
Prerequisites
| Tool | Required version | Check |
|---|---|---|
| Docker + Docker Compose | 24.0+ / v2.20+ | docker --version |
| Python | 3.12 | python3 --version |
| Julia | 1.10+ | julia --version |
| Node.js | 20 LTS | node --version |
| pnpm | 8+ | pnpm --version |
| curl + jq | any | curl --version && jq --version |
Docker is used for PostgreSQL, Redis, and MinIO. Julia and Python run locally for development.
Step 1: Clone and configure
git clone https://github.com/your-org/MangoGridStudio.git
cd MangoGridStudio
Copy the environment template:
cp backend/.env.example backend/.env
The defaults work for local development. Key variables:
DATABASE_URL= # leave blank to use the derived local-dev URL
POSTGRES_USER=mangogrid
POSTGRES_PASSWORD=mangogrid123
POSTGRES_DB=mangogrid_uc
DB_SERVER_PORT=5432
REDIS_URL=redis://localhost:6379/0
JULIA_URL=http://localhost:8082
AUTH_BYPASS_ENABLED=True # disable auth for local dev
ANTHROPIC_API_KEY= # optional; enables AI Analyst and OpenAI fallback route
OPENAI_API_KEY= # optional; tuning_diagnosis auto-reroutes away unless customer acknowledgement is enabled
OPENAI_BASE_URL=
MANGOGRID_OPENAI_CUSTOMER_ACKNOWLEDGED=false
Step 2: Start infrastructure services
cd backend
docker-compose up -d postgres redis minio
Verify all three services are healthy:
docker-compose ps
Expected output — all three should show healthy:
NAME STATUS
MangoGrid_uc_postgres running (healthy)
MangoGrid_uc_redis running (healthy)
MangoGrid_uc_minio running (healthy)
If any show starting, wait 10 seconds and run docker-compose ps again.
Step 3: Install Python dependencies
cd backend
python3 -m venv .venv
source .venv/bin/activate # on Windows: .venv\Scripts\activate
pip install -r requirements.txt
Run database migrations:
alembic upgrade head
Expected output ends with:
INFO [alembic.runtime.migration] Running upgrade ... -> <revision_id>, ...
Step 4: Start the FastAPI backend
uvicorn app.main:app --host 0.0.0.0 --port 58000 --reload
Verify it is up:
curl -s http://localhost:58000/health | jq .
Expected:
{ "status": "ok" }
Step 5: Start the Julia solver API
In a new terminal:
cd backend/julia_api
julia --project=. build.jl # first run only — downloads and precompiles packages (~5-10 min)
julia --project=. -e 'using MangoGridJuliaAPI; MangoGridJuliaAPI.run()'
The first build.jl step downloads Julia packages (HiGHS, JuMP, UnitCommitment, etc.) and precompiles the system image. This takes 5-10 minutes on first run and is cached for subsequent runs.
Verify:
curl -s http://localhost:8082/health | jq .
Expected:
{ "status": "ok", "version": "0.1.0" }
Step 6: Start the frontend (optional)
In a new terminal:
pnpm install
pnpm dev
The frontend will be available at http://localhost:5173.
Step 7: Run your first UC solve
Use the IEEE 118-bus 24-hour test input from examples/uc_input_ieee118_24h.json.
7a. Submit the job
With AUTH_BYPASS_ENABLED=True, you can skip the login step and use any token:
JOB=$(curl -s -X POST http://localhost:58000/modules/analyst/solve/uc \
-H "Content-Type: application/json" \
-H "Authorization: Bearer dev-bypass-token" \
-d '{
"scenario_id": "quickstart_ieee118",
"payload": '"$(cat examples/uc_input_ieee118_24h.json)"',
"timeout": 120
}' | jq -r .job_id)
echo "Job submitted: $JOB"
7b. Poll for completion
until curl -s http://localhost:58000/modules/analyst/solve/$JOB/status \
-H "Authorization: Bearer dev-bypass-token" | jq -r .status | grep -q completed; do
sleep 2
echo -n "."
done
echo "Solve complete."
Expected: the loop exits after ~4 seconds for the IEEE 118-bus 24-hour problem.
7c. Fetch results
curl -s http://localhost:58000/modules/analyst/solve/$JOB/results \
-H "Authorization: Bearer dev-bypass-token" | jq '{
objective_value,
solve_time_s,
termination_status
}'
Expected output:
{
"objective_value": 142850.50,
"solve_time_s": 3.8,
"termination_status": "OPTIMAL"
}
If you get "termination_status": "INFEASIBLE", the most common causes are:
- Total generator
p_max< peak load. Check that sum of allp_maxvalues exceeds the highest load value. - A generator has
p_min > p_max. Check generator data. min_uptimeormin_downtimeconstraints conflict withinitial_status. See Troubleshooting.
Step 8: Submit your first experiment
Run a fuel price sensitivity sweep over the IEEE 118-bus case:
EXP=$(curl -s -X POST http://localhost:58000/experiments/submit \
-H "Content-Type: application/json" \
-H "Authorization: Bearer dev-bypass-token" \
-d '{
"name": "quickstart_gas_sensitivity",
"base_scenario_id": "quickstart_ieee118",
"scenario_matrix": {
"method": "grid",
"variables": [
{
"name": "gas_price_per_mmbtu",
"type": "continuous",
"min": 2.0,
"max": 6.0,
"steps": 3
}
]
},
"timeout_per_scenario": 60,
"max_parallel": 2
}' | jq -r .experiment_id)
echo "Experiment submitted: $EXP"
Poll progress:
watch -n 2 "curl -s http://localhost:58000/experiments/$EXP/status \
-H 'Authorization: Bearer dev-bypass-token' | jq '{status, scenarios_completed, scenarios_total}'"
Download results as CSV when complete:
curl -s "http://localhost:58000/experiments/$EXP/results/download?format=csv" \
-H "Authorization: Bearer dev-bypass-token" \
-o experiment_results.csv
cat experiment_results.csv
Step 9: Ask the AI Analyst a question
First generate explain artifacts:
curl -s -X POST "http://localhost:58000/modules/analyst/explain/quickstart_ieee118/generate" \
-H "Authorization: Bearer dev-bypass-token" | jq .
Then ask a question:
curl -s -X POST http://localhost:58000/modules/analyst/chat \
-H "Content-Type: application/json" \
-H "Authorization: Bearer dev-bypass-token" \
-d '{
"scenario_id": "quickstart_ieee118",
"message": "Which transmission constraints are binding at the peak hour and what are their shadow prices?"
}' | jq .response
The AI Analyst will call get_binding_constraints automatically and respond in plain English.
Note: the AI Analyst requires an ANTHROPIC_API_KEY environment variable set in backend/.env. If it is not set, the chat endpoint returns 503. Set it with:
echo "ANTHROPIC_API_KEY=sk-ant-..." >> backend/.env
Step 10: Explore the API
Swagger UI
The FastAPI backend generates interactive API documentation automatically. With the backend running, open:
http://localhost:58000/docs
Every endpoint is listed with its request schema, response schema, and a "Try it out" button. No separate tool required.
For a read-only view, ReDoc is at:
http://localhost:58000/redoc
Export the OpenAPI spec
To generate a static backend/openapi.json for use with Postman, code generators, or offline documentation:
python scripts/export_openapi.py
Expected output:
[INFO] Importing FastAPI application ...
[INFO] Generating OpenAPI schema ...
[OK] OpenAPI schema written to backend/openapi.json
[INFO] Total endpoints: 87
To validate the schema and print a grouped endpoint table:
python scripts/export_openapi.py --validate --catalog
This is safe to run without a live database — it extracts the schema from the in-memory FastAPI app.
Load in Postman
- Open Postman and select
File > Import - Choose
Fileand selectbackend/openapi.json - Postman generates a full collection with all endpoints pre-configured
- Set
baseUrltohttp://localhost:58000in the collection variables - Add
Authorization: Bearer dev-bypass-tokento the collection headers (whileAUTH_BYPASS_ENABLED=True)
Concept guides
Before writing production integrations, read the concept guides to understand what the solver is actually doing:
| Guide | Covers |
|---|---|
| Unit Commitment | DA-UC objective function, constraint types, IC chaining, Enhanced UC pipeline |
| LMP Decomposition | LMP = energy + congestion + loss (PJM M11 §6.4), PTDF derivation, worked 2-bus example |
Using authentication in production
When AUTH_BYPASS_ENABLED=False (the production default):
# Login
TOKEN=$(curl -s -X POST http://localhost:58000/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"your@email.com","password":"yourpassword"}' | jq -r .access_token)
# Use token
curl -s http://localhost:58000/modules/analyst/solve/uc \
-H "Authorization: Bearer $TOKEN" \
...
Using the Python client
The Python solver client provides an async wrapper for the Julia solver API:
import asyncio
import json
# Import the solver client from the backend package
from backend.analyst.solver.client import JuliaSolverClient
async def main():
client = JuliaSolverClient(base_url="http://localhost:8082")
with open("examples/uc_input_ieee118_24h.json") as f:
payload = json.load(f)
job_id = await client.submit_job("uc", payload, timeout=120)
result = await client.wait_for_result(job_id, poll_interval=2.0)
print(f"Objective: {result['objective_value']:.2f}")
print(f"Solve time: {result['solve_time_s']:.1f}s")
asyncio.run(main())
Troubleshooting
"Connection refused" on port 8082
The Julia API takes 2-3 minutes to start on a warm JIT cache. Run curl http://localhost:8082/health every 10 seconds until it responds.
If it never responds, check the Julia terminal for errors. The most common cause is a missing package — run julia --project=. build.jl again.
"INFEASIBLE" solve result
- Check that total
p_maxacross all generators exceeds the peak load in all 24 hours. - Check that no generator has
p_min > p_max. - Check that
initial_statusis consistent withmin_uptime/min_downtime. For example, a generator withmin_uptime=8andinitial_status=1(online for 1 hour) is valid. A generator withmin_downtime=4andinitial_status=-1(offline for 1 hour) must stay offline for 3 more hours at the start of the solve.
"502 Bad Gateway" from FastAPI
The Julia solver service is not reachable. Check that http://localhost:8082/health returns 200, and that JULIA_API_URL in backend/.env matches the running address.
Alembic "relation does not exist"
The PostgreSQL container is not fully initialized yet. Run docker-compose ps and wait until MangoGrid_uc_postgres shows healthy, then re-run alembic upgrade head.
MinIO connection errors
MinIO can take 15-20 seconds to finish initializing. If the FastAPI backend fails with S3 errors on startup, restart it: uvicorn app.main:app --host 0.0.0.0 --port 58000 --reload.
What to read next
- API Reference — authentication and Unit Commitment endpoint documentation
- Unit Commitment — what the UC solver is actually doing, constraint types, and PJM M11 references
- LMP Decomposition — how LMP = energy + congestion + loss (PJM M11 §6.4)
examples/uc_input_ieee118_24h.json— the canonical test input (54 generators, 118 buses, 24h)