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
12 changes: 12 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## What does this PR do?
> Briefly describe the changes. (e.g., "Added a user authentication form" or "Refactored the API fetching logic.")
-
-

Comment on lines +1 to +5

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template currently includes empty list items (- with no content). These render as blank bullets and can be confusing to fill out (and may be flagged by Markdown linters if added later). Consider replacing them with clearer placeholders (e.g., HTML comments, or checkbox items like - [ ] ...) so authors know what to write without leaving empty bullets.

Copilot uses AI. Check for mistakes.
## Why is this necessary?
> Explain the *problem* you are solving. If you look back at this in 6 months, will you know why you wrote this code?
-

## 🧠 What did I learn? (The most important part!)
> Did you figure out a new CSS trick? Finally understand Promises? Make a note of it here.
-
2 changes: 1 addition & 1 deletion docs/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This folder is the backend living documentation for LeetDoodle.

## Service Inventory

- `canvas-service` (port `8084` HTTP debug surface, `9091` gRPC): durable canvas structure owner; persists nodes, edges, and versioned structural ops.
- `canvas-service` (port `9091` gRPC): durable canvas structure owner; persists nodes, edges, and versioned structural ops.
- `collab` (port `8080`): WebSocket relay for real-time canvas collaboration.
- `leetcode-service` (port `8081` HTTP, `9090` gRPC): problem catalog APIs + internal eval-data gRPC provider.
- `submissions` (port `8082`): submission intake and retrieval; writes transactional outbox.
Expand Down
3 changes: 0 additions & 3 deletions docs/backend/architecture/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ This page zooms into each Spring service and maps internal components to their r

```mermaid
flowchart LR
CC[CanvasController]
CG[CanvasGrpcService]
CS[CanvasService @Transactional]
CAR[CanvasRepository]
Expand All @@ -15,7 +14,6 @@ flowchart LR
COR[CanvasOperationRepository]
PG[(PostgreSQL canvas schema)]

CC --> CS
CG --> CS
CS --> CAR
CS --> CNR
Expand All @@ -27,7 +25,6 @@ flowchart LR
COR --> PG
```

- `CanvasController` exposes a small HTTP debug surface for manual inspection.
- `CanvasGrpcService` is the internal service-to-service contract used by collab.
- `CanvasService.applyStructuralOperation()` reserves a new version, appends to `canvas_ops`, applies the materialized write, and commits in one transaction.
- `CanvasRepository` owns canvas-level metadata such as `head_version`.
Expand Down
4 changes: 2 additions & 2 deletions docs/backend/architecture/containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ flowchart TB
FE[Frontend\nReact/Vite]

subgraph APP[Spring Boot Services]
CAN[canvas-service\n:8084 (HTTP), :9091 (gRPC)]
CAN[canvas-service\n:9091 (gRPC)]
COL[collab\n:8080]
LEE[leetcode-service\n:8081 (HTTP), :9090 (gRPC)]
SUB[submissions\n:8082]
Expand Down Expand Up @@ -40,7 +40,7 @@ flowchart TB

## Container Responsibilities

- **canvas-service**: Durable structural canvas owner. Stores materialized node/edge state plus ordered committed structural ops. Exposes gRPC for internal hot-path calls and a small HTTP debug surface.
- **canvas-service**: Durable structural canvas owner. Stores materialized node/edge state plus ordered committed structural ops. Exposes gRPC for internal hot-path calls.
- **collab**: Room/session registry, fan-out relay, in-memory CRDT op-log for replay, and gRPC client to canvas-service for persist-first structural websocket flows.
- **leetcode-service**: Paginated/filterable problem APIs plus internal gRPC eval-data endpoint.
- **submissions**: Accepts code submissions, persists row, persists outbox event in same transaction, and polls/publishes unpublished rows to RabbitMQ.
Expand Down
65 changes: 0 additions & 65 deletions docs/backend/contracts/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,9 @@ This document captures the backend HTTP contracts currently implemented by Sprin

## Base URLs (local dev)

- `http://localhost:8084` -> `canvas-service`
- `http://localhost:8081` -> `leetcode-service`
- `http://localhost:8082` -> `submissions`

## Canvas API (`/api/canvases`)

These endpoints remain available as a debug/admin surface.
Internal `collab -> canvas-service` traffic now uses gRPC instead of HTTP.

