Skip to content

Commit 2412e7a

Browse files
committed
Added realtime-sync.md and auth.md docs
1 parent b46478f commit 2412e7a

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

docs/auth.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Authentication & Security
2+
3+
This document outlines how CodenCollab secures user data and prevents unauthorized access. We rely on **Supabase** for identity management and standard **JWT (JSON Web Token)** verification for access control.
4+
5+
## The Authentication Flow
6+
7+
We treat the Frontend and Backend as two separate entities that do not trust each other. The **JWT** is the only proof of identity accepted by the backend.
8+
9+
### 1. Client-Side Login (Frontend)
10+
* The user logs in via the React frontend using the Supabase Client SDK.
11+
* Supabase returns a session object containing an `access_token` (JWT) and a `refresh_token`.
12+
* This token is stored securely in the browser (handled automatically by the Supabase client).
13+
14+
### 2. Protecting API Routes (REST)
15+
When a user attempts to run code or fetch sensitive data, the frontend attaches the token to the HTTP Headers:
16+
17+
```http
18+
POST /rooms/123/run HTTP/1.1
19+
Authorization: Bearer <SUPABASE_ACCESS_TOKEN>
20+
21+
```
22+
23+
* **Backend Check:** The FastAPI backend extracts this token and verifies its signature against our **Supabase JWT Secret**.
24+
* **Expiration:** If the token is expired, the request is immediately rejected with a `401 Unauthorized` error.
25+
26+
### 3. Protecting the WebSocket (Real-Time)
27+
28+
Securing WebSockets is trickier because they are persistent connections.
29+
30+
* **Handshake:** During the initial Socket.IO handshake, the client should pass the token in the `auth` object.
31+
* **Connection Guard:** The backend validates this token *before* allowing the socket to connect. If the token is invalid, the socket is disconnected immediately, preventing the user from receiving any real-time updates.
32+
33+
---
34+
35+
## Server-Side Access Control
36+
37+
Authentication identifies *who* the user is. Authorization determines *what* they can do.
38+
39+
### Room-Level Security
40+
41+
Just because a user is logged in doesn't mean they can enter any room.
42+
43+
* **Join Event:** When a socket emits `join { room_id }`, the backend checks if that room is public or private. If private, it verifies if the user's ID is on the allowlist for that room.
44+
45+
### Execution Security
46+
47+
Running code is the most dangerous action in the app.
48+
49+
* **Validation:** The `/run` endpoint is strictly protected. We verify the JWT on every single execution request.
50+
* **Sanitization:** Input is stripped of obvious malicious shell characters before being sent to the sandbox.
51+
* **Isolation:** Execution happens in **Piston**, a completely separate environment. Even if a user bypasses backend checks, they are trapped in a Docker container with no network access to our database.
52+
53+
---
54+
55+
## Security Best Practices
56+
57+
### 1. Secret Management
58+
59+
* **Service Role Keys:** We strictly keep the `SUPABASE_SERVICE_ROLE_KEY` on the backend. This key has admin rights and is **never** exposed to the frontend/browser.
60+
* **Environment Variables:** All secrets are loaded via `.env` files and are never committed to Git.
61+
62+
### 2. Network Security
63+
64+
* **HTTPS/WSS:** In production, all traffic (REST and WebSockets) must be encrypted via TLS.
65+
* **CORS (Cross-Origin Resource Sharing):** We explicitly whitelist only our frontend domain (e.g., `https://codencollab-app.vercel.app`) to prevent malicious websites from triggering actions on behalf of a user.
66+
67+
### 3. Token Lifecycle
68+
69+
* Supabase tokens are short-lived (usually 1 hour).
70+
* The frontend handles token refreshing automatically. If a session expires during a coding session, the client will silently refresh the token and reconnect the socket seamlessly.

docs/realtime-sync.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Real-Time Synchronization Strategy
2+
3+
This document explains the practical implementation details of CodenCollab's synchronization engine. It covers how we keep clients in sync, handle network "chattiness," and prevent infinite update loops.
4+
5+
## Core Architecture: Room Scoping
6+
We utilize **Socket.IO Rooms** to isolate collaboration sessions.
7+
- **Strict Isolation:** All events (`code-update`, `cursor`, `execution-result`) are emitted to a specific `room_id`.
8+
- **Privacy:** This ensures that actions in "Room A" are never broadcast to "Room B," maintaining data privacy and reducing unnecessary server load.
9+
10+
## The "Echo" Problem (Feedback Loops)
11+
The hardest part of real-time syncing is preventing an infinite loop where:
12+
1. User A types a character.
13+
2. Server sends it to User B.
14+
3. User B's editor applies the change programmatically.
15+
4. User B's editor detects a "change" and sends it *back* to User A.
16+
5. Repeat forever until the browser crashes.
17+
18+
### Our Solution: The `isApplyingRemoteChange` Flag
19+
We use a React `useRef` boolean to distinguish between *human* edits and *socket* edits.
20+
21+
1. **Incoming Event:** When a `code-update` event arrives, we set `isApplyingRemoteChange.current = true`.
22+
2. **Apply Edit:** We apply the delta to the Monaco Model.
23+
3. **Reset:** Immediately after application, we set the flag back to `false`.
24+
4. **Event Listener:** Our local `onDidChangeModelContent` listener checks this flag first. If it is `true`, it knows the change came from the server, so it **ignores it** and does not emit a socket event.
25+
26+
## Cursor Optimization (Debouncing)
27+
Cursor movements are extremely high-frequency events. Sending a packet for every pixel a mouse moves would flood the network and degrade performance.
28+
29+
### Strategy
30+
- **Debouncing:** We implement a **100ms throttle** on the client side.
31+
- **Logic:** If a user moves their cursor, we wait 100ms. If they move again within that window, we reset the timer. We only emit the final position once the user stops moving or the interval passes.
32+
- **Result:** This reduces network traffic by approximately 90% while still looking "live" to other users.
33+
34+
## Handling Decorations (Visuals)
35+
To render remote cursors, we do not insert text into the document. Instead, we use Monaco's **Decorations API**.
36+
37+
- **Implementation:** We maintain a `decorationsCollectionRef`.
38+
- **Update Cycle:** When a `cursor` event arrives, we calculate the new positions and overwrite the collection using `set()`.
39+
- **Memory Management:** Monaco handles the cleanup of old decorations automatically when we overwrite them, preventing memory leaks in long sessions.
40+
41+
## Conflict Resolution & Limitations
42+
Currently, CodenCollab uses a **Server-Relay** (Last Write Wins) approach.
43+
- **Pros:** Extremely low latency and simple codebase. Perfect for pair programming (2-3 people).
44+
- **Cons:** Not mathematically conflict-free. If two users type on the exact same line at the exact same millisecond, consistency is not guaranteed.
45+
46+
### Future Migration Path
47+
If the project scales to support large classrooms or offline-first editing, we plan to migrate the state management to a **CRDT** (Conflict-free Replicated Data Type) library like **Yjs**. This would allow for decentralized, mathematical conflict resolution at the cost of higher complexity.

0 commit comments

Comments
 (0)