Collaborative algorithm practice workspace with a node-based canvas, real-time presence, and asynchronous code evaluation.
LeetDoodle combines three things that are usually separate:
- A visual canvas for problem-solving workflows.
- Multiplayer collaboration (presence, cursor, shared node state).
- Production-style evaluation pipeline (transactional outbox, scheduled dispatcher, queue consumer, sandboxed execution).
The goal is to practice algorithm solving and systems design in one place.
- Real-time collaboration over WebSockets (
collabservice). - Problem catalog with REST + internal gRPC eval-data API (
leetcode-service). - Async submissions with transactional outbox (
submissionsservice). - Queue-driven worker execution inside Docker sandboxes (
workerservice). - In-process outbox dispatcher from Postgres to RabbitMQ.
flowchart LR
FE[Frontend React/Vite]
COL[collab :8080]
LEE[leetcode-service :8081 / gRPC :9090]
SUB[submissions :8082]
WRK[worker :8083]
PG[(Postgres)]
RMQ[(RabbitMQ)]
DCK[(Docker Engine)]
FE <-->|WS /ws| COL
FE <-->|HTTP /api/problems| LEE
FE <-->|HTTP /api/submissions| SUB
LEE --> PG
SUB --> PG
SUB -->|outbox row| PG
SUB -->|poll + publish| RMQ
WRK --> RMQ
WRK -->|gRPC GetProblemEval| LEE
WRK --> PG
WRK --> DCK
More architecture detail lives in docs/backend.
frontend/ React + Vite client
services/
collab/ WebSocket relay
leetcode/ Problem APIs + gRPC eval metadata service
submissions/ Submission API + outbox writer/dispatcher
worker/ Rabbit consumer + Docker eval runner
grpc-api/ Shared protobuf/gRPC stubs
infra/
compose/ Docker Compose stack (Postgres, RabbitMQ)
scripts/ Dev lifecycle scripts
docs/backend/ Architecture, contracts, ADRs, runbooks
- Frontend: React 19, TypeScript, Vite, CodeMirror
- Backend: Java 21+, Spring Boot 3.4, Maven, gRPC
- Data: PostgreSQL 16
- Messaging: RabbitMQ, transactional outbox with Spring scheduler
- Execution Isolation: Docker containers
- Docker + Docker Compose
- Java 21+ (project compiles with
maven.compiler.release=21) - Maven 3.9+
- Node.js 20+ and pnpm
./scripts/backend-restart.shThis script:
- installs
services/grpc-apito local Maven cache, - starts Docker infra (
postgres,rabbitmq), - waits for core infra readiness before booting Spring apps,
- runs clean Maven startup for each backend service by default (prevents stale
target/classesissues), - starts Spring services (
collab,leetcode,submissions,worker), - writes logs to
.logs/and PIDs to.run/.
If you need a faster startup and are okay skipping clean rebuilds:
./scripts/backend-restart.sh --no-cleancd frontend
pnpm install
pnpm devFrontend runs on Vite default (http://localhost:5173).
http://localhost:5173
| Component | Port | Purpose |
|---|---|---|
| frontend (Vite) | 5173 |
UI |
| collab | 8080 |
WebSocket relay (/ws) |
| leetcode-service (HTTP) | 8081 |
Problems REST API |
| leetcode-service (gRPC) | 9090 |
Worker eval metadata API |
| submissions | 8082 |
Submission create/poll API |
| worker | 8083 |
Worker process (internal APIs) |
| postgres | 5432 |
Primary DB |
| rabbitmq | 5672 |
AMQP |
| rabbitmq mgmt | 15672 |
Rabbit UI |
mvn -f services/pom.xml -DskipTests compilepnpm -C frontend buildpnpm -C frontend lint:allThis enforces:
- ESLint with zero warnings (
--max-warnings=0) - canonical Tailwind token color class syntax (for example
text-(--token))
./scripts/setup-git-hooks.shAfter setup, every commit runs scripts/pre-commit.sh (currently strict frontend lint checks).
./scripts/backend-down.shTo keep infra running while stopping Spring services:
./scripts/backend-down.sh --keep-infra./scripts/backend-restart.shUseful flags:
--keep-infra(restart Spring services only, leave Docker infra up)--no-clean(skip clean rebuild path)
./scripts/db-reset.sh- REST: docs/backend/contracts/rest-api.md
- gRPC eval API: docs/backend/contracts/grpc-problem-eval.md
- WebSocket events: docs/backend/contracts/websocket-events.md
- Messaging path: docs/backend/contracts/eval-messaging.md
- ADR-0001: Transactional Outbox + Scheduled Dispatcher + RabbitMQ
- ADR-0002: Worker Direct DB Access
- ADR-0003: Stateful In-Memory Collab Relay
- ADR-0004: Worker Reads Eval Data via gRPC
workerrequires a running Docker daemon to execute submissions.submissionsowns the outbox dispatcher and publishes to RabbitMQ exchangeeval.- Submission status is asynchronous by design: client posts, then polls by
submissionId.
When opening a PR:
- Keep docs in sync with behavior changes (
docs/backendis docs-as-code). - Update contracts and ADRs when architecture/semantics change.
- Keep backend Javadocs consistent with the team standard: docs/backend/standards/javadoc-and-teaching-style.md
Active development. Interfaces and schemas may evolve quickly while core architecture stabilizes.