Skip to content

About

ScenarioManager is a web editor and execution service for connected autonomous vehicle scenarios. It combines a React editor, a FastAPI backend, PostgreSQL, CARLA, and the bundled OpenCDA runtime.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

ScenarioManager | CAVISE

ScenarioManager is a web editor and execution service for connected autonomous vehicle scenarios. It combines a React editor, a FastAPI backend, PostgreSQL, CARLA, and the bundled OpenCDA runtime.

Demo

Scene Editor

Scene editor

Scene Graph

Scene graph panel

Configuration Export

Configuration export

Screenshots

Editor Object settings
3D editor Settings panel
Simulation settings Export menu
Simulation settings Export menu

Main Capabilities

  • Edit roads, vehicles, RSUs, obstacles, weather, and attack scenarios.
  • Validate scenarios before export or simulation.
  • Export OpenCDA YAML, OpenSCENARIO, OpenDRIVE, and CARLA Python scripts.
  • Start and monitor OpenCDA simulations through REST and WebSocket APIs.
  • Store scenarios in PostgreSQL and expose run artifacts through the backend.
  • Evaluate routes, collisions, localization, communication, and attack effects.

Stack

Area Technologies
Frontend React, TypeScript, Vite, Zustand, MapLibre GL, Three.js
Backend Python, FastAPI, Pydantic, SQLAlchemy, Alembic
Simulation CARLA 0.9.16, OpenCDA, SUMO integration
Storage PostgreSQL 17
Tooling Docker Compose, uv, Yarn, Vitest, Playwright, pytest, Ruff

Prerequisites

  • Docker Engine with Docker Compose.
  • CARLA 0.9.16 for running simulations.
  • Python 3.11 or 3.12 and uv for local backend work.
  • Node.js 22 with Corepack for local frontend work.

Quick Start

  1. Create the environment file and set a real database password:

    cp .env.example .env
  2. Prepare the evaluation directory for the backend container user:

    mkdir -p evaluation_outputs
    sudo chown -R 10001:10001 evaluation_outputs
    sudo chmod -R a+rX evaluation_outputs

    The backend runs as UID/GID 10001 and needs write access. Artifacts must remain readable by all users because the rootless frontend container mounts the same directory read-only.

  3. Start CARLA on the host configured by CARLA_HOST and CARLA_PORT.

  4. Build and start the complete system:

    docker compose --profile prod up --build -d
  5. Check service status:

    docker compose ps

Open the frontend at http://localhost, the API at http://localhost:8000, and the OpenAPI documentation at http://localhost:8000/docs.

The backend waits for PostgreSQL and applies Alembic migrations automatically because Compose sets RUN_MIGRATIONS=1.

System Commands

Command Description
docker compose --profile prod up --build -d Build and start frontend, backend, and PostgreSQL.
docker compose up --build backend Start backend and PostgreSQL in the foreground.
docker compose ps Show service and health status.
docker compose logs -f backend Follow backend and simulation process logs.
docker compose logs -f db Follow PostgreSQL logs.
docker compose restart backend Restart only the backend service.
docker compose exec backend alembic current Show the applied database revision.
docker compose exec backend alembic upgrade head Apply all pending migrations manually.
docker build --target test --tag scenario-manager-backend-test . Build the isolated backend test image used by CI.
docker run --rm scenario-manager-backend-test Run the backend pytest suite in that image.
docker compose stop Stop services without removing containers.
docker compose down Stop and remove service containers.
docker compose down -v Also delete database and evaluation volumes.

Use curl http://localhost:8000/health for a direct backend health check.

Backend Development

Install the core dependencies:

uv sync

Include CARLA and the full simulation stack when needed:

uv sync --extra simulation

Install the repository hook once after dependency installation:

uv run pre-commit install

It formats and checks only staged Python, TypeScript, and SCSS files. Run the same checks for the whole repository with uv run pre-commit run --all-files.

Command Description
uv run pytest tests/backend -q Run backend tests.
uv run ruff check app tests migrations main.py Run Python lint checks.
uv run alembic upgrade head Apply migrations from the local environment.
uv run alembic current Show the current database revision.
make dev Shortcut for starting backend and PostgreSQL with Compose.
make test Shortcut for backend tests.

Local Alembic commands require a database reachable with the values from .env. The standard Compose database is intentionally available only inside the Compose network, so migration execution normally happens in the backend container.

Frontend Development

Install dependencies and start Vite:

corepack enable
yarn --cwd frontend install --frozen-lockfile
yarn --cwd frontend dev

The development UI is available at http://localhost:5173. Set VITE_API_URL in frontend/.env.development when the backend is not available at its default address.