### `GET /api/canvases/{canvasId}`

Returns the current durable materialized state for one canvas:

```json
{
"canvasId": "canvas-1",
"headVersion": 12,
"nodes": [],
"edges": []
}
```

Notes:

- New canvases return an empty snapshot with `headVersion = 0`.
- This is the durable bootstrap source of truth for structural canvas state.

### `GET /api/canvases/{canvasId}/ops?afterVersion={n}&limit={m}`

Returns committed structural ops newer than the caller's known version.

Notes:

- `afterVersion` is required and must be `>= 0`.
- `limit` is optional and defaults to `200`.
- Current ops are durable structural changes only, not cursor/presence traffic.

### `POST /api/canvases/{canvasId}/ops`

Commits one structural operation transactionally.

Request body shape:

```json
{
"clientOperationId": "op-123",
"actorUserId": "user-123",
"operationType": "NODE_MOVE",
"payload": {
"nodeId": "node-1",
"x": 420,
"y": 180
}
}
```

Notes:

- `clientOperationId` is required for idempotent retries.
- Supported durable operation types are:
- `NODE_CREATE`
- `NODE_MOVE`
- `NODE_UPDATE`
- `NODE_DELETE`
- `EDGE_CREATE`
- `EDGE_DELETE`
- The service reserves the next canvas version, appends the op log row, applies the materialized table mutation, and commits all of that in one DB transaction.

## Problems API (`/api/problems`)

### `GET /api/problems`
Expand Down
2 changes: 0 additions & 2 deletions docs/backend/operations/local-runtime-and-runbooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Service ports:
- leetcode-service gRPC: `9090`
- submissions: `8082`
- worker: `8083`
- canvas-service HTTP: `8084`
- canvas-service gRPC: `9091`

Helper scripts:
Expand Down Expand Up @@ -62,7 +61,6 @@ Helper scripts:

## Known Current Constraints

- Collab has not been rerouted to canvas-service yet, so live structural websocket traffic can still diverge from the new durable canvas write path until the next integration pass.
- Collab op log is in-memory; process restarts lose replay history.
- No DLQ configured for eval pipeline.
- No unified backend error envelope standard yet.
4 changes: 2 additions & 2 deletions services/canvas/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
Comment on lines 23 to 26

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

services/canvas is now gRPC-only, but the module still depends on spring-web primarily for HttpStatus/ResponseStatusException usage. If the goal is to trim all HTTP-centric dependencies from canvas-service, consider introducing transport-agnostic/domain exceptions and mapping them to gRPC Status in the adapter, which would let you drop spring-web entirely.

Copilot uses AI. Check for mistakes.

<dependency>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
/**
* gRPC server adapter for durable canvas state.
*
* <p>The HTTP controller can remain available as a debug surface, but internal
* service-to-service traffic should use this gRPC contract so collab and canvas
* share one compile-time-checked interface.
* <p>This is the only service-to-service transport for durable canvas state.
* Keeping the boundary on gRPC avoids a second parallel contract drifting away
* from the real persistence and sequencing path.
Comment on lines +23 to +25

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service is positioned as a gRPC-only boundary, but errors are still represented via ResponseStatusException/HttpStatus and then mapped to gRPC Status. If you want to keep the gRPC boundary free of HTTP semantics, consider switching to domain exceptions (or gRPC-native exceptions) and mapping those to Status instead of relying on ResponseStatusException.

Copilot uses AI. Check for mistakes.
*/
@GrpcService
public class CanvasGrpcService extends CanvasServiceGrpc.CanvasServiceImplBase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@
* Application service for durable structural canvas operations.
*
* <p>This service owns the "persisted truth" for nodes, edges, and structural
* sequencing. A future collab integration can call into this service for
* durable operations while continuing to relay ephemeral events like cursors in
* memory.
* sequencing. Collab already calls into this service for durable operations
* while continuing to relay ephemeral events like cursors in memory.
*/
@Service
public class CanvasService {
Expand Down
1 change: 0 additions & 1 deletion services/canvas/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
spring.application.name=canvas-service
server.port=8084

spring.datasource.url=jdbc:postgresql://localhost:5432/leetdoodle
spring.datasource.username=leetdoodle
Expand Down
Loading