Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This project reproduces the legacy PHP/jQuery stack with a contemporary architec

## How This Differs From The Original

- The original UmpleOnline in the legacy `umple` repo is a PHP/jQuery application; this repo splits the app into a React/Vite frontend, a Go API, and a Node-based code execution service.
- The original UmpleOnline in the legacy `umple` repo is a PHP/jQuery application; this repo splits the app into a React/Vite frontend, a Go API, dedicated collaboration and LSP proxy services, and a Node-based code execution service.
- Local development is container-first: `make dev` brings up the backend services and the frontend hot-reload server, instead of the older mixed script-based setup.
- The `code-exec` service defaults to port `4401`, while the legacy `UmpleCodeExecution` service defaults to `4400`, so both stacks can run on the same machine without a port collision.
- Backend, collab, LSP, and code-exec ports can all be remapped from the repo root `.env` when you need to run multiple local stacks side by side.
Expand All @@ -26,7 +26,7 @@ This project reproduces the legacy PHP/jQuery stack with a contemporary architec
│ CodeMirror · ReactFlow │
│ Tailwind CSS · Zustand │
└────────────┬────────────────┘
│ /api/*
│ /api/* · /ws/collab/* · /ws/lsp
┌────────────▼────────────────┐
│ Backend (Go/Chi) │ Port 3001
│ ├─ TCP ──▶ umplesync.jar │
Expand All @@ -37,13 +37,23 @@ This project reproduces the legacy PHP/jQuery stack with a contemporary architec
│ Code Exec (Node.js) │ Port 4401
│ Sandboxed code runner │
└─────────────────────────────┘

┌─────────────────────────────┐
│ Collab (Yjs WebSocket) │ Port 3002
└─────────────────────────────┘

┌─────────────────────────────┐
│ LSP Proxy (WS to stdio) │ Port 9999
└─────────────────────────────┘
```

Three services, all containerized with Docker:
Five services, all containerized with Docker:

- **Frontend** — React 19, TypeScript, Vite, CodeMirror 6, ReactFlow
- **Backend** — Go 1.24 (Chi router), communicates with `umplesync.jar` via TCP and Graphviz for diagram rendering
- **Code Exec** — Node.js service for running compiled code in a sandbox
- **Frontend** - React 19, TypeScript, Vite, CodeMirror 6, ReactFlow. See [frontend/README.md](frontend/README.md).
- **Backend** - Go 1.24 (Chi router), communicates with `umplesync.jar` via TCP and Graphviz for diagram rendering. See [backend/README.md](backend/README.md).
- **Collab** - Yjs WebSocket server for realtime shared editing. See [collab/README.md](collab/README.md).
- **LSP Proxy** - WebSocket-to-stdio bridge for `umple-lsp-server`. See [lsp-proxy/README.md](lsp-proxy/README.md).
- **Code Exec** - Node.js service for running compiled code in a sandbox. See [code-exec/README.md](code-exec/README.md).

## Getting Started

Expand Down
133 changes: 133 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Backend API

The backend is the Go API layer for UmpleOnline. It owns model persistence,
compiler orchestration, diagram/export generation, examples, tasks, status
reporting, AI provider proxying, and the bridge to the code execution service.

## Runtime Shape

```
Browser / frontend nginx
|
| /api/*
v
Go backend (Chi)
|
| TCP
v
umplesync.jar server

Go backend
|
| HTTP
v
code-exec service

Go backend
|
| filesystem
v
/data/models, /examples, /jars
```

The backend listens on `PORT`, defaulting to `3001`. In development Vite
proxies `/api/*` to it. In production the frontend nginx container proxies
`/api/*` to the backend container.

## Internal Architecture

- `cmd/server/main.go` loads configuration, initializes stores, starts the
compiler pool, wires the router, and handles graceful shutdown.
- `internal/config` maps environment variables to runtime config.
- `internal/api/router.go` registers all HTTP routes under `/api`.
- `internal/api/handlers` contains request handlers for generation, diagrams,
exports, execution, examples, models, CRUD helpers, tasks, health, and status.
- `internal/compiler` starts and supervises `umplesync.jar` as a long-running
TCP server, sends compiler commands, and serializes writes per model.
- `internal/model` stores model directories, tab metadata, `.ump` tab files,
generated assets, and temporary-model cleanup.
- `internal/task` stores task definitions and responses on disk.
- `internal/execution` proxies run requests to `code-exec`.

The backend uses filesystem storage by design. Model IDs map to directories
under `MODEL_STORE_PATH`, and multi-tab models are represented as `tabs.json`
plus one `.ump` file per tab.

## Main API Families

- `GET /api/health` and `GET /api/status` - service and dependency health.
- `POST /api/generate` - compile and generate a target output.
- `POST /api/sync` - apply text/diagram synchronization operations.
- `POST /api/diagram` and `POST /api/export` - diagram rendering and export.
- `POST /api/execute` - compile and run generated Java/Python through
`code-exec`.
- `GET /api/models/{id}` and `POST /api/models/{id}/promote` - model loading
and temporary-to-durable promotion.
- `GET /api/examples`, `GET /api/examples/{id}`, and
`GET /api/examples/resolve` - bundled example catalog.
- `POST /api/crud/schema` and `POST /api/crud/diagram` - CRUD model helpers.
- `POST /api/tasks` and related task response routes - task workflows.
- `/api/ai/*` - provider proxying for browser-origin AI calls.

## Compiler Lifecycle

`internal/compiler.Pool` starts:

```text
java -cp $UMPLE_SYNC_JAR cruise.umple.PlaygroundMain -server $UMPLE_PORT
```

Requests connect to that server over TCP and send the command format expected
by `umplesync.jar`. If the JVM exits or a TCP dial fails, the pool attempts a
restart. Per-model mutexes prevent concurrent writes to the same model
directory while compile/sync flows are active.

## How This Differs From The Original

Legacy UmpleOnline handled most backend work in PHP. The closest original
entry points are:

- `~/umple/umpleonline/umple.php` - rendered the page, interpreted URL
parameters, loaded examples/models, and emitted runtime configuration.
- `~/umple/umpleonline/scripts/compiler.php` - handled AJAX actions for saving,
loading, compiling, image/export generation, and task operations.
- `~/umple/umpleonline/scripts/compiler_config.php` - contained the DataStore
abstraction and low-level socket calls to the compiler.

This backend keeps the compiler contract but changes the architecture:

- HTTP behavior is split into typed Go handlers instead of one large
request-switching PHP script.
- Model storage is explicit Go code under `internal/model`, not PHP helper
functions embedded in compiler configuration.
- Compiler process supervision lives in `internal/compiler.Pool`, with restart
and per-model locking in one place.
- Examples are served from the checked-in `examples/` snapshot instead of being
assembled from legacy page/menu generation at runtime.
- Code execution is delegated to the separate `code-exec` service instead of
being handled inside the same PHP endpoint family.
- Status and health are first-class JSON APIs rather than operational details
hidden behind legacy script pages.

## Development

From the repo root:

```bash
make dev-backend
make logs-backend
make tidy
```

Focused Go checks should run from this folder:

```bash
go test ./...
go vet ./...
```

When adding Go dependencies in the Docker dev stack, run:

```bash
docker compose exec backend go mod tidy
```
108 changes: 108 additions & 0 deletions collab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Collaboration Service

This service owns realtime multi-user editing for UmpleOnline. It is a small
Node/TypeScript WebSocket server that speaks the Yjs sync and awareness
protocols used by the React frontend.

## Runtime Shape

```
Browser editor
|
| y-websocket over /ws/collab/{roomId}
v
collab service
|
| in-memory Y.Doc per room
v
connected browser peers
```

The frontend connects through the same origin as the app:

- Dev: Vite proxies `/ws/collab/*` to `localhost:${COLLAB_PORT:-3002}`.
- Prod: nginx in the frontend container proxies `/ws/collab/*` to the
`collab` container.

The service exposes:

- `GET /health` - plain `ok` health check for Docker Compose.
- `GET /status` - JSON runtime stats for active rooms, connections, awareness
states, process ID, uptime, and connection counters.
- `WS /ws/collab/{roomId}` - Yjs sync and awareness transport.

## Internal Architecture

- `src/server.ts` creates the HTTP server, WebSocket server, health endpoint,
status endpoint, and room routing.
- `src/sync.ts` contains the Yjs document registry and WebSocket protocol
handling.
- Each room ID maps to one in-memory `WSSharedDoc`.
- Each `WSSharedDoc` tracks connected sockets plus Yjs awareness client IDs.
- Document updates are rebroadcast with `y-protocols/sync`.
- Presence updates are rebroadcast with `y-protocols/awareness`.
- When the last socket leaves a room, the Yjs document is destroyed and removed
from memory.

The service does not persist collaboration state. The room is a live shared
editing session. Durable model state is still managed by the backend model
store when the frontend compiles, syncs, promotes, or loads a model.

## Frontend Contract

The React frontend owns the user-facing collaboration lifecycle:

- `frontend/src/hooks/useCollab.ts` creates the `Y.Doc`, connects the
`WebsocketProvider`, sets awareness identity, and hydrates or seeds shared
tabs.
- `frontend/src/hooks/useCollabTabs.ts` maps shared Yjs tab state into the
local Zustand session store.
- `frontend/src/components/editor/UmpleEditor.tsx` binds CodeMirror to the
active shared `Y.Text`.

Shared Yjs data uses these names:

- `Y.Map("tabs")` stores tab metadata by tab ID.
- `Y.Text("tab:<id>")` stores each tab's source text.

## How This Differs From The Original

Legacy UmpleOnline handled collaboration inside the PHP/jQuery page flow. The
old UI in `~/umple/umpleonline/umple.php` rendered collaboration controls,
loaded `scripts/socket.io/socket.io.js`, and called browser globals from
`scripts/umpleCollab.js`. Its server endpoint was configured through
`scripts/collab-server-config.js.template` with a Socket.IO path such as
`/collabapi`.

This rewrite separates collaboration into a dedicated service:

- The collaboration transport is Yjs binary sync over WebSocket, not the legacy
Socket.IO collaboration client.
- Room state is isolated in `collab/src/sync.ts` instead of being mixed into
`Page`, `Action`, and global browser objects.
- The frontend stores collaborative tabs in structured Yjs maps/text objects
instead of patching a single page-level text model.
- The service has its own health and status endpoints, so orchestration and
monitoring do not depend on PHP page rendering.

## Development

From this folder:

```bash
bun install
bun run dev
bun run build
```

Normally this service is started by Docker Compose:

```bash
make dev-backend
```

or as part of the full stack:

```bash
make dev
```
Loading
Loading