Command Description
yarn --cwd frontend build Build the production frontend.
yarn --cwd frontend test Run Vitest once.
yarn --cwd frontend test:watch Run Vitest in watch mode.
yarn --cwd frontend test:e2e Run Playwright end-to-end tests.
yarn --cwd frontend lint Run ESLint.
yarn --cwd frontend lint:css Fix Stylelint issues.
yarn --cwd frontend format Format frontend files with Prettier.
make frontend Shortcut for the Vite development server.
make frontend-test Shortcut for frontend tests.

Before running Playwright locally for the first time, install its browser with yarn --cwd frontend playwright install chromium.

Configuration

The backend loads .env through pydantic-settings and python-dotenv. Compose also passes this file to the backend with env_file and refuses to start PostgreSQL when the required database values are missing.

Variable Purpose Example
DB_NAME PostgreSQL database name. scenario_manager
DB_USER PostgreSQL user. scenario_manager
DB_PASSWORD PostgreSQL password. change-me
DB_HOST Compose PostgreSQL service host. db
DB_PORT PostgreSQL port inside the Compose network. 5432
DB_ENCODING Database client encoding. UTF8
CARLA_HOST CARLA host reachable from the backend container. host.docker.internal
CARLA_PORT CARLA RPC port. 2000
CARLA_TRAFFIC_MANAGER_PORT Traffic Manager RPC port inside the backend container. 8001
CARLA_TIMEOUT_SECONDS CARLA connection timeout. 60
RUN_MIGRATIONS Run alembic upgrade head on backend startup when set to 1. 1

Compose defines RUN_MIGRATIONS=1. Other values belong in .env; do not put secrets in docker-compose.yml.

In production, set AUTH_JWT_SECRET (at least 32 characters), AUTH_BOOTSTRAP_ADMIN_EMAIL, and AUTH_BOOTSTRAP_ADMIN_PASSWORD (at least 12 characters). The first startup creates that admin if it does not yet exist. Authenticate via POST /api/auth/login; the access token is also stored in a secure httpOnly cookie. The web interface shows a sign-in screen whenever JWT authentication is enabled; it never stores the token in browser storage. Admins can create operator and viewer users through POST /api/auth/users. Viewers have read-only API access; operators and admins can edit scenarios and control simulation runs.

When AUTH_JWT_SECRET is empty in development, the app deliberately uses a local development admin and disables login/logout. Set all three AUTH_* variables and restart Compose to enable the login screen and real user sessions.

Runtime Flow

  1. The frontend creates or imports a road network and scenario objects.
  2. The backend validates and stores scenarios in PostgreSQL.
  3. Export uses the same canonical OpenCDA YAML builder as simulation startup.
  4. The backend launches OpenCDA against CARLA and streams status over WebSocket.
  5. Evaluation reports, plots, and diagnostic logs are exposed as run results.

The simulation request keeps its JSON structure and includes the generated OpenCDA YAML as the opencda_config_yaml string. The current request and response schemas are documented at /docs.

API Summary

Scenarios

Method Endpoint Purpose
GET /api/v1/scenarios?offset=0&limit=50 List scenarios.
GET /api/v1/scenarios/{scenario_id} Load a scenario.
POST /api/v1/scenarios Create a scenario.
PATCH /api/v1/scenarios/{scenario_id} Update a scenario.
DELETE /api/v1/scenarios/{scenario_id} Delete a scenario.

Simulation

Method Endpoint Purpose
POST /api/start_opencda Start a simulation run.
GET /api/status Read current simulation status.
POST /api/stop Stop the current simulation.
WS /api/ws/simulation Stream simulation status updates.
GET /api/results List completed, partial and archived runs.
GET /api/results/{run_id} Return chart samples, metadata and artifact links.
DELETE /api/results/{run_id} Delete evaluation artifacts.
GET /api/results/{run_id}/files/{filename} Download an artifact.
GET /health Check backend and database health.

Logs and Data

  • docker compose logs -f backend contains service startup, API, runner, and simulation process output.
  • Evaluation reports and detailed per-run diagnostics are written under evaluation_outputs/, which is bind-mounted into the backend container.
  • On Linux hosts, keep evaluation_outputs/ owned by UID/GID 10001 and readable by all users (chmod -R a+rX) so the backend can write artifacts and the rootless frontend can serve them.
  • PostgreSQL data is stored in the postgres_data named volume.
  • Uploaded custom OpenDRIVE maps are written under assets/xodrs/.
  • Run artifacts are also available through /api/results/{run_id}.

Interactive results (MVP)

A ready-to-view example is included as DEMO · Town01 — GNSS drift. Open Results, press Refresh and select it in the run history. It contains 33 interactive charts for three vehicles: routes, speed, acceleration, GNSS/filter errors, safety events and RSU coverage. The curves are synthetic and clearly labelled as demo data; the original POC_Scenario_Town01 only supplied the scenario inspiration and vehicle start/end positions. No CARLA simulation is needed to view it.

