diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..6234866 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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.") +- +- + +## 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. +- \ No newline at end of file diff --git a/docs/backend/README.md b/docs/backend/README.md index c0a1ad2..b4ad20a 100644 --- a/docs/backend/README.md +++ b/docs/backend/README.md @@ -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. diff --git a/docs/backend/architecture/components.md b/docs/backend/architecture/components.md index fb0ca6f..322abd7 100644 --- a/docs/backend/architecture/components.md +++ b/docs/backend/architecture/components.md @@ -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] @@ -15,7 +14,6 @@ flowchart LR COR[CanvasOperationRepository] PG[(PostgreSQL canvas schema)] - CC --> CS CG --> CS CS --> CAR CS --> CNR @@ -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`. diff --git a/docs/backend/architecture/containers.md b/docs/backend/architecture/containers.md index b795707..443808f 100644 --- a/docs/backend/architecture/containers.md +++ b/docs/backend/architecture/containers.md @@ -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] @@ -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. diff --git a/docs/backend/contracts/rest-api.md b/docs/backend/contracts/rest-api.md index 988e95a..f76ad6b 100644 --- a/docs/backend/contracts/rest-api.md +++ b/docs/backend/contracts/rest-api.md @@ -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` diff --git a/docs/backend/operations/local-runtime-and-runbooks.md b/docs/backend/operations/local-runtime-and-runbooks.md index c10a6cd..8f9d006 100644 --- a/docs/backend/operations/local-runtime-and-runbooks.md +++ b/docs/backend/operations/local-runtime-and-runbooks.md @@ -14,7 +14,6 @@ Service ports: - leetcode-service gRPC: `9090` - submissions: `8082` - worker: `8083` -- canvas-service HTTP: `8084` - canvas-service gRPC: `9091` Helper scripts: @@ -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. diff --git a/services/canvas/pom.xml b/services/canvas/pom.xml index 1df7909..507d7b3 100644 --- a/services/canvas/pom.xml +++ b/services/canvas/pom.xml @@ -21,8 +21,8 @@ - org.springframework.boot - spring-boot-starter-web + org.springframework + spring-web diff --git a/services/canvas/src/main/java/com/leetdoodle/canvas/controller/CanvasController.java b/services/canvas/src/main/java/com/leetdoodle/canvas/controller/CanvasController.java deleted file mode 100644 index 114fd27..0000000 --- a/services/canvas/src/main/java/com/leetdoodle/canvas/controller/CanvasController.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.leetdoodle.canvas.controller; - -import com.leetdoodle.canvas.model.CanvasSnapshot; -import com.leetdoodle.canvas.model.CommittedCanvasOperation; -import com.leetdoodle.canvas.model.StructuralOperationRequest; -import com.leetdoodle.canvas.service.CanvasService; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -/** - * HTTP debug surface for durable canvas state and structural sequencing. - * - *

The internal hot path now uses gRPC from collab -> canvas-service. These - * endpoints remain useful for manual inspection and debugging because they are - * easy to exercise with curl/Postman during local development. - */ -@RestController -@RequestMapping("/api/canvases") -@CrossOrigin(origins = "*") -public class CanvasController { - - private final CanvasService canvasService; - - public CanvasController(CanvasService canvasService) { - this.canvasService = canvasService; - } - - /** - * Return the current durable canvas state. - */ - @GetMapping("/{canvasId}") - public CanvasSnapshot getSnapshot(@PathVariable String canvasId) { - return canvasService.getSnapshot(canvasId); - } - - /** - * Return committed structural ops newer than the caller's last known version. - */ - @GetMapping("/{canvasId}/ops") - public List getOperationsAfter(@PathVariable String canvasId, - @RequestParam long afterVersion, - @RequestParam(required = false) Integer limit) { - return canvasService.getOperationsAfter(canvasId, afterVersion, limit); - } - - /** - * Commit one durable structural operation. - */ - @PostMapping("/{canvasId}/ops") - public CommittedCanvasOperation applyStructuralOperation(@PathVariable String canvasId, - @RequestBody StructuralOperationRequest request) { - return canvasService.applyStructuralOperation(canvasId, request); - } -} diff --git a/services/canvas/src/main/java/com/leetdoodle/canvas/grpc/CanvasGrpcService.java b/services/canvas/src/main/java/com/leetdoodle/canvas/grpc/CanvasGrpcService.java index 9a934f2..5908691 100644 --- a/services/canvas/src/main/java/com/leetdoodle/canvas/grpc/CanvasGrpcService.java +++ b/services/canvas/src/main/java/com/leetdoodle/canvas/grpc/CanvasGrpcService.java @@ -20,9 +20,9 @@ /** * gRPC server adapter for durable canvas state. * - *

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. + *

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. */ @GrpcService public class CanvasGrpcService extends CanvasServiceGrpc.CanvasServiceImplBase { diff --git a/services/canvas/src/main/java/com/leetdoodle/canvas/service/CanvasService.java b/services/canvas/src/main/java/com/leetdoodle/canvas/service/CanvasService.java index 0723cef..7a7ce55 100644 --- a/services/canvas/src/main/java/com/leetdoodle/canvas/service/CanvasService.java +++ b/services/canvas/src/main/java/com/leetdoodle/canvas/service/CanvasService.java @@ -33,9 +33,8 @@ * Application service for durable structural canvas operations. * *

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 { diff --git a/services/canvas/src/main/resources/application.properties b/services/canvas/src/main/resources/application.properties index f3040d2..84a5e54 100644 --- a/services/canvas/src/main/resources/application.properties +++ b/services/canvas/src/main/resources/application.properties @@ -1,5 +1,4 @@ spring.application.name=canvas-service -server.port=8084 spring.datasource.url=jdbc:postgresql://localhost:5432/leetdoodle spring.datasource.username=leetdoodle