The history list and chart area scroll independently. To recreate the example after deleting it or after automatic result retention cleanup, run:

docker run --rm -v "$PWD:/app" -w /app python:3.11-slim python scripts/create_demo_results.py

New runs save evaluation_outputs/<run_id>/charts.json instead of rendering PNG charts on the server. Results use local files only; no new database tables or migrations are needed. The existing scenario database is separate from this results storage. The configured EVAL_DIR and the Docker bind mount determine where files survive container restarts; the existing retention policy still applies.

GET /api/results/<run_id> returns files, run_id, data and data_error. data is the versioned chart document:

{
  "schema_version": 1,
  "run_id": "Town01_example",
  "fixed_delta_seconds": 0.05,
  "elapsed_seconds": 10,
  "actors": [{ "id": "7", "label": "Vehicle 7", "metrics": [] }],
  "charts": [{
    "id": "speed",
    "actor_id": "7",
    "title": "Vehicle speed",
    "description": "Speed reported by the V2X manager.",
    "category": "motion",
    "kind": "line",
    "x_axis": { "label": "Elapsed simulation time", "unit": "s" },
    "y_axis": { "label": "Speed", "unit": "km/h" },
    "series": [{ "id": "transmitted", "label": "V2X-transmitted speed", "points": [[0.05, 3.6], [0.1, 7.2]] }]
  }],
  "warnings": []
}

Points are [x, y] pairs; null Y values mark unavailable measurements and produce gaps. Time-stamped buffers use simulation seconds (tick × step duration). IMU, localization and planner buffers without timestamps use explicitly labelled sample indices. Routes use world coordinates in metres with equal axis scaling. TTC values ≥ 1000 seconds and platoon gaps ≥ 100 are unavailable sentinels. Full available samples are retained, including short and stopped runs. The planner itself omits its first 100 updates. Safety counters count affected ticks, while the collision indicator also includes late sensor callbacks.

Results provides vehicle and category selection, interactive legends, pointer and keyboard inspection, a sample table, metrics and downloads. Select two runs for comparison and choose the vehicle independently in each; CARLA actor IDs are not stable across runs. Old PNG-only runs remain downloadable with data: null. Unreadable chart files return data_error while keeping other downloads available. metrics.json, configuration files and diagnostic logs remain available too.

Inspect generated files in the backend container when using Docker:

docker compose exec backend ls -la evaluation_outputs

Project Structure

scenario-manager/
|-- app/
|   |-- routers/                 # REST and WebSocket endpoints
|   |-- config.py                # .env-backed application settings
|   |-- database.py              # SQLAlchemy engine and sessions
|   |-- models.py                # ORM database models
|   |-- schemas.py               # Pydantic API contracts
|   |-- opencda_config.py        # Canonical OpenCDA YAML processing
|   |-- runner.py                # CARLA/OpenCDA process orchestration
|   |-- scenario_validation.py   # Scenario validation rules
|   `-- log_config.py            # Backend logging setup
|-- migrations/
|   |-- versions/                # Alembic migration revisions
|   `-- env.py                   # Alembic runtime configuration
|-- opencda/                     # Bundled OpenCDA simulation runtime
|-- frontend/
|   |-- src/
|   |   |-- api/                 # Backend API clients
|   |   |-- components/          # Shared React components
|   |   |-- pages/               # Editor and generator screens
|   |   `-- store/               # Zustand application state
|   |-- tests/e2e/               # Playwright tests
|   |-- public/                  # Static frontend files
|   |-- Dockerfile               # Development and production stages
|   `-- nginx/default.conf       # Production reverse proxy
|-- assets/xodrs/                # Runtime custom OpenDRIVE maps
|-- evaluation_outputs/          # Local simulation artifacts and diagnostics
|-- tests/
|   |-- backend/                 # pytest backend suite
|   `-- load/                    # Load-test scenarios
|-- alembic.ini                  # Alembic CLI configuration
|-- docker-compose.yml           # Backend, PostgreSQL, and production UI
|-- Dockerfile                   # Backend image
|-- entrypoint.sh                # Optional migration startup hook
|-- main.py                      # FastAPI application entry point
|-- pyproject.toml               # Python dependencies and tool settings
|-- uv.lock                      # Locked Python dependency graph
`-- Makefile                     # Common development shortcuts

License

Copyright (c) 2025 CAVISE. All rights reserved.

About

ScenarioManager is a web editor and execution service for connected autonomous vehicle scenarios. It combines a React editor, a FastAPI backend, PostgreSQL, CARLA, and the bundled OpenCDA runtime.